提交 1824c723 编写于 作者: D David Hildenbrand 提交者: Christian Borntraeger

KVM: s390: pfmf: support conditional-sske facility

We already indicate that facility but don't implement it in our pfmf
interception handler. Let's add a new storage key handling function for
conditionally setting the guest storage key.

As we will reuse this function later on, let's directly implement returning
the old key via parameter and indicating if any change happened via rc.
Signed-off-by: NDavid Hildenbrand <dahi@linux.vnet.ibm.com>
Signed-off-by: NChristian Borntraeger <borntraeger@de.ibm.com>
上级 2c26d1d2
...@@ -893,6 +893,9 @@ void ptep_zap_key(struct mm_struct *mm, unsigned long addr, pte_t *ptep); ...@@ -893,6 +893,9 @@ void ptep_zap_key(struct mm_struct *mm, unsigned long addr, pte_t *ptep);
bool test_and_clear_guest_dirty(struct mm_struct *mm, unsigned long address); bool test_and_clear_guest_dirty(struct mm_struct *mm, unsigned long address);
int set_guest_storage_key(struct mm_struct *mm, unsigned long addr, int set_guest_storage_key(struct mm_struct *mm, unsigned long addr,
unsigned char key, bool nq); unsigned char key, bool nq);
int cond_set_guest_storage_key(struct mm_struct *mm, unsigned long addr,
unsigned char key, unsigned char *oldkey,
bool nq, bool mr, bool mc);
int get_guest_storage_key(struct mm_struct *mm, unsigned long addr, int get_guest_storage_key(struct mm_struct *mm, unsigned long addr,
unsigned char *key); unsigned char *key);
......
...@@ -654,8 +654,10 @@ static int handle_epsw(struct kvm_vcpu *vcpu) ...@@ -654,8 +654,10 @@ static int handle_epsw(struct kvm_vcpu *vcpu)
static int handle_pfmf(struct kvm_vcpu *vcpu) static int handle_pfmf(struct kvm_vcpu *vcpu)
{ {
bool mr = false, mc = false, nq;
int reg1, reg2; int reg1, reg2;
unsigned long start, end; unsigned long start, end;
unsigned char key;
vcpu->stat.instruction_pfmf++; vcpu->stat.instruction_pfmf++;
...@@ -675,6 +677,15 @@ static int handle_pfmf(struct kvm_vcpu *vcpu) ...@@ -675,6 +677,15 @@ static int handle_pfmf(struct kvm_vcpu *vcpu)
!test_kvm_facility(vcpu->kvm, 14)) !test_kvm_facility(vcpu->kvm, 14))
return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
/* Only provide conditional-SSKE support if enabled for the guest */
if (vcpu->run->s.regs.gprs[reg1] & PFMF_SK &&
test_kvm_facility(vcpu->kvm, 10)) {
mr = vcpu->run->s.regs.gprs[reg1] & PFMF_MR;
mc = vcpu->run->s.regs.gprs[reg1] & PFMF_MC;
}
nq = vcpu->run->s.regs.gprs[reg1] & PFMF_NQ;
key = vcpu->run->s.regs.gprs[reg1] & PFMF_KEY;
start = vcpu->run->s.regs.gprs[reg2] & PAGE_MASK; start = vcpu->run->s.regs.gprs[reg2] & PAGE_MASK;
start = kvm_s390_logical_to_effective(vcpu, start); start = kvm_s390_logical_to_effective(vcpu, start);
...@@ -723,11 +734,10 @@ static int handle_pfmf(struct kvm_vcpu *vcpu) ...@@ -723,11 +734,10 @@ static int handle_pfmf(struct kvm_vcpu *vcpu)
if (rc) if (rc)
return rc; return rc;
down_read(&current->mm->mmap_sem); down_read(&current->mm->mmap_sem);
rc = set_guest_storage_key(current->mm, useraddr, rc = cond_set_guest_storage_key(current->mm, useraddr,
vcpu->run->s.regs.gprs[reg1] & PFMF_KEY, key, NULL, nq, mr, mc);
vcpu->run->s.regs.gprs[reg1] & PFMF_NQ);
up_read(&current->mm->mmap_sem); up_read(&current->mm->mmap_sem);
if (rc) if (rc < 0)
return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
} }
......
...@@ -539,6 +539,39 @@ int set_guest_storage_key(struct mm_struct *mm, unsigned long addr, ...@@ -539,6 +539,39 @@ int set_guest_storage_key(struct mm_struct *mm, unsigned long addr,
} }
EXPORT_SYMBOL(set_guest_storage_key); EXPORT_SYMBOL(set_guest_storage_key);
/**
* Conditionally set a guest storage key (handling csske).
* oldkey will be updated when either mr or mc is set and a pointer is given.
*
* Returns 0 if a guests storage key update wasn't necessary, 1 if the guest
* storage key was updated and -EFAULT on access errors.
*/
int cond_set_guest_storage_key(struct mm_struct *mm, unsigned long addr,
unsigned char key, unsigned char *oldkey,
bool nq, bool mr, bool mc)
{
unsigned char tmp, mask = _PAGE_ACC_BITS | _PAGE_FP_BIT;
int rc;
/* we can drop the pgste lock between getting and setting the key */
if (mr | mc) {
rc = get_guest_storage_key(current->mm, addr, &tmp);
if (rc)
return rc;
if (oldkey)
*oldkey = tmp;
if (!mr)
mask |= _PAGE_REFERENCED;
if (!mc)
mask |= _PAGE_CHANGED;
if (!((tmp ^ key) & mask))
return 0;
}
rc = set_guest_storage_key(current->mm, addr, key, nq);
return rc < 0 ? rc : 1;
}
EXPORT_SYMBOL(cond_set_guest_storage_key);
int get_guest_storage_key(struct mm_struct *mm, unsigned long addr, int get_guest_storage_key(struct mm_struct *mm, unsigned long addr,
unsigned char *key) unsigned char *key)
{ {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册