From: Dave Martin <Dave.Martin@arm.com>
To: kvmarm@lists.cs.columbia.edu
Cc: "Peter Maydell" <peter.maydell@linaro.org>,
"Okamoto Takayuki" <tokamoto@jp.fujitsu.com>,
"Christoffer Dall" <cdall@kernel.org>,
"Ard Biesheuvel" <ard.biesheuvel@linaro.org>,
"Marc Zyngier" <marc.zyngier@arm.com>,
"Catalin Marinas" <catalin.marinas@arm.com>,
"Will Deacon" <will.deacon@arm.com>,
"Zhang Lei" <zhang.lei@jp.fujitsu.com>,
"Julien Grall" <julien.grall@arm.com>,
"Alex Bennée" <alex.bennee@linaro.org>,
linux-arm-kernel@lists.infradead.org
Subject: [PATCH v5 22/26] KVM: arm64/sve: Add pseudo-register for the guest's vector lengths
Date: Mon, 18 Feb 2019 19:52:35 +0000 [thread overview]
Message-ID: <1550519559-15915-23-git-send-email-Dave.Martin@arm.com> (raw)
In-Reply-To: <1550519559-15915-1-git-send-email-Dave.Martin@arm.com>
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, along with corresponding storage in struct
kvm_vcpu_arch.
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 to track vcpu finalization explicitly, and enforce proper
sequencing of ioctls.
The new 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>
---
Changes since v4:
* Add a UAPI header comment indicating the pseudo-register status of
KVM_REG_ARM64_SVE_VLS.
* Get rid of the sve_vqs[] array from struct kvm_vcpu_arch. This
array is pointless, because its contents must match the host's
internal sve_vq_map anyway, up to vcpu->arch.sve_max_vl.
The ioctl register accessors are slow-path code, so we can decode
or reconstruct sve_vqs[] on demand instead, for exchange with
userspace.
* For compatibility with potential future architecture extensions,
enabling vector lengths above 256 bytes for the guest is explicitly
disallowed now (because the code for exposing additional bits
through ioctl is currently missing). This can be addressed later
if/when needed.
Note:
* I defensively pass an array by pointer here, to help avoid
accidentally breaking assumptions during future maintenance.
Due to (over?)zealous constification, this causes the following
sparse warning. I think this is sparse getting confused: I am not
relying on any kernel-specific semantics here, and GCC generates no
warning.
+arch/arm64/kvm/guest.c:33: warning: incorrect type in argument 1 (different modifiers)
+arch/arm64/kvm/guest.c:33: expected unsigned long long const [usertype] ( *const vqs )[8]
+arch/arm64/kvm/guest.c:33: got unsigned long long [usertype] ( * )[8]
---
arch/arm64/include/asm/kvm_host.h | 7 ++-
arch/arm64/include/uapi/asm/kvm.h | 4 ++
arch/arm64/kvm/guest.c | 124 ++++++++++++++++++++++++++++++++++++--
arch/arm64/kvm/reset.c | 9 +++
4 files changed, 136 insertions(+), 8 deletions(-)
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 015c2578..e53119a 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -24,6 +24,7 @@
#include <linux/bitmap.h>
#include <linux/types.h>
+#include <linux/kernel.h>
#include <linux/kvm_types.h>
#include <asm/cpufeature.h>
#include <asm/daifflags.h>
@@ -331,6 +332,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_FINALIZED (1 << 6) /* vcpu config completed */
#define vcpu_has_sve(vcpu) (system_supports_sve() && \
((vcpu)->arch.flags & KVM_ARM64_GUEST_HAS_SVE))
@@ -554,7 +556,8 @@ void kvm_arch_free_vm(struct kvm *kvm);
int kvm_arm_setup_stage2(struct kvm *kvm, unsigned long type);
/* Commit to the set of vcpu registers currently configured: */
-static inline int kvm_arm_vcpu_finalize(struct kvm_vcpu *vcpu) { return 0; }
-#define kvm_arm_vcpu_finalized(vcpu) true
+int kvm_arm_vcpu_finalize(struct kvm_vcpu *vcpu);
+#define kvm_arm_vcpu_finalized(vcpu) \
+ ((vcpu)->arch.flags & KVM_ARM64_VCPU_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..7ff1bd4 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -243,6 +243,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 4a2ad60..5f48c17 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -217,6 +217,81 @@ 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);
+
+ BUILD_BUG_ON(sizeof(vqs) != KVM_REG_SIZE(reg->id));
+ 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_finalized(vcpu))
+ return -EPERM; /* too late! */
+
+ if (WARN_ON(vcpu->arch.sve_state))
+ return -EINVAL;
+
+ BUILD_BUG_ON(sizeof(vqs) != KVM_REG_SIZE(reg->id));
+ 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;
+
+ /*
+ * 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_ONCE(sve_vl_from_vq(max_vq) > SVE_VL_ARCH_MAX,
+ "KVM: Requested vector length not supported yet\n"))
+ 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_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)
@@ -297,9 +372,21 @@ static int sve_reg_region(struct sve_state_region *region,
static int get_sve_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
{
struct sve_state_region region;
+ int ret;
char __user *uptr = (char __user *)reg->addr;
- if (!vcpu_has_sve(vcpu) || sve_reg_region(®ion, vcpu, reg))
+ if (!vcpu_has_sve(vcpu))
+ return -ENOENT;
+
+ if (reg->id == KVM_REG_ARM64_SVE_VLS)
+ return get_sve_vls(vcpu, reg);
+
+ /* Finalize the number of slices per SVE register: */
+ ret = kvm_arm_vcpu_finalize(vcpu);
+ if (ret)
+ return ret;
+
+ if (sve_reg_region(®ion, vcpu, reg))
return -ENOENT;
if (copy_to_user(uptr, vcpu->arch.sve_state + region.koffset,
@@ -313,9 +400,21 @@ static int get_sve_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
static int set_sve_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
{
struct sve_state_region region;
+ int ret;
const char __user *uptr = (const char __user *)reg->addr;
- if (!vcpu_has_sve(vcpu) || sve_reg_region(®ion, vcpu, reg))
+ if (!vcpu_has_sve(vcpu))
+ return -ENOENT;
+
+ if (reg->id == KVM_REG_ARM64_SVE_VLS)
+ return set_sve_vls(vcpu, reg);
+
+ /* Finalize the number of slices per SVE register: */
+ ret = kvm_arm_vcpu_finalize(vcpu);
+ if (ret)
+ return ret;
+
+ if (sve_reg_region(®ion, vcpu, reg))
return -ENOENT;
if (copy_from_user(vcpu->arch.sve_state + region.koffset, uptr,
@@ -452,30 +551,43 @@ 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 */);
+ 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, u64 __user **uind)
{
/* Only the first slice ever exists, for now */
const unsigned int slices = 1;
+ u64 reg;
unsigned int i, n;
if (!vcpu_has_sve(vcpu))
return 0;
+ /*
+ * 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, (*uind)++))
+ return -EFAULT;
+
for (i = 0; i < slices; i++) {
for (n = 0; n < SVE_NUM_ZREGS; n++) {
- if (put_user(KVM_REG_ARM64_SVE_ZREG(n, i), (*uind)++))
+ reg = KVM_REG_ARM64_SVE_ZREG(n, i);
+ if (put_user(reg, (*uind)++))
return -EFAULT;
}
for (n = 0; n < SVE_NUM_PREGS; n++) {
- if (put_user(KVM_REG_ARM64_SVE_PREG(n, i), (*uind)++))
+ reg = KVM_REG_ARM64_SVE_PREG(n, i);
+ if (put_user(reg, (*uind)++))
return -EFAULT;
}
- if (put_user(KVM_REG_ARM64_SVE_FFR(i), (*uind)++))
+ reg = KVM_REG_ARM64_SVE_FFR(i);
+ if (put_user(reg, (*uind)++))
return -EFAULT;
}
diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
index b72a3dd..1379fb2 100644
--- a/arch/arm64/kvm/reset.c
+++ b/arch/arm64/kvm/reset.c
@@ -98,6 +98,15 @@ int kvm_arch_vm_ioctl_check_extension(struct kvm *kvm, long ext)
return r;
}
+int kvm_arm_vcpu_finalize(struct kvm_vcpu *vcpu)
+{
+ if (likely(kvm_arm_vcpu_finalized(vcpu)))
+ return 0;
+
+ vcpu->arch.flags |= KVM_ARM64_VCPU_FINALIZED;
+ return 0;
+}
+
/**
* 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
next prev parent reply other threads:[~2019-02-18 19:57 UTC|newest]
Thread overview: 96+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-02-18 19:52 [PATCH v5 00/26] KVM: arm64: SVE guest support Dave Martin
2019-02-18 19:52 ` [PATCH v5 01/26] KVM: Documentation: Document arm64 core registers in detail Dave Martin
2019-02-21 11:48 ` Julien Grall
2019-02-26 12:05 ` Dave Martin
2019-02-21 11:57 ` Peter Maydell
2019-02-18 19:52 ` [PATCH v5 02/26] arm64: fpsimd: Always set TIF_FOREIGN_FPSTATE on task state flush Dave Martin
2019-02-21 12:39 ` Julien Grall
2019-02-26 12:06 ` Dave Martin
2019-02-26 12:35 ` Julien Grall
2019-02-18 19:52 ` [PATCH v5 03/26] KVM: arm64: Delete orphaned declaration for __fpsimd_enabled() Dave Martin
2019-02-18 19:52 ` [PATCH v5 04/26] KVM: arm64: Refactor kvm_arm_num_regs() for easier maintenance Dave Martin
2019-02-18 19:52 ` [PATCH v5 05/26] KVM: arm64: Add missing #include of <linux/bitmap.h> to kvm_host.h Dave Martin
2019-02-20 15:23 ` Mark Rutland
2019-02-26 12:06 ` Dave Martin
2019-02-26 12:31 ` Mark Rutland
2019-02-26 12:33 ` Dave Martin
2019-02-26 12:40 ` Mark Rutland
2019-02-18 19:52 ` [PATCH v5 06/26] arm64/sve: Check SVE virtualisability Dave Martin
2019-02-20 11:12 ` Julien Thierry
2019-02-26 12:06 ` Dave Martin
2019-03-01 12:39 ` Julien Thierry
2019-03-01 14:44 ` Dave Martin
2019-02-21 13:36 ` Julien Grall
2019-02-26 12:06 ` Dave Martin
2019-02-26 15:43 ` Julien Grall
2019-02-18 19:52 ` [PATCH v5 07/26] arm64/sve: Clarify role of the VQ map maintenance functions Dave Martin
2019-02-20 11:43 ` Julien Thierry
2019-02-26 12:06 ` Dave Martin
2019-02-21 13:46 ` Julien Grall
2019-02-26 12:07 ` Dave Martin
2019-02-18 19:52 ` [PATCH v5 08/26] arm64/sve: Enable SVE state tracking for non-task contexts Dave Martin
2019-02-22 15:26 ` Julien Grall
2019-02-26 12:07 ` Dave Martin
2019-02-26 15:49 ` Julien Grall
2019-02-26 15:58 ` Dave Martin
2019-02-26 15:59 ` Julien Grall
2019-02-26 16:03 ` Dave Martin
2019-02-18 19:52 ` [PATCH v5 09/26] KVM: arm64: Add a vcpu flag to control SVE visibility for the guest Dave Martin
2019-02-18 19:52 ` [PATCH v5 10/26] KVM: arm64: Propagate vcpu into read_id_reg() Dave Martin
2019-02-18 19:52 ` [PATCH v5 11/26] KVM: arm64: Extend reset_unknown() to handle mixed RES0/UNKNOWN registers Dave Martin
2019-02-20 13:33 ` Julien Thierry
2019-02-26 12:07 ` Dave Martin
2019-02-22 16:04 ` Julien Grall
2019-02-18 19:52 ` [PATCH v5 12/26] KVM: arm64: Support runtime sysreg visibility filtering Dave Martin
2019-02-20 14:33 ` Julien Thierry
2019-02-26 12:07 ` Dave Martin
2019-02-20 15:37 ` Mark Rutland
2019-02-26 12:12 ` Dave Martin
2019-02-18 19:52 ` [PATCH v5 13/26] KVM: arm64/sve: System register context switch and access support Dave Martin
2019-02-20 16:48 ` Julien Thierry
2019-02-26 16:32 ` Julien Grall
2019-02-26 17:01 ` Dave Martin
2019-02-27 12:02 ` Julien Grall
2019-02-27 13:50 ` Dave Martin
2019-02-27 14:17 ` Julien Grall
2019-02-27 14:38 ` Dave Martin
2019-02-18 19:52 ` [PATCH v5 14/26] KVM: arm64/sve: Context switch the SVE registers Dave Martin
2019-02-20 16:19 ` Mark Rutland
2019-02-26 12:13 ` Dave Martin
2019-02-20 16:46 ` Julien Thierry
2019-02-26 12:13 ` Dave Martin
2019-02-26 16:56 ` Julien Grall
2019-02-27 13:37 ` Dave Martin
2019-02-18 19:52 ` [PATCH v5 15/26] KVM: Allow 2048-bit register access via ioctl interface Dave Martin
2019-02-18 19:52 ` [PATCH v5 16/26] KVM: arm64: Add missing #include of <linux/string.h> in guest.c Dave Martin
2019-02-18 19:52 ` [PATCH v5 17/26] KVM: arm64: Reject ioctl access to FPSIMD V-regs on SVE vcpus Dave Martin
2019-02-21 12:06 ` Julien Thierry
2019-02-26 12:13 ` Dave Martin
2019-02-18 19:52 ` [PATCH v5 18/26] KVM: arm64/sve: Add SVE support to register access ioctl interface Dave Martin
2019-02-21 15:23 ` Julien Thierry
2019-02-26 12:13 ` Dave Martin
2019-03-01 13:03 ` Julien Thierry
2019-03-01 14:45 ` Dave Martin
2019-02-18 19:52 ` [PATCH v5 19/26] KVM: arm64: Enumerate SVE register indices for KVM_GET_REG_LIST Dave Martin
2019-02-21 16:28 ` Julien Thierry
2019-02-18 19:52 ` [PATCH v5 20/26] arm64/sve: In-kernel vector length availability query interface Dave Martin
2019-02-18 19:52 ` [PATCH v5 21/26] KVM: arm/arm64: Add hook to finalize the vcpu configuration Dave Martin
2019-02-18 19:52 ` Dave Martin [this message]
2019-02-21 17:48 ` [PATCH v5 22/26] KVM: arm64/sve: Add pseudo-register for the guest's vector lengths Julien Thierry
2019-02-26 12:13 ` Dave Martin
2019-03-01 13:28 ` Julien Thierry
2019-03-01 14:55 ` Dave Martin
2019-03-07 13:47 ` Marc Zyngier
2019-03-07 15:30 ` Dave Martin
2019-02-18 19:52 ` [PATCH v5 23/26] KVM: arm64/sve: Allow userspace to enable SVE for vcpus Dave Martin
2019-02-22 9:05 ` Julien Thierry
2019-02-26 12:13 ` Dave Martin
2019-02-18 19:52 ` [PATCH v5 24/26] KVM: arm64: Add a capabillity to advertise SVE support Dave Martin
2019-02-22 9:10 ` Julien Thierry
2019-02-26 12:14 ` Dave Martin
2019-02-18 19:52 ` [PATCH v5 25/26] KVM: Document errors for KVM_GET_ONE_REG and KVM_SET_ONE_REG Dave Martin
2019-02-18 19:52 ` [PATCH v5 26/26] KVM: arm64/sve: Document KVM API extensions for SVE Dave Martin
2019-02-20 15:47 ` [PATCH v5 00/26] KVM: arm64: SVE guest support Dave Martin
2019-03-03 2:40 ` Zhang, Lei
2019-03-05 9:47 ` Dave Martin
2019-03-08 7:06 ` Zhang, Lei
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=1550519559-15915-23-git-send-email-Dave.Martin@arm.com \
--to=dave.martin@arm.com \
--cc=alex.bennee@linaro.org \
--cc=ard.biesheuvel@linaro.org \
--cc=catalin.marinas@arm.com \
--cc=cdall@kernel.org \
--cc=julien.grall@arm.com \
--cc=kvmarm@lists.cs.columbia.edu \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=marc.zyngier@arm.com \
--cc=peter.maydell@linaro.org \
--cc=tokamoto@jp.fujitsu.com \
--cc=will.deacon@arm.com \
--cc=zhang.lei@jp.fujitsu.com \
/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).