diff options
Diffstat (limited to 'arch/s390/kvm')
-rw-r--r-- | arch/s390/kvm/Kconfig | 1 | ||||
-rw-r--r-- | arch/s390/kvm/diag.c | 4 | ||||
-rw-r--r-- | arch/s390/kvm/intercept.c | 18 | ||||
-rw-r--r-- | arch/s390/kvm/interrupt.c | 13 | ||||
-rw-r--r-- | arch/s390/kvm/kvm-s390.c | 57 | ||||
-rw-r--r-- | arch/s390/kvm/kvm-s390.h | 10 | ||||
-rw-r--r-- | arch/s390/kvm/priv.c | 3 | ||||
-rw-r--r-- | arch/s390/kvm/sie64a.S | 75 | ||||
-rw-r--r-- | arch/s390/kvm/sigp.c | 7 |
9 files changed, 128 insertions, 60 deletions
diff --git a/arch/s390/kvm/Kconfig b/arch/s390/kvm/Kconfig index 6ee55ae84ce2..a7251580891c 100644 --- a/arch/s390/kvm/Kconfig +++ b/arch/s390/kvm/Kconfig @@ -35,6 +35,7 @@ config KVM # OK, it's a little counter-intuitive to do this, but it puts it neatly under # the virtualization menu. +source drivers/vhost/Kconfig source drivers/virtio/Kconfig endif # VIRTUALIZATION diff --git a/arch/s390/kvm/diag.c b/arch/s390/kvm/diag.c index 8300309698fa..9e4c84187cf5 100644 --- a/arch/s390/kvm/diag.c +++ b/arch/s390/kvm/diag.c @@ -39,7 +39,7 @@ static int __diag_ipl_functions(struct kvm_vcpu *vcpu) vcpu->run->s390_reset_flags = 0; break; default: - return -ENOTSUPP; + return -EOPNOTSUPP; } atomic_clear_mask(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags); @@ -62,6 +62,6 @@ int kvm_s390_handle_diag(struct kvm_vcpu *vcpu) case 0x308: return __diag_ipl_functions(vcpu); default: - return -ENOTSUPP; + return -EOPNOTSUPP; } } diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c index b40096494e46..3ddc30895e31 100644 --- a/arch/s390/kvm/intercept.c +++ b/arch/s390/kvm/intercept.c @@ -32,7 +32,7 @@ static int handle_lctlg(struct kvm_vcpu *vcpu) vcpu->stat.instruction_lctlg++; if ((vcpu->arch.sie_block->ipb & 0xff) != 0x2f) - return -ENOTSUPP; + return -EOPNOTSUPP; useraddr = disp2; if (base2) @@ -138,7 +138,7 @@ static int handle_stop(struct kvm_vcpu *vcpu) rc = __kvm_s390_vcpu_store_status(vcpu, KVM_S390_STORE_STATUS_NOADDR); if (rc >= 0) - rc = -ENOTSUPP; + rc = -EOPNOTSUPP; } if (vcpu->arch.local_int.action_bits & ACTION_RELOADVCPU_ON_STOP) { @@ -150,7 +150,7 @@ static int handle_stop(struct kvm_vcpu *vcpu) if (vcpu->arch.local_int.action_bits & ACTION_STOP_ON_STOP) { vcpu->arch.local_int.action_bits &= ~ACTION_STOP_ON_STOP; VCPU_EVENT(vcpu, 3, "%s", "cpu stopped"); - rc = -ENOTSUPP; + rc = -EOPNOTSUPP; } spin_unlock_bh(&vcpu->arch.local_int.lock); @@ -171,9 +171,9 @@ static int handle_validity(struct kvm_vcpu *vcpu) 2*PAGE_SIZE); if (rc) /* user will receive sigsegv, exit to user */ - rc = -ENOTSUPP; + rc = -EOPNOTSUPP; } else - rc = -ENOTSUPP; + rc = -EOPNOTSUPP; if (rc) VCPU_EVENT(vcpu, 2, "unhandled validity intercept code %d", @@ -189,7 +189,7 @@ static int handle_instruction(struct kvm_vcpu *vcpu) handler = instruction_handlers[vcpu->arch.sie_block->ipa >> 8]; if (handler) return handler(vcpu); - return -ENOTSUPP; + return -EOPNOTSUPP; } static int handle_prog(struct kvm_vcpu *vcpu) @@ -206,7 +206,7 @@ static int handle_instruction_and_prog(struct kvm_vcpu *vcpu) rc = handle_instruction(vcpu); rc2 = handle_prog(vcpu); - if (rc == -ENOTSUPP) + if (rc == -EOPNOTSUPP) vcpu->arch.sie_block->icptcode = 0x04; if (rc) return rc; @@ -231,9 +231,9 @@ int kvm_handle_sie_intercept(struct kvm_vcpu *vcpu) u8 code = vcpu->arch.sie_block->icptcode; if (code & 3 || (code >> 2) >= ARRAY_SIZE(intercept_funcs)) - return -ENOTSUPP; + return -EOPNOTSUPP; func = intercept_funcs[code >> 2]; if (func) return func(vcpu); - return -ENOTSUPP; + return -EOPNOTSUPP; } diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c index 43486c2408e1..35c21bf910c5 100644 --- a/arch/s390/kvm/interrupt.c +++ b/arch/s390/kvm/interrupt.c @@ -10,12 +10,13 @@ * Author(s): Carsten Otte <cotte@de.ibm.com> */ -#include <asm/lowcore.h> -#include <asm/uaccess.h> -#include <linux/hrtimer.h> #include <linux/interrupt.h> #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" #include "gaccess.h" @@ -187,8 +188,8 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu, if (rc == -EFAULT) exception = 1; - rc = put_guest_u64(vcpu, __LC_PFAULT_INTPARM, - inti->ext.ext_params2); + rc = put_guest_u64(vcpu, __LC_EXT_PARAMS2, + inti->ext.ext_params2); if (rc == -EFAULT) exception = 1; break; @@ -342,7 +343,7 @@ int kvm_s390_handle_wait(struct kvm_vcpu *vcpu) if (psw_interrupts_disabled(vcpu)) { VCPU_EVENT(vcpu, 3, "%s", "disabled wait"); __unset_cpu_idle(vcpu); - return -ENOTSUPP; /* disabled wait */ + return -EOPNOTSUPP; /* disabled wait */ } if (psw_extint_disabled(vcpu) || diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index f8bcaefd7d34..ae3705816878 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -23,6 +23,7 @@ #include <linux/module.h> #include <linux/slab.h> #include <linux/timer.h> +#include <asm/asm-offsets.h> #include <asm/lowcore.h> #include <asm/pgtable.h> #include <asm/nmi.h> @@ -241,6 +242,7 @@ void kvm_arch_destroy_vm(struct kvm *kvm) kvm_free_physmem(kvm); free_page((unsigned long)(kvm->arch.sca)); debug_unregister(kvm->arch.dbf); + cleanup_srcu_struct(&kvm->srcu); kfree(kvm); } @@ -339,11 +341,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: @@ -543,7 +547,7 @@ rerun_vcpu: rc = -EINTR; } - if (rc == -ENOTSUPP) { + if (rc == -EOPNOTSUPP) { /* intercept cannot be handled in-kernel, prepare kvm-run */ kvm_run->exit_reason = KVM_EXIT_S390_SIEIC; kvm_run->s390_sieic.icptcode = vcpu->arch.sie_block->icptcode; @@ -603,45 +607,45 @@ int __kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu, unsigned long addr) } else prefix = 0; - if (__guestcopy(vcpu, addr + offsetof(struct save_area_s390x, fp_regs), + if (__guestcopy(vcpu, addr + offsetof(struct save_area, fp_regs), vcpu->arch.guest_fpregs.fprs, 128, prefix)) return -EFAULT; - if (__guestcopy(vcpu, addr + offsetof(struct save_area_s390x, gp_regs), + if (__guestcopy(vcpu, addr + offsetof(struct save_area, gp_regs), vcpu->arch.guest_gprs, 128, prefix)) return -EFAULT; - if (__guestcopy(vcpu, addr + offsetof(struct save_area_s390x, psw), + if (__guestcopy(vcpu, addr + offsetof(struct save_area, psw), &vcpu->arch.sie_block->gpsw, 16, prefix)) return -EFAULT; - if (__guestcopy(vcpu, addr + offsetof(struct save_area_s390x, pref_reg), + if (__guestcopy(vcpu, addr + offsetof(struct save_area, pref_reg), &vcpu->arch.sie_block->prefix, 4, prefix)) return -EFAULT; if (__guestcopy(vcpu, - addr + offsetof(struct save_area_s390x, fp_ctrl_reg), + addr + offsetof(struct save_area, fp_ctrl_reg), &vcpu->arch.guest_fpregs.fpc, 4, prefix)) return -EFAULT; - if (__guestcopy(vcpu, addr + offsetof(struct save_area_s390x, tod_reg), + if (__guestcopy(vcpu, addr + offsetof(struct save_area, tod_reg), &vcpu->arch.sie_block->todpr, 4, prefix)) return -EFAULT; - if (__guestcopy(vcpu, addr + offsetof(struct save_area_s390x, timer), + if (__guestcopy(vcpu, addr + offsetof(struct save_area, timer), &vcpu->arch.sie_block->cputm, 8, prefix)) return -EFAULT; - if (__guestcopy(vcpu, addr + offsetof(struct save_area_s390x, clk_cmp), + if (__guestcopy(vcpu, addr + offsetof(struct save_area, clk_cmp), &vcpu->arch.sie_block->ckc, 8, prefix)) return -EFAULT; - if (__guestcopy(vcpu, addr + offsetof(struct save_area_s390x, acc_regs), + if (__guestcopy(vcpu, addr + offsetof(struct save_area, acc_regs), &vcpu->arch.guest_acrs, 64, prefix)) return -EFAULT; if (__guestcopy(vcpu, - addr + offsetof(struct save_area_s390x, ctrl_regs), + addr + offsetof(struct save_area, ctrl_regs), &vcpu->arch.sie_block->gcr, 128, prefix)) return -EFAULT; return 0; @@ -689,14 +693,12 @@ long kvm_arch_vcpu_ioctl(struct file *filp, } /* Section: memory related */ -int kvm_arch_set_memory_region(struct kvm *kvm, - struct kvm_userspace_memory_region *mem, - struct kvm_memory_slot old, - int user_alloc) +int kvm_arch_prepare_memory_region(struct kvm *kvm, + struct kvm_memory_slot *memslot, + struct kvm_memory_slot old, + struct kvm_userspace_memory_region *mem, + int user_alloc) { - int i; - struct kvm_vcpu *vcpu; - /* A few sanity checks. We can have exactly one memory slot which has to start at guest virtual zero and which has to be located at a page boundary in userland and which has to end at a page boundary. @@ -719,14 +721,23 @@ int kvm_arch_set_memory_region(struct kvm *kvm, if (!user_alloc) return -EINVAL; + return 0; +} + +void kvm_arch_commit_memory_region(struct kvm *kvm, + struct kvm_userspace_memory_region *mem, + struct kvm_memory_slot old, + int user_alloc) +{ + int i; + struct kvm_vcpu *vcpu; + /* request update of sie control block for all available vcpus */ kvm_for_each_vcpu(i, vcpu, kvm) { if (test_and_set_bit(KVM_REQ_MMU_RELOAD, &vcpu->requests)) continue; kvm_s390_inject_sigp_stop(vcpu, ACTION_RELOADVCPU_ON_STOP); } - - return 0; } void kvm_arch_flush_shadow(struct kvm *kvm) @@ -741,7 +752,7 @@ gfn_t unalias_gfn(struct kvm *kvm, gfn_t 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; @@ -750,7 +761,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 06cce8285ba0..cfa9d1777457 100644 --- a/arch/s390/kvm/kvm-s390.h +++ b/arch/s390/kvm/kvm-s390.h @@ -67,10 +67,14 @@ static inline long kvm_s390_vcpu_get_memsize(struct kvm_vcpu *vcpu) static inline void kvm_s390_vcpu_set_mem(struct kvm_vcpu *vcpu) { + int idx; struct kvm_memory_slot *mem; + struct kvm_memslots *memslots; - down_read(&vcpu->kvm->slots_lock); - mem = &vcpu->kvm->memslots[0]; + idx = srcu_read_lock(&vcpu->kvm->srcu); + memslots = kvm_memslots(vcpu->kvm); + + mem = &memslots->memslots[0]; vcpu->arch.sie_block->gmsor = mem->userspace_addr; vcpu->arch.sie_block->gmslm = @@ -78,7 +82,7 @@ static inline void kvm_s390_vcpu_set_mem(struct kvm_vcpu *vcpu) (mem->npages << PAGE_SHIFT) + VIRTIODESCSPACE - 1ul; - up_read(&vcpu->kvm->slots_lock); + srcu_read_unlock(&vcpu->kvm->srcu, idx); } /* implemented in priv.c */ diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c index d426aac8095d..44205507717c 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> @@ -323,5 +324,5 @@ int kvm_s390_handle_b2(struct kvm_vcpu *vcpu) else return handler(vcpu); } - return -ENOTSUPP; + return -EOPNOTSUPP; } diff --git a/arch/s390/kvm/sie64a.S b/arch/s390/kvm/sie64a.S index 934fd6a885f6..7e9d30d567b0 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 15ee1111de58..702276f5e2fa 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; @@ -172,7 +173,7 @@ static int __sigp_set_arch(struct kvm_vcpu *vcpu, u32 parameter) rc = 0; /* order accepted */ break; default: - rc = -ENOTSUPP; + rc = -EOPNOTSUPP; } return rc; } @@ -293,7 +294,7 @@ int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu) vcpu->stat.instruction_sigp_restart++; /* user space must know about restart */ default: - return -ENOTSUPP; + return -EOPNOTSUPP; } if (rc < 0) |