summaryrefslogtreecommitdiffstats
path: root/arch/s390/kvm
diff options
context:
space:
mode:
Diffstat (limited to 'arch/s390/kvm')
-rw-r--r--arch/s390/kvm/intercept.c2
-rw-r--r--arch/s390/kvm/interrupt.c1
-rw-r--r--arch/s390/kvm/kvm-s390.c72
-rw-r--r--arch/s390/kvm/kvm-s390.h4
-rw-r--r--arch/s390/kvm/priv.c1
-rw-r--r--arch/s390/kvm/sie64a.S75
-rw-r--r--arch/s390/kvm/sigp.c3
7 files changed, 93 insertions, 65 deletions
diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c
index 3ddc30895e3..f7b6df45d8b 100644
--- a/arch/s390/kvm/intercept.c
+++ b/arch/s390/kvm/intercept.c
@@ -135,7 +135,7 @@ static int handle_stop(struct kvm_vcpu *vcpu)
spin_lock_bh(&vcpu->arch.local_int.lock);
if (vcpu->arch.local_int.action_bits & ACTION_STORE_ON_STOP) {
vcpu->arch.local_int.action_bits &= ~ACTION_STORE_ON_STOP;
- rc = __kvm_s390_vcpu_store_status(vcpu,
+ rc = kvm_s390_vcpu_store_status(vcpu,
KVM_S390_STORE_STATUS_NOADDR);
if (rc >= 0)
rc = -EOPNOTSUPP;
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
index 834774d8d5f..35c21bf910c 100644
--- a/arch/s390/kvm/interrupt.c
+++ b/arch/s390/kvm/interrupt.c
@@ -14,6 +14,7 @@
#include <linux/kvm_host.h>
#include <linux/hrtimer.h>
#include <linux/signal.h>
+#include <linux/slab.h>
#include <asm/asm-offsets.h>
#include <asm/uaccess.h>
#include "kvm-s390.h"
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 49292869a5c..4fe68650535 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -207,6 +207,7 @@ out_nokvm:
void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
{
VCPU_EVENT(vcpu, 3, "%s", "free cpu");
+ clear_bit(63 - vcpu->vcpu_id, (unsigned long *) &vcpu->kvm->arch.sca->mcn);
if (vcpu->kvm->arch.sca->cpu[vcpu->vcpu_id].sda ==
(__u64) vcpu->arch.sie_block)
vcpu->kvm->arch.sca->cpu[vcpu->vcpu_id].sda = 0;
@@ -296,7 +297,7 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
{
atomic_set(&vcpu->arch.sie_block->cpuflags, CPUSTAT_ZARCH);
set_bit(KVM_REQ_MMU_RELOAD, &vcpu->requests);
- vcpu->arch.sie_block->ecb = 2;
+ vcpu->arch.sie_block->ecb = 6;
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);
@@ -329,6 +330,7 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
kvm->arch.sca->cpu[id].sda = (__u64) vcpu->arch.sie_block;
vcpu->arch.sie_block->scaoh = (__u32)(((__u64)kvm->arch.sca) >> 32);
vcpu->arch.sie_block->scaol = (__u32)(__u64)kvm->arch.sca;
+ set_bit(63 - id, (unsigned long *) &kvm->arch.sca->mcn);
spin_lock_init(&vcpu->arch.local_int.lock);
INIT_LIST_HEAD(&vcpu->arch.local_int.list);
@@ -341,11 +343,13 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
rc = kvm_vcpu_init(vcpu, kvm, id);
if (rc)
- goto out_free_cpu;
+ goto out_free_sie_block;
VM_EVENT(kvm, 3, "create cpu %d at %p, sie block at %p", id, vcpu,
vcpu->arch.sie_block);
return vcpu;
+out_free_sie_block:
+ free_page((unsigned long)(vcpu->arch.sie_block));
out_free_cpu:
kfree(vcpu);
out_nomem:
@@ -361,63 +365,49 @@ int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu)
static int kvm_arch_vcpu_ioctl_initial_reset(struct kvm_vcpu *vcpu)
{
- vcpu_load(vcpu);
kvm_s390_vcpu_initial_reset(vcpu);
- vcpu_put(vcpu);
return 0;
}
int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
{
- vcpu_load(vcpu);
memcpy(&vcpu->arch.guest_gprs, &regs->gprs, sizeof(regs->gprs));
- vcpu_put(vcpu);
return 0;
}
int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
{
- vcpu_load(vcpu);
memcpy(&regs->gprs, &vcpu->arch.guest_gprs, sizeof(regs->gprs));
- vcpu_put(vcpu);
return 0;
}
int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
struct kvm_sregs *sregs)
{
- vcpu_load(vcpu);
memcpy(&vcpu->arch.guest_acrs, &sregs->acrs, sizeof(sregs->acrs));
memcpy(&vcpu->arch.sie_block->gcr, &sregs->crs, sizeof(sregs->crs));
- vcpu_put(vcpu);
return 0;
}
int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
struct kvm_sregs *sregs)
{
- vcpu_load(vcpu);
memcpy(&sregs->acrs, &vcpu->arch.guest_acrs, sizeof(sregs->acrs));
memcpy(&sregs->crs, &vcpu->arch.sie_block->gcr, sizeof(sregs->crs));
- vcpu_put(vcpu);
return 0;
}
int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
{
- vcpu_load(vcpu);
memcpy(&vcpu->arch.guest_fpregs.fprs, &fpu->fprs, sizeof(fpu->fprs));
vcpu->arch.guest_fpregs.fpc = fpu->fpc;
- vcpu_put(vcpu);
return 0;
}
int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
{
- vcpu_load(vcpu);
memcpy(&fpu->fprs, &vcpu->arch.guest_fpregs.fprs, sizeof(fpu->fprs));
fpu->fpc = vcpu->arch.guest_fpregs.fpc;
- vcpu_put(vcpu);
return 0;
}
@@ -425,14 +415,12 @@ static int kvm_arch_vcpu_ioctl_set_initial_psw(struct kvm_vcpu *vcpu, psw_t psw)
{
int rc = 0;
- vcpu_load(vcpu);
if (atomic_read(&vcpu->arch.sie_block->cpuflags) & CPUSTAT_RUNNING)
rc = -EBUSY;
else {
vcpu->run->psw_mask = psw.mask;
vcpu->run->psw_addr = psw.addr;
}
- vcpu_put(vcpu);
return rc;
}
@@ -496,8 +484,6 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
int rc;
sigset_t sigsaved;
- vcpu_load(vcpu);
-
rerun_vcpu:
if (vcpu->requests)
if (test_and_clear_bit(KVM_REQ_MMU_RELOAD, &vcpu->requests))
@@ -566,8 +552,6 @@ rerun_vcpu:
if (vcpu->sigset_active)
sigprocmask(SIG_SETMASK, &sigsaved, NULL);
- vcpu_put(vcpu);
-
vcpu->stat.exit_userspace++;
return rc;
}
@@ -587,7 +571,7 @@ static int __guestcopy(struct kvm_vcpu *vcpu, u64 guestdest, const void *from,
* KVM_S390_STORE_STATUS_NOADDR: -> 0x1200 on 64 bit
* KVM_S390_STORE_STATUS_PREFIXED: -> prefix
*/
-int __kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu, unsigned long addr)
+int kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu, unsigned long addr)
{
const unsigned char archmode = 1;
int prefix;
@@ -649,45 +633,42 @@ int __kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu, unsigned long addr)
return 0;
}
-static int kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu, unsigned long addr)
-{
- int rc;
-
- vcpu_load(vcpu);
- rc = __kvm_s390_vcpu_store_status(vcpu, addr);
- vcpu_put(vcpu);
- return rc;
-}
-
long kvm_arch_vcpu_ioctl(struct file *filp,
unsigned int ioctl, unsigned long arg)
{
struct kvm_vcpu *vcpu = filp->private_data;
void __user *argp = (void __user *)arg;
+ long r;
switch (ioctl) {
case KVM_S390_INTERRUPT: {
struct kvm_s390_interrupt s390int;
+ r = -EFAULT;
if (copy_from_user(&s390int, argp, sizeof(s390int)))
- return -EFAULT;
- return kvm_s390_inject_vcpu(vcpu, &s390int);
+ break;
+ r = kvm_s390_inject_vcpu(vcpu, &s390int);
+ break;
}
case KVM_S390_STORE_STATUS:
- return kvm_s390_vcpu_store_status(vcpu, arg);
+ r = kvm_s390_vcpu_store_status(vcpu, arg);
+ break;
case KVM_S390_SET_INITIAL_PSW: {
psw_t psw;
+ r = -EFAULT;
if (copy_from_user(&psw, argp, sizeof(psw)))
- return -EFAULT;
- return kvm_arch_vcpu_ioctl_set_initial_psw(vcpu, psw);
+ break;
+ r = kvm_arch_vcpu_ioctl_set_initial_psw(vcpu, psw);
+ break;
}
case KVM_S390_INITIAL_RESET:
- return kvm_arch_vcpu_ioctl_initial_reset(vcpu);
+ r = kvm_arch_vcpu_ioctl_initial_reset(vcpu);
+ break;
default:
- ;
+ r = -EINVAL;
}
- return -EINVAL;
+ return r;
}
/* Section: memory related */
@@ -742,15 +723,10 @@ void kvm_arch_flush_shadow(struct kvm *kvm)
{
}
-gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn)
-{
- return gfn;
-}
-
static int __init kvm_s390_init(void)
{
int ret;
- ret = kvm_init(NULL, sizeof(struct kvm_vcpu), THIS_MODULE);
+ ret = kvm_init(NULL, sizeof(struct kvm_vcpu), 0, THIS_MODULE);
if (ret)
return ret;
@@ -759,7 +735,7 @@ static int __init kvm_s390_init(void)
* 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);
+ facilities = (unsigned long long *) get_zeroed_page(GFP_KERNEL|GFP_DMA);
if (!facilities) {
kvm_exit();
return -ENOMEM;
diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h
index 60f09ab3672..a7b7586626d 100644
--- a/arch/s390/kvm/kvm-s390.h
+++ b/arch/s390/kvm/kvm-s390.h
@@ -72,7 +72,7 @@ static inline void kvm_s390_vcpu_set_mem(struct kvm_vcpu *vcpu)
struct kvm_memslots *memslots;
idx = srcu_read_lock(&vcpu->kvm->srcu);
- memslots = rcu_dereference(vcpu->kvm->memslots);
+ memslots = kvm_memslots(vcpu->kvm);
mem = &memslots->memslots[0];
@@ -92,7 +92,7 @@ int kvm_s390_handle_b2(struct kvm_vcpu *vcpu);
int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu);
/* implemented in kvm-s390.c */
-int __kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu,
+int kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu,
unsigned long addr);
/* implemented in diag.c */
int kvm_s390_handle_diag(struct kvm_vcpu *vcpu);
diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c
index 28c55677eb3..44205507717 100644
--- a/arch/s390/kvm/priv.c
+++ b/arch/s390/kvm/priv.c
@@ -12,6 +12,7 @@
*/
#include <linux/kvm.h>
+#include <linux/gfp.h>
#include <linux/errno.h>
#include <asm/current.h>
#include <asm/debug.h>
diff --git a/arch/s390/kvm/sie64a.S b/arch/s390/kvm/sie64a.S
index 934fd6a885f..7e9d30d567b 100644
--- a/arch/s390/kvm/sie64a.S
+++ b/arch/s390/kvm/sie64a.S
@@ -1,20 +1,58 @@
/*
* sie64a.S - low level sie call
*
- * Copyright IBM Corp. 2008
+ * Copyright IBM Corp. 2008,2010
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License (version 2 only)
* as published by the Free Software Foundation.
*
* Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
+ * Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
*/
#include <linux/errno.h>
#include <asm/asm-offsets.h>
+#include <asm/setup.h>
+#include <asm/asm-offsets.h>
+#include <asm/ptrace.h>
+#include <asm/thread_info.h>
+
+_TIF_EXIT_SIE = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING)
+
+/*
+ * offsets into stackframe
+ * SP_ = offsets into stack sie64 is called with
+ * SPI_ = offsets into irq stack
+ */
+SP_GREGS = __SF_EMPTY
+SP_HOOK = __SF_EMPTY+8
+SP_GPP = __SF_EMPTY+16
+SPI_PSW = STACK_FRAME_OVERHEAD + __PT_PSW
+
-SP_R5 = 5 * 8 # offset into stackframe
-SP_R6 = 6 * 8
+ .macro SPP newpp
+ tm __LC_MACHINE_FLAGS+6,0x20 # MACHINE_FLAG_SPP
+ jz 0f
+ .insn s,0xb2800000,\newpp
+0:
+ .endm
+
+sie_irq_handler:
+ SPP __LC_CMF_HPP # set host id
+ larl %r2,sie_inst
+ clg %r2,SPI_PSW+8(0,%r15) # intercepted sie
+ jne 1f
+ xc __LC_SIE_HOOK(8),__LC_SIE_HOOK
+ lg %r2,__LC_THREAD_INFO # pointer thread_info struct
+ tm __TI_flags+7(%r2),_TIF_EXIT_SIE
+ jz 0f
+ larl %r2,sie_exit # work pending, leave sie
+ stg %r2,__LC_RETURN_PSW+8
+ br %r14
+0: larl %r2,sie_reenter # re-enter with guest id
+ stg %r2,__LC_RETURN_PSW+8
+1: br %r14
/*
* sie64a calling convention:
@@ -23,23 +61,34 @@ SP_R6 = 6 * 8
*/
.globl sie64a
sie64a:
- lgr %r5,%r3
- stmg %r5,%r14,SP_R5(%r15) # save register on entry
- lgr %r14,%r2 # pointer to sie control block
- lmg %r0,%r13,0(%r3) # load guest gprs 0-13
+ stg %r3,SP_GREGS(%r15) # save guest register save area
+ stmg %r6,%r14,__SF_GPRS(%r15) # save registers on entry
+ lgr %r14,%r2 # pointer to sie control block
+ larl %r5,sie_irq_handler
+ stg %r2,SP_GPP(%r15)
+ stg %r5,SP_HOOK(%r15) # save hook target
+ lmg %r0,%r13,0(%r3) # load guest gprs 0-13
+sie_reenter:
+ mvc __LC_SIE_HOOK(8),SP_HOOK(%r15)
+ SPP SP_GPP(%r15) # set guest id
sie_inst:
sie 0(%r14)
- lg %r14,SP_R5(%r15)
- stmg %r0,%r13,0(%r14) # save guest gprs 0-13
+ xc __LC_SIE_HOOK(8),__LC_SIE_HOOK
+ SPP __LC_CMF_HPP # set host id
+sie_exit:
+ lg %r14,SP_GREGS(%r15)
+ stmg %r0,%r13,0(%r14) # save guest gprs 0-13
lghi %r2,0
- lmg %r6,%r14,SP_R6(%r15)
+ lmg %r6,%r14,__SF_GPRS(%r15)
br %r14
sie_err:
- lg %r14,SP_R5(%r15)
- stmg %r0,%r13,0(%r14) # save guest gprs 0-13
+ xc __LC_SIE_HOOK(8),__LC_SIE_HOOK
+ SPP __LC_CMF_HPP # set host id
+ lg %r14,SP_GREGS(%r15)
+ stmg %r0,%r13,0(%r14) # save guest gprs 0-13
lghi %r2,-EFAULT
- lmg %r6,%r14,SP_R6(%r15)
+ lmg %r6,%r14,__SF_GPRS(%r15)
br %r14
.section __ex_table,"a"
diff --git a/arch/s390/kvm/sigp.c b/arch/s390/kvm/sigp.c
index 241a48459b6..702276f5e2f 100644
--- a/arch/s390/kvm/sigp.c
+++ b/arch/s390/kvm/sigp.c
@@ -14,6 +14,7 @@
#include <linux/kvm.h>
#include <linux/kvm_host.h>
+#include <linux/slab.h>
#include "gaccess.h"
#include "kvm-s390.h"
@@ -112,7 +113,7 @@ static int __inject_sigp_stop(struct kvm_s390_local_interrupt *li, int action)
{
struct kvm_s390_interrupt_info *inti;
- inti = kzalloc(sizeof(*inti), GFP_KERNEL);
+ inti = kzalloc(sizeof(*inti), GFP_ATOMIC);
if (!inti)
return -ENOMEM;
inti->type = KVM_S390_SIGP_STOP;