aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Huth <thuth@linux.vnet.ibm.com>2015-02-06 09:01:21 -0500
committerChristian Borntraeger <borntraeger@de.ibm.com>2015-03-17 11:26:24 -0400
commit41408c28f283b49202ae374b1c42bc8e9b33a048 (patch)
tree4acd40bb4bacc760ad3c65c82b5604145d64d437
parent664b4973537068402954bee6e2959b858f263a6f (diff)
KVM: s390: Add MEMOP ioctls for reading/writing guest memory
On s390, we've got to make sure to hold the IPTE lock while accessing logical memory. So let's add an ioctl for reading and writing logical memory to provide this feature for userspace, too. The maximum transfer size of this call is limited to 64kB to prevent that the guest can trigger huge copy_from/to_user transfers. QEMU currently only requests up to one or two pages so far, so 16*4kB seems to be a reasonable limit here. Signed-off-by: Thomas Huth <thuth@linux.vnet.ibm.com> Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
-rw-r--r--Documentation/virtual/kvm/api.txt46
-rw-r--r--arch/s390/kvm/gaccess.c22
-rw-r--r--arch/s390/kvm/gaccess.h2
-rw-r--r--arch/s390/kvm/kvm-s390.c74
-rw-r--r--include/uapi/linux/kvm.h21
5 files changed, 165 insertions, 0 deletions
diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
index ee47998ec368..281179d92a28 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -2716,6 +2716,52 @@ The fields in each entry are defined as follows:
2716 eax, ebx, ecx, edx: the values returned by the cpuid instruction for 2716 eax, ebx, ecx, edx: the values returned by the cpuid instruction for
2717 this function/index combination 2717 this function/index combination
2718 2718
27194.89 KVM_S390_MEM_OP
2720
2721Capability: KVM_CAP_S390_MEM_OP
2722Architectures: s390
2723Type: vcpu ioctl
2724Parameters: struct kvm_s390_mem_op (in)
2725Returns: = 0 on success,
2726 < 0 on generic error (e.g. -EFAULT or -ENOMEM),
2727 > 0 if an exception occurred while walking the page tables
2728
2729Read or write data from/to the logical (virtual) memory of a VPCU.
2730
2731Parameters are specified via the following structure:
2732
2733struct kvm_s390_mem_op {
2734 __u64 gaddr; /* the guest address */
2735 __u64 flags; /* flags */
2736 __u32 size; /* amount of bytes */
2737 __u32 op; /* type of operation */
2738 __u64 buf; /* buffer in userspace */
2739 __u8 ar; /* the access register number */
2740 __u8 reserved[31]; /* should be set to 0 */
2741};
2742
2743The type of operation is specified in the "op" field. It is either
2744KVM_S390_MEMOP_LOGICAL_READ for reading from logical memory space or
2745KVM_S390_MEMOP_LOGICAL_WRITE for writing to logical memory space. The
2746KVM_S390_MEMOP_F_CHECK_ONLY flag can be set in the "flags" field to check
2747whether the corresponding memory access would create an access exception
2748(without touching the data in the memory at the destination). In case an
2749access exception occurred while walking the MMU tables of the guest, the
2750ioctl returns a positive error number to indicate the type of exception.
2751This exception is also raised directly at the corresponding VCPU if the
2752flag KVM_S390_MEMOP_F_INJECT_EXCEPTION is set in the "flags" field.
2753
2754The start address of the memory region has to be specified in the "gaddr"
2755field, and the length of the region in the "size" field. "buf" is the buffer
2756supplied by the userspace application where the read data should be written
2757to for KVM_S390_MEMOP_LOGICAL_READ, or where the data that should be written
2758is stored for a KVM_S390_MEMOP_LOGICAL_WRITE. "buf" is unused and can be NULL
2759when KVM_S390_MEMOP_F_CHECK_ONLY is specified. "ar" designates the access
2760register number to be used.
2761
2762The "reserved" field is meant for future extensions. It is not used by
2763KVM with the currently defined set of flags.
2764
27195. The kvm_run structure 27655. The kvm_run structure
2720------------------------ 2766------------------------
2721 2767
diff --git a/arch/s390/kvm/gaccess.c b/arch/s390/kvm/gaccess.c
index ea38d716e24d..a7559f7207df 100644
--- a/arch/s390/kvm/gaccess.c
+++ b/arch/s390/kvm/gaccess.c
@@ -864,6 +864,28 @@ int guest_translate_address(struct kvm_vcpu *vcpu, unsigned long gva, ar_t ar,
864} 864}
865 865
866/** 866/**
867 * check_gva_range - test a range of guest virtual addresses for accessibility
868 */
869int check_gva_range(struct kvm_vcpu *vcpu, unsigned long gva, ar_t ar,
870 unsigned long length, int is_write)
871{
872 unsigned long gpa;
873 unsigned long currlen;
874 int rc = 0;
875
876 ipte_lock(vcpu);
877 while (length > 0 && !rc) {
878 currlen = min(length, PAGE_SIZE - (gva % PAGE_SIZE));
879 rc = guest_translate_address(vcpu, gva, ar, &gpa, is_write);
880 gva += currlen;
881 length -= currlen;
882 }
883 ipte_unlock(vcpu);
884
885 return rc;
886}
887
888/**
867 * kvm_s390_check_low_addr_prot_real - check for low-address protection 889 * kvm_s390_check_low_addr_prot_real - check for low-address protection
868 * @gra: Guest real address 890 * @gra: Guest real address
869 * 891 *
diff --git a/arch/s390/kvm/gaccess.h b/arch/s390/kvm/gaccess.h
index 835e557dabf4..ef03726cc661 100644
--- a/arch/s390/kvm/gaccess.h
+++ b/arch/s390/kvm/gaccess.h
@@ -157,6 +157,8 @@ int read_guest_lc(struct kvm_vcpu *vcpu, unsigned long gra, void *data,
157 157
158int guest_translate_address(struct kvm_vcpu *vcpu, unsigned long gva, 158int guest_translate_address(struct kvm_vcpu *vcpu, unsigned long gva,
159 ar_t ar, unsigned long *gpa, int write); 159 ar_t ar, unsigned long *gpa, int write);
160int check_gva_range(struct kvm_vcpu *vcpu, unsigned long gva, ar_t ar,
161 unsigned long length, int is_write);
160 162
161int access_guest(struct kvm_vcpu *vcpu, unsigned long ga, ar_t ar, void *data, 163int access_guest(struct kvm_vcpu *vcpu, unsigned long ga, ar_t ar, void *data,
162 unsigned long len, int write); 164 unsigned long len, int write);
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 610e90afadf2..b7ecef98b668 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -25,6 +25,7 @@
25#include <linux/random.h> 25#include <linux/random.h>
26#include <linux/slab.h> 26#include <linux/slab.h>
27#include <linux/timer.h> 27#include <linux/timer.h>
28#include <linux/vmalloc.h>
28#include <asm/asm-offsets.h> 29#include <asm/asm-offsets.h>
29#include <asm/lowcore.h> 30#include <asm/lowcore.h>
30#include <asm/pgtable.h> 31#include <asm/pgtable.h>
@@ -38,6 +39,8 @@
38#include "trace.h" 39#include "trace.h"
39#include "trace-s390.h" 40#include "trace-s390.h"
40 41
42#define MEM_OP_MAX_SIZE 65536 /* Maximum transfer size for KVM_S390_MEM_OP */
43
41#define VCPU_STAT(x) offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU 44#define VCPU_STAT(x) offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU
42 45
43struct kvm_stats_debugfs_item debugfs_entries[] = { 46struct kvm_stats_debugfs_item debugfs_entries[] = {
@@ -177,6 +180,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
177 case KVM_CAP_S390_USER_SIGP: 180 case KVM_CAP_S390_USER_SIGP:
178 r = 1; 181 r = 1;
179 break; 182 break;
183 case KVM_CAP_S390_MEM_OP:
184 r = MEM_OP_MAX_SIZE;
185 break;
180 case KVM_CAP_NR_VCPUS: 186 case KVM_CAP_NR_VCPUS:
181 case KVM_CAP_MAX_VCPUS: 187 case KVM_CAP_MAX_VCPUS:
182 r = KVM_MAX_VCPUS; 188 r = KVM_MAX_VCPUS;
@@ -2185,6 +2191,65 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,
2185 return r; 2191 return r;
2186} 2192}
2187 2193
2194static long kvm_s390_guest_mem_op(struct kvm_vcpu *vcpu,
2195 struct kvm_s390_mem_op *mop)
2196{
2197 void __user *uaddr = (void __user *)mop->buf;
2198 void *tmpbuf = NULL;
2199 int r, srcu_idx;
2200 const u64 supported_flags = KVM_S390_MEMOP_F_INJECT_EXCEPTION
2201 | KVM_S390_MEMOP_F_CHECK_ONLY;
2202
2203 if (mop->flags & ~supported_flags)
2204 return -EINVAL;
2205
2206 if (mop->size > MEM_OP_MAX_SIZE)
2207 return -E2BIG;
2208
2209 if (!(mop->flags & KVM_S390_MEMOP_F_CHECK_ONLY)) {
2210 tmpbuf = vmalloc(mop->size);
2211 if (!tmpbuf)
2212 return -ENOMEM;
2213 }
2214
2215 srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
2216
2217 switch (mop->op) {
2218 case KVM_S390_MEMOP_LOGICAL_READ:
2219 if (mop->flags & KVM_S390_MEMOP_F_CHECK_ONLY) {
2220 r = check_gva_range(vcpu, mop->gaddr, mop->ar, mop->size, false);
2221 break;
2222 }
2223 r = read_guest(vcpu, mop->gaddr, mop->ar, tmpbuf, mop->size);
2224 if (r == 0) {
2225 if (copy_to_user(uaddr, tmpbuf, mop->size))
2226 r = -EFAULT;
2227 }
2228 break;
2229 case KVM_S390_MEMOP_LOGICAL_WRITE:
2230 if (mop->flags & KVM_S390_MEMOP_F_CHECK_ONLY) {
2231 r = check_gva_range(vcpu, mop->gaddr, mop->ar, mop->size, true);
2232 break;
2233 }
2234 if (copy_from_user(tmpbuf, uaddr, mop->size)) {
2235 r = -EFAULT;
2236 break;
2237 }
2238 r = write_guest(vcpu, mop->gaddr, mop->ar, tmpbuf, mop->size);
2239 break;
2240 default:
2241 r = -EINVAL;
2242 }
2243
2244 srcu_read_unlock(&vcpu->kvm->srcu, srcu_idx);
2245
2246 if (r > 0 && (mop->flags & KVM_S390_MEMOP_F_INJECT_EXCEPTION) != 0)
2247 kvm_s390_inject_prog_irq(vcpu, &vcpu->arch.pgm);
2248
2249 vfree(tmpbuf);
2250 return r;
2251}
2252
2188long kvm_arch_vcpu_ioctl(struct file *filp, 2253long kvm_arch_vcpu_ioctl(struct file *filp,
2189 unsigned int ioctl, unsigned long arg) 2254 unsigned int ioctl, unsigned long arg)
2190{ 2255{
@@ -2284,6 +2349,15 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
2284 r = kvm_vcpu_ioctl_enable_cap(vcpu, &cap); 2349 r = kvm_vcpu_ioctl_enable_cap(vcpu, &cap);
2285 break; 2350 break;
2286 } 2351 }
2352 case KVM_S390_MEM_OP: {
2353 struct kvm_s390_mem_op mem_op;
2354
2355 if (copy_from_user(&mem_op, argp, sizeof(mem_op)) == 0)
2356 r = kvm_s390_guest_mem_op(vcpu, &mem_op);
2357 else
2358 r = -EFAULT;
2359 break;
2360 }
2287 default: 2361 default:
2288 r = -ENOTTY; 2362 r = -ENOTTY;
2289 } 2363 }
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 82634a492fe0..0e16f2c9f0de 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -365,6 +365,24 @@ struct kvm_translation {
365 __u8 pad[5]; 365 __u8 pad[5];
366}; 366};
367 367
368/* for KVM_S390_MEM_OP */
369struct kvm_s390_mem_op {
370 /* in */
371 __u64 gaddr; /* the guest address */
372 __u64 flags; /* flags */
373 __u32 size; /* amount of bytes */
374 __u32 op; /* type of operation */
375 __u64 buf; /* buffer in userspace */
376 __u8 ar; /* the access register number */
377 __u8 reserved[31]; /* should be set to 0 */
378};
379/* types for kvm_s390_mem_op->op */
380#define KVM_S390_MEMOP_LOGICAL_READ 0
381#define KVM_S390_MEMOP_LOGICAL_WRITE 1
382/* flags for kvm_s390_mem_op->flags */
383#define KVM_S390_MEMOP_F_CHECK_ONLY (1ULL << 0)
384#define KVM_S390_MEMOP_F_INJECT_EXCEPTION (1ULL << 1)
385
368/* for KVM_INTERRUPT */ 386/* for KVM_INTERRUPT */
369struct kvm_interrupt { 387struct kvm_interrupt {
370 /* in */ 388 /* in */
@@ -761,6 +779,7 @@ struct kvm_ppc_smmu_info {
761#define KVM_CAP_CHECK_EXTENSION_VM 105 779#define KVM_CAP_CHECK_EXTENSION_VM 105
762#define KVM_CAP_S390_USER_SIGP 106 780#define KVM_CAP_S390_USER_SIGP 106
763#define KVM_CAP_S390_VECTOR_REGISTERS 107 781#define KVM_CAP_S390_VECTOR_REGISTERS 107
782#define KVM_CAP_S390_MEM_OP 108
764 783
765#ifdef KVM_CAP_IRQ_ROUTING 784#ifdef KVM_CAP_IRQ_ROUTING
766 785
@@ -1136,6 +1155,8 @@ struct kvm_s390_ucas_mapping {
1136#define KVM_ARM_VCPU_INIT _IOW(KVMIO, 0xae, struct kvm_vcpu_init) 1155#define KVM_ARM_VCPU_INIT _IOW(KVMIO, 0xae, struct kvm_vcpu_init)
1137#define KVM_ARM_PREFERRED_TARGET _IOR(KVMIO, 0xaf, struct kvm_vcpu_init) 1156#define KVM_ARM_PREFERRED_TARGET _IOR(KVMIO, 0xaf, struct kvm_vcpu_init)
1138#define KVM_GET_REG_LIST _IOWR(KVMIO, 0xb0, struct kvm_reg_list) 1157#define KVM_GET_REG_LIST _IOWR(KVMIO, 0xb0, struct kvm_reg_list)
1158/* Available with KVM_CAP_S390_MEM_OP */
1159#define KVM_S390_MEM_OP _IOW(KVMIO, 0xb1, struct kvm_s390_mem_op)
1139 1160
1140#define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0) 1161#define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0)
1141#define KVM_DEV_ASSIGN_PCI_2_3 (1 << 1) 1162#define KVM_DEV_ASSIGN_PCI_2_3 (1 << 1)