aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/kvm
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 /arch/s390/kvm
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>
Diffstat (limited to 'arch/s390/kvm')
-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
3 files changed, 98 insertions, 0 deletions
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 }