diff options
Diffstat (limited to 'arch/s390/kvm/priv.c')
-rw-r--r-- | arch/s390/kvm/priv.c | 49 |
1 files changed, 49 insertions, 0 deletions
diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c index 73c47bd95db3..391626361084 100644 --- a/arch/s390/kvm/priv.c +++ b/arch/s390/kvm/priv.c | |||
@@ -326,3 +326,52 @@ int kvm_s390_handle_b2(struct kvm_vcpu *vcpu) | |||
326 | } | 326 | } |
327 | return -EOPNOTSUPP; | 327 | return -EOPNOTSUPP; |
328 | } | 328 | } |
329 | |||
330 | static int handle_tprot(struct kvm_vcpu *vcpu) | ||
331 | { | ||
332 | int base1 = (vcpu->arch.sie_block->ipb & 0xf0000000) >> 28; | ||
333 | int disp1 = (vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16; | ||
334 | int base2 = (vcpu->arch.sie_block->ipb & 0xf000) >> 12; | ||
335 | int disp2 = vcpu->arch.sie_block->ipb & 0x0fff; | ||
336 | u64 address1 = disp1 + base1 ? vcpu->arch.guest_gprs[base1] : 0; | ||
337 | u64 address2 = disp2 + base2 ? vcpu->arch.guest_gprs[base2] : 0; | ||
338 | struct vm_area_struct *vma; | ||
339 | |||
340 | vcpu->stat.instruction_tprot++; | ||
341 | |||
342 | /* we only handle the Linux memory detection case: | ||
343 | * access key == 0 | ||
344 | * guest DAT == off | ||
345 | * everything else goes to userspace. */ | ||
346 | if (address2 & 0xf0) | ||
347 | return -EOPNOTSUPP; | ||
348 | if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_DAT) | ||
349 | return -EOPNOTSUPP; | ||
350 | |||
351 | |||
352 | down_read(¤t->mm->mmap_sem); | ||
353 | vma = find_vma(current->mm, | ||
354 | (unsigned long) __guestaddr_to_user(vcpu, address1)); | ||
355 | if (!vma) { | ||
356 | up_read(¤t->mm->mmap_sem); | ||
357 | return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); | ||
358 | } | ||
359 | |||
360 | vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44); | ||
361 | if (!(vma->vm_flags & VM_WRITE) && (vma->vm_flags & VM_READ)) | ||
362 | vcpu->arch.sie_block->gpsw.mask |= (1ul << 44); | ||
363 | if (!(vma->vm_flags & VM_WRITE) && !(vma->vm_flags & VM_READ)) | ||
364 | vcpu->arch.sie_block->gpsw.mask |= (2ul << 44); | ||
365 | |||
366 | up_read(¤t->mm->mmap_sem); | ||
367 | return 0; | ||
368 | } | ||
369 | |||
370 | int kvm_s390_handle_e5(struct kvm_vcpu *vcpu) | ||
371 | { | ||
372 | /* For e5xx... instructions we only handle TPROT */ | ||
373 | if ((vcpu->arch.sie_block->ipa & 0x00ff) == 0x01) | ||
374 | return handle_tprot(vcpu); | ||
375 | return -EOPNOTSUPP; | ||
376 | } | ||
377 | |||