|
@@ -930,8 +930,9 @@ int kvm_s390_handle_eb(struct kvm_vcpu *vcpu)
|
|
|
static int handle_tprot(struct kvm_vcpu *vcpu)
|
|
|
{
|
|
|
u64 address1, address2;
|
|
|
- struct vm_area_struct *vma;
|
|
|
- unsigned long user_address;
|
|
|
+ unsigned long hva, gpa;
|
|
|
+ int ret = 0, cc = 0;
|
|
|
+ bool writable;
|
|
|
|
|
|
vcpu->stat.instruction_tprot++;
|
|
|
|
|
@@ -942,32 +943,41 @@ static int handle_tprot(struct kvm_vcpu *vcpu)
|
|
|
|
|
|
/* we only handle the Linux memory detection case:
|
|
|
* access key == 0
|
|
|
- * guest DAT == off
|
|
|
* everything else goes to userspace. */
|
|
|
if (address2 & 0xf0)
|
|
|
return -EOPNOTSUPP;
|
|
|
if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_DAT)
|
|
|
- return -EOPNOTSUPP;
|
|
|
-
|
|
|
- down_read(¤t->mm->mmap_sem);
|
|
|
- user_address = __gmap_translate(address1, vcpu->arch.gmap);
|
|
|
- if (IS_ERR_VALUE(user_address))
|
|
|
- goto out_inject;
|
|
|
- vma = find_vma(current->mm, user_address);
|
|
|
- if (!vma)
|
|
|
- goto out_inject;
|
|
|
- vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44);
|
|
|
- if (!(vma->vm_flags & VM_WRITE) && (vma->vm_flags & VM_READ))
|
|
|
- vcpu->arch.sie_block->gpsw.mask |= (1ul << 44);
|
|
|
- if (!(vma->vm_flags & VM_WRITE) && !(vma->vm_flags & VM_READ))
|
|
|
- vcpu->arch.sie_block->gpsw.mask |= (2ul << 44);
|
|
|
-
|
|
|
- up_read(¤t->mm->mmap_sem);
|
|
|
- return 0;
|
|
|
+ ipte_lock(vcpu);
|
|
|
+ ret = guest_translate_address(vcpu, address1, &gpa, 1);
|
|
|
+ if (ret == PGM_PROTECTION) {
|
|
|
+ /* Write protected? Try again with read-only... */
|
|
|
+ cc = 1;
|
|
|
+ ret = guest_translate_address(vcpu, address1, &gpa, 0);
|
|
|
+ }
|
|
|
+ if (ret) {
|
|
|
+ if (ret == PGM_ADDRESSING || ret == PGM_TRANSLATION_SPEC) {
|
|
|
+ ret = kvm_s390_inject_program_int(vcpu, ret);
|
|
|
+ } else if (ret > 0) {
|
|
|
+ /* Translation not available */
|
|
|
+ kvm_s390_set_psw_cc(vcpu, 3);
|
|
|
+ ret = 0;
|
|
|
+ }
|
|
|
+ goto out_unlock;
|
|
|
+ }
|
|
|
|
|
|
-out_inject:
|
|
|
- up_read(¤t->mm->mmap_sem);
|
|
|
- return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
|
|
|
+ hva = gfn_to_hva_prot(vcpu->kvm, gpa_to_gfn(gpa), &writable);
|
|
|
+ if (kvm_is_error_hva(hva)) {
|
|
|
+ ret = kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
|
|
|
+ } else {
|
|
|
+ if (!writable)
|
|
|
+ cc = 1; /* Write not permitted ==> read-only */
|
|
|
+ kvm_s390_set_psw_cc(vcpu, cc);
|
|
|
+ /* Note: CC2 only occurs for storage keys (not supported yet) */
|
|
|
+ }
|
|
|
+out_unlock:
|
|
|
+ if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_DAT)
|
|
|
+ ipte_unlock(vcpu);
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
int kvm_s390_handle_e5(struct kvm_vcpu *vcpu)
|