From: <darkhan@amazon.com>
To: <pbonzini@redhat.com>
Cc: <kvm@vger.kernel.org>, <corbet@lwn.net>, <maz@kernel.org>,
<james.morse@arm.com>, <catalin.marinas@arm.com>,
<chenhc@lemote.com>, <paulus@ozlabs.org>, <frankja@linux.ibm.com>,
<mingo@redhat.com>, <acme@redhat.com>, <graf@amazon.de>,
<darkhan@amazon.de>, Darkhan Mukashov <darkhan@amazon.com>
Subject: [PATCH 3/3] KVM: introduce new vcpu ioctls KVM_GET_MANY_REGS and KVM_SET_MANY_REGS
Date: Fri, 20 Nov 2020 13:56:16 +0100 [thread overview]
Message-ID: <20201120125616.14436-4-darkhan@amazon.com> (raw)
In-Reply-To: <20201120125616.14436-1-darkhan@amazon.com>
From: Darkhan Mukashov <darkhan@amazon.com>
In order to read/write arbitrary number of registers, one has to call
KVM_(GET|SET)_ONE_REG ioctls multiple times. New KVM APIs
KVM_(GET|SET)_MANY_REGS make it possible to bulk read/write vCPU registers
at one ioctl call. These ioctls can be very useful when vCPU state
serialization/deserialization is required (e.g. live update of kvm, live
migration of guests), hence all registers have to be saved/restored.
KVM_(GET|SET)_MANY_REGS will help avoid performance overhead associated
with syscall (ioctl in our case) handling. Tests conducted on AWS Graviton2
Processors (64-bit ARM Neoverse cores) show that average save/restore time
of all vCPU registers can be optimized ~3.5 times per vCPU with new ioctls.
Test results can be found in Table 1.
+---------+-------------+---------------+
| | kvm_one_reg | kvm_many_regs |
+---------+-------------+---------------+
| get all | 123 usec | 33 usec |
+---------+-------------+---------------+
| set all | 120 usec | 36 usec |
+---------+-------------+---------------+
Table 1. Test results
KVM_(GET|SET)_MANY_REGS accept one argument
struct kvm_many_regs {
/*
* number of regs to be got/set
*/
__u64 n;
/*
* the same struct used by KVM_(GET|SET)_ONE_REG
*/
struct kvm_one_reg reg[0];
}
New ioctls allow to get/set values of multiple registers implemented in a
vcpu. Registers to get/set are indicated by the 'id' field of each
struct kvm_one_reg in the passed array. On success, KVM_GET_MANY_REGS
writes values of indicated registers to memory locations pointed by
the 'addr' field of each kvm_one_reg, KVM_SET_MANY_REGS changes values
of registers to values located at memory locations pointed by the 'addr'
field of each kvm_one_reg.
KVM_(GET|SET)_MANY_REGS rely on KVM_(GET|SET)_ONE_REG, which are not
implemented in x86. Therefore, new ioctls support all architectures except
x86.
Signed-off-by: Darkhan Mukashov <darkhan@amazon.com>
---
Documentation/virt/kvm/api.rst | 74 ++++++++++++++++++++++++++++++++++
include/uapi/linux/kvm.h | 11 +++++
virt/kvm/kvm_main.c | 42 +++++++++++++++++++
3 files changed, 127 insertions(+)
diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
index 6d6135c15729..9a229f7e182e 100644
--- a/Documentation/virt/kvm/api.rst
+++ b/Documentation/virt/kvm/api.rst
@@ -4808,6 +4808,80 @@ If a vCPU is in running state while this ioctl is invoked, the vCPU may
experience inconsistent filtering behavior on MSR accesses.
+4.127 KVM_GET_MANY_REGS
+-----------------------
+
+:Capability: basic
+:Architectures: all except x86
+:Type: vcpu ioctl
+:Parameters: struct kvm_many_regs (in)
+:Returns: 0 on success, negative value on failure
+
+Errors:
+
+ ====== ============================================================
+ E2BIG the passed array of kvm_one_regs is too big, its size should
+ not exceed KVM_MANY_REGS_MAX_SIZE
+ ====== ============================================================
+
+As this ioctl uses KVM_GET_ONE_REG, errors from KVM_GET_ONE_REG are propagated.
+
+(These error codes are indicative only: do not rely on a specific error
+code being returned in a specific situation.)
+
+::
+
+ struct kvm_many_regs {
+ __u64 n;
+ struct kvm_one_reg reg[0];
+ };
+
+This ioctl allows to receive values of multiple registers implemented
+in a vcpu. Registers to read are indicated by the 'id' field of each
+kvm_one_reg struct in the passed array. On success, values of indicated
+registers are written to memory locations pointed by the 'addr' field
+of each kvm_one_reg.
+
+In case of duplicate IDs in the 'reg' array, the register will be read as many
+times as it appears in the array.
+
+The list of registers accessible using this interface is identical to the
+list in 4.68.
+
+4.128 KVM_SET_MANY_REGS
+-----------------------
+
+:Capability: basic
+:Architectures: all except x86
+:Type: vcpu ioctl
+:Parameters: struct kvm_many_regs (in)
+:Returns: 0 on success, negative value on failure
+
+Errors:
+
+ ====== ============================================================
+ E2BIG the passed array of kvm_one_regs is too big, its size should
+ not exceed KVM_MANY_REGS_MAX_SIZE
+ ====== ============================================================
+
+As this ioctl uses KVM_SET_ONE_REG, errors from KVM_SET_ONE_REG are propagated.
+
+(These error codes are indicative only: do not rely on a specific error
+code being returned in a specific situation.)
+
+This ioctl allows to set values of multiple registers implemented
+in a vcpu. Registers to set are indicated by the 'id' field of each
+kvm_one_reg struct in the passed array. On success, values of registers
+are changed to values located at memory locations pointed by the 'addr'
+field of each kvm_one_reg.
+
+In case of duplicate IDs in the 'reg' array, the register will be set as many
+times as it appears in the array.
+
+The list of registers accessible using this interface is identical to the
+list in 4.68.
+
+
5. The kvm_run structure
========================
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index ca41220b40b8..87e799457fc3 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -1223,6 +1223,14 @@ struct kvm_one_reg {
__u64 addr;
};
+/* For KVM_(GET|SET)_MANY_REGS */
+#define KVM_MANY_REGS_MAX_SIZE 16384
+
+struct kvm_many_regs {
+ __u64 n;
+ struct kvm_one_reg reg[0];
+};
+
#define KVM_MSI_VALID_DEVID (1U << 0)
struct kvm_msi {
__u32 address_lo;
@@ -1557,6 +1565,9 @@ struct kvm_pv_cmd {
/* Available with KVM_CAP_X86_MSR_FILTER */
#define KVM_X86_SET_MSR_FILTER _IOW(KVMIO, 0xc6, struct kvm_msr_filter)
+#define KVM_GET_MANY_REGS _IOW(KVMIO, 0xc7, struct kvm_many_regs)
+#define KVM_SET_MANY_REGS _IOW(KVMIO, 0xc8, struct kvm_many_regs)
+
/* Secure Encrypted Virtualization command */
enum sev_cmd_id {
/* Guest initialization commands */
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index e14185f4977f..3bb618882d2c 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -3255,6 +3255,48 @@ static long kvm_vcpu_ioctl(struct file *filp,
kvm_arch_after_reg_access(vcpu);
break;
}
+ case KVM_SET_MANY_REGS:
+ case KVM_GET_MANY_REGS: {
+ struct kvm_many_regs __user *user_regs = argp;
+ struct kvm_many_regs many_regs;
+ struct kvm_one_reg *reg;
+ unsigned int i, size;
+
+ r = kvm_arch_before_reg_access(vcpu);
+ if (r < 0)
+ break;
+
+ r = -EFAULT;
+ if (copy_from_user(&many_regs, user_regs, sizeof(many_regs)))
+ goto out_after_regs_access;
+
+ r = -E2BIG;
+ size = sizeof(struct kvm_one_reg) * many_regs.n;
+ if (size > KVM_MANY_REGS_MAX_SIZE)
+ goto out_after_regs_access;
+
+ r = -ENOMEM;
+ reg = (struct kvm_one_reg *)memdup_user(user_regs->reg, size);
+ if (IS_ERR(reg))
+ goto out_after_regs_access;
+
+ if (ioctl == KVM_GET_MANY_REGS)
+ for (i = 0; i < many_regs.n; i++) {
+ r = kvm_arch_vcpu_ioctl_get_one_reg(vcpu, ®[i]);
+ if (r < 0)
+ break;
+ }
+ else
+ for (i = 0; i < many_regs.n; i++) {
+ r = kvm_arch_vcpu_ioctl_set_one_reg(vcpu, ®[i]);
+ if (r < 0)
+ break;
+ }
+ kfree(reg);
+out_after_regs_access:
+ kvm_arch_after_reg_access(vcpu);
+ break;
+ }
case KVM_GET_REGS: {
struct kvm_regs *kvm_regs;
--
2.17.1
next prev parent reply other threads:[~2020-11-20 12:57 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-11-20 12:56 [PATCH 0/3] Introduce new vcpu ioctls KVM_(GET|SET)_MANY_REGS darkhan
2020-11-20 12:56 ` [PATCH 1/3] Documentation: KVM: change description of vcpu ioctls KVM_(GET|SET)_ONE_REG darkhan
2020-11-20 12:56 ` [PATCH 2/3] KVM: handle vcpu ioctls KVM_(GET|SET)_ONE_REG in a generic function darkhan
2020-11-20 12:56 ` darkhan [this message]
2020-11-23 11:39 ` [PATCH 0/3] Introduce new vcpu ioctls KVM_(GET|SET)_MANY_REGS Marc Zyngier
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=20201120125616.14436-4-darkhan@amazon.com \
--to=darkhan@amazon.com \
--cc=acme@redhat.com \
--cc=catalin.marinas@arm.com \
--cc=chenhc@lemote.com \
--cc=corbet@lwn.net \
--cc=darkhan@amazon.de \
--cc=frankja@linux.ibm.com \
--cc=graf@amazon.de \
--cc=james.morse@arm.com \
--cc=kvm@vger.kernel.org \
--cc=maz@kernel.org \
--cc=mingo@redhat.com \
--cc=paulus@ozlabs.org \
--cc=pbonzini@redhat.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