Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ef50f7ac authored by Christian Borntraeger's avatar Christian Borntraeger Committed by Avi Kivity
Browse files

KVM: s390: Allow stfle instruction in the guest



2.6.31-rc introduced an architecture level set checker based on facility
bits. e.g. if the kernel is compiled to run only on z9, several facility
bits are checked very early and the kernel refuses to boot if a z9 specific
facility is missing.
Until now kvm on s390 did not implement the store facility extended (STFLE)
instruction. A 2.6.31-rc kernel that was compiled for z9 or higher did not
boot in kvm. This patch implements stfle.

This patch should go in before 2.6.31.

Signed-off-by: default avatarChristian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: default avatarAvi Kivity <avi@redhat.com>
parent a3f9d398
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -99,7 +99,9 @@ struct kvm_s390_sie_block {
	__u8	reservedd0[48];		/* 0x00d0 */
	__u64	gcr[16];		/* 0x0100 */
	__u64	gbea;			/* 0x0180 */
	__u8	reserved188[120];	/* 0x0188 */
	__u8	reserved188[24];	/* 0x0188 */
	__u32	fac;			/* 0x01a0 */
	__u8	reserved1a4[92];	/* 0x01a4 */
} __attribute__((packed));

struct kvm_vcpu_stat {
+22 −1
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@
#include <asm/lowcore.h>
#include <asm/pgtable.h>
#include <asm/nmi.h>
#include <asm/system.h>
#include "kvm-s390.h"
#include "gaccess.h"

@@ -69,6 +70,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
	{ NULL }
};

static unsigned long long *facilities;

/* Section: not file related */
void kvm_arch_hardware_enable(void *garbage)
@@ -288,6 +290,7 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
	vcpu->arch.sie_block->gmsor = vcpu->kvm->arch.guest_origin;
	vcpu->arch.sie_block->ecb   = 2;
	vcpu->arch.sie_block->eca   = 0xC1002001U;
	vcpu->arch.sie_block->fac   = (int) (long) facilities;
	hrtimer_init(&vcpu->arch.ckc_timer, CLOCK_REALTIME, HRTIMER_MODE_ABS);
	tasklet_init(&vcpu->arch.tasklet, kvm_s390_tasklet,
		     (unsigned long) vcpu);
@@ -739,11 +742,29 @@ gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn)

static int __init kvm_s390_init(void)
{
	return kvm_init(NULL, sizeof(struct kvm_vcpu), THIS_MODULE);
	int ret;
	ret = kvm_init(NULL, sizeof(struct kvm_vcpu), THIS_MODULE);
	if (ret)
		return ret;

	/*
	 * guests can ask for up to 255+1 double words, we need a full page
	 * to hold the maximum amount of facilites. On the other hand, we
	 * only set facilities that are known to work in KVM.
	 */
	facilities = (unsigned long long *) get_zeroed_page(GFP_DMA);
	if (!facilities) {
		kvm_exit();
		return -ENOMEM;
	}
	stfle(facilities, 1);
	facilities[0] &= 0xff00fff3f0700000ULL;
	return 0;
}

static void __exit kvm_s390_exit(void)
{
	free_page((unsigned long) facilities);
	kvm_exit();
}

+1 −1
Original line number Diff line number Diff line
@@ -158,7 +158,7 @@ static int handle_stfl(struct kvm_vcpu *vcpu)

	vcpu->stat.instruction_stfl++;
	/* only pass the facility bits, which we can handle */
	facility_list &= 0xfe00fff3;
	facility_list &= 0xff00fff3;

	rc = copy_to_guest(vcpu, offsetof(struct _lowcore, stfl_fac_list),
			   &facility_list, sizeof(facility_list));