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

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
...@@ -99,7 +99,9 @@ struct kvm_s390_sie_block { ...@@ -99,7 +99,9 @@ struct kvm_s390_sie_block {
__u8 reservedd0[48]; /* 0x00d0 */ __u8 reservedd0[48]; /* 0x00d0 */
__u64 gcr[16]; /* 0x0100 */ __u64 gcr[16]; /* 0x0100 */
__u64 gbea; /* 0x0180 */ __u64 gbea; /* 0x0180 */
__u8 reserved188[120]; /* 0x0188 */ __u8 reserved188[24]; /* 0x0188 */
__u32 fac; /* 0x01a0 */
__u8 reserved1a4[92]; /* 0x01a4 */
} __attribute__((packed)); } __attribute__((packed));
struct kvm_vcpu_stat { struct kvm_vcpu_stat {
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <asm/lowcore.h> #include <asm/lowcore.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include <asm/nmi.h> #include <asm/nmi.h>
#include <asm/system.h>
#include "kvm-s390.h" #include "kvm-s390.h"
#include "gaccess.h" #include "gaccess.h"
...@@ -69,6 +70,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = { ...@@ -69,6 +70,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
{ NULL } { NULL }
}; };
static unsigned long long *facilities;
/* Section: not file related */ /* Section: not file related */
void kvm_arch_hardware_enable(void *garbage) void kvm_arch_hardware_enable(void *garbage)
...@@ -288,6 +290,7 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu) ...@@ -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->gmsor = vcpu->kvm->arch.guest_origin;
vcpu->arch.sie_block->ecb = 2; vcpu->arch.sie_block->ecb = 2;
vcpu->arch.sie_block->eca = 0xC1002001U; 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); hrtimer_init(&vcpu->arch.ckc_timer, CLOCK_REALTIME, HRTIMER_MODE_ABS);
tasklet_init(&vcpu->arch.tasklet, kvm_s390_tasklet, tasklet_init(&vcpu->arch.tasklet, kvm_s390_tasklet,
(unsigned long) vcpu); (unsigned long) vcpu);
...@@ -739,11 +742,29 @@ gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn) ...@@ -739,11 +742,29 @@ gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn)
static int __init kvm_s390_init(void) 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) static void __exit kvm_s390_exit(void)
{ {
free_page((unsigned long) facilities);
kvm_exit(); kvm_exit();
} }
......
...@@ -158,7 +158,7 @@ static int handle_stfl(struct kvm_vcpu *vcpu) ...@@ -158,7 +158,7 @@ static int handle_stfl(struct kvm_vcpu *vcpu)
vcpu->stat.instruction_stfl++; vcpu->stat.instruction_stfl++;
/* only pass the facility bits, which we can handle */ /* 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), rc = copy_to_guest(vcpu, offsetof(struct _lowcore, stfl_fac_list),
&facility_list, sizeof(facility_list)); &facility_list, sizeof(facility_list));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment