Skip to content

Commit

Permalink
KVM: s390: vsie: support STFLE interpretation
Browse files Browse the repository at this point in the history
Issuing STFLE is extremely rare. Instead of copying 2k on every
VSIE call, let's do this lazily, when a guest 3 tries to execute
STFLE. We can setup the block and retry.

Unfortunately, we can't directly forward that facility list, as
we only have a 31 bit address for the facility list designation.
So let's use a DMA allocation for our vsie_page instead for now.

Acked-by: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: David Hildenbrand <dahi@linux.vnet.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
  • Loading branch information
David Hildenbrand authored and Christian Borntraeger committed Jun 21, 2016
1 parent 4ceafa9 commit 66b630d
Showing 1 changed file with 47 additions and 2 deletions.
49 changes: 47 additions & 2 deletions arch/s390/kvm/vsie.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <asm/mmu_context.h>
#include <asm/sclp.h>
#include <asm/nmi.h>
#include <asm/dis.h>
#include "kvm-s390.h"
#include "gaccess.h"

Expand All @@ -27,7 +28,8 @@ struct vsie_page {
struct kvm_s390_sie_block *scb_o; /* 0x0200 */
/* the shadow gmap in use by the vsie_page */
struct gmap *gmap; /* 0x0208 */
__u8 reserved[0x1000 - 0x0210]; /* 0x0210 */
__u8 reserved[0x0800 - 0x0210]; /* 0x0210 */
__u8 fac[S390_ARCH_FAC_LIST_SIZE_BYTE]; /* 0x0800 */
} __packed;

/* trigger a validity icpt for the given scb */
Expand Down Expand Up @@ -194,6 +196,7 @@ static int shadow_scb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
scb_s->ecb2 = 0;
scb_s->ecb3 = 0;
scb_s->ecd = 0;
scb_s->fac = 0;

rc = prepare_cpuflags(vcpu, vsie_page);
if (rc)
Expand Down Expand Up @@ -521,6 +524,44 @@ static inline void clear_vsie_icpt(struct vsie_page *vsie_page)
vsie_page->scb_s.icptcode = 0;
}

/* rewind the psw and clear the vsie icpt, so we can retry execution */
static void retry_vsie_icpt(struct vsie_page *vsie_page)
{
struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s;
int ilen = insn_length(scb_s->ipa >> 8);

/* take care of EXECUTE instructions */
if (scb_s->icptstatus & 1) {
ilen = (scb_s->icptstatus >> 4) & 0x6;
if (!ilen)
ilen = 4;
}
scb_s->gpsw.addr = __rewind_psw(scb_s->gpsw, ilen);
clear_vsie_icpt(vsie_page);
}

/*
* Try to shadow + enable the guest 2 provided facility list.
* Retry instruction execution if enabled for and provided by guest 2.
*
* Returns: - 0 if handled (retry or guest 2 icpt)
* - > 0 if control has to be given to guest 2
*/
static int handle_stfle(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
{
struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s;
__u32 fac = vsie_page->scb_o->fac & 0x7ffffff8U;

if (fac && test_kvm_facility(vcpu->kvm, 7)) {
retry_vsie_icpt(vsie_page);
if (read_guest_real(vcpu, fac, &vsie_page->fac,
sizeof(vsie_page->fac)))
return set_validity_icpt(scb_s, 0x1090U);
scb_s->fac = (__u32)(__u64) &vsie_page->fac;
}
return 0;
}

/*
* Run the vsie on a shadow scb and a shadow gmap, without any further
* sanity checks, handling SIE faults.
Expand Down Expand Up @@ -558,6 +599,10 @@ static int do_vsie_run(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
return handle_fault(vcpu, vsie_page);

switch (scb_s->icptcode) {
case ICPT_INST:
if (scb_s->ipa == 0xb2b0)
rc = handle_stfle(vcpu, vsie_page);
break;
case ICPT_STOP:
/* stop not requested by g2 - must have been a kick */
if (!(atomic_read(&scb_o->cpuflags) & CPUSTAT_STOP_INT))
Expand Down Expand Up @@ -690,7 +735,7 @@ static struct vsie_page *get_vsie_page(struct kvm *kvm, unsigned long addr)

mutex_lock(&kvm->arch.vsie.mutex);
if (kvm->arch.vsie.page_count < nr_vcpus) {
page = alloc_page(GFP_KERNEL | __GFP_ZERO);
page = alloc_page(GFP_KERNEL | __GFP_ZERO | GFP_DMA);
if (!page) {
mutex_unlock(&kvm->arch.vsie.mutex);
return ERR_PTR(-ENOMEM);
Expand Down

0 comments on commit 66b630d

Please sign in to comment.