diff options
Diffstat (limited to 'ANDROID_3.4.5/arch/s390/kvm')
-rw-r--r-- | ANDROID_3.4.5/arch/s390/kvm/Kconfig | 50 | ||||
-rw-r--r-- | ANDROID_3.4.5/arch/s390/kvm/Makefile | 14 | ||||
-rw-r--r-- | ANDROID_3.4.5/arch/s390/kvm/diag.c | 97 | ||||
-rw-r--r-- | ANDROID_3.4.5/arch/s390/kvm/gaccess.h | 386 | ||||
-rw-r--r-- | ANDROID_3.4.5/arch/s390/kvm/intercept.c | 265 | ||||
-rw-r--r-- | ANDROID_3.4.5/arch/s390/kvm/interrupt.c | 641 | ||||
-rw-r--r-- | ANDROID_3.4.5/arch/s390/kvm/kvm-s390.c | 908 | ||||
-rw-r--r-- | ANDROID_3.4.5/arch/s390/kvm/kvm-s390.h | 92 | ||||
-rw-r--r-- | ANDROID_3.4.5/arch/s390/kvm/priv.c | 382 | ||||
-rw-r--r-- | ANDROID_3.4.5/arch/s390/kvm/sigp.c | 421 |
10 files changed, 0 insertions, 3256 deletions
diff --git a/ANDROID_3.4.5/arch/s390/kvm/Kconfig b/ANDROID_3.4.5/arch/s390/kvm/Kconfig deleted file mode 100644 index 78eb9847..00000000 --- a/ANDROID_3.4.5/arch/s390/kvm/Kconfig +++ /dev/null @@ -1,50 +0,0 @@ -# -# KVM configuration -# -source "virt/kvm/Kconfig" - -menuconfig VIRTUALIZATION - def_bool y - prompt "Virtualization" - ---help--- - Say Y here to get to see options for using your Linux host to run other - operating systems inside virtual machines (guests). - This option alone does not add any kernel code. - - If you say N, all options in this submenu will be skipped and disabled. - -if VIRTUALIZATION - -config KVM - def_tristate y - prompt "Kernel-based Virtual Machine (KVM) support" - depends on HAVE_KVM && EXPERIMENTAL - select PREEMPT_NOTIFIERS - select ANON_INODES - ---help--- - Support hosting paravirtualized guest machines using the SIE - virtualization capability on the mainframe. This should work - on any 64bit machine. - - This module provides access to the hardware capabilities through - a character device node named /dev/kvm. - - To compile this as a module, choose M here: the module - will be called kvm. - - If unsure, say N. - -config KVM_S390_UCONTROL - bool "Userspace controlled virtual machines" - depends on KVM - ---help--- - Allow CAP_SYS_ADMIN users to create KVM virtual machines that are - controlled by userspace. - - If unsure, say N. - -# OK, it's a little counter-intuitive to do this, but it puts it neatly under -# the virtualization menu. -source drivers/vhost/Kconfig - -endif # VIRTUALIZATION diff --git a/ANDROID_3.4.5/arch/s390/kvm/Makefile b/ANDROID_3.4.5/arch/s390/kvm/Makefile deleted file mode 100644 index 3975722b..00000000 --- a/ANDROID_3.4.5/arch/s390/kvm/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -# Makefile for kernel virtual machines on s390 -# -# Copyright IBM Corp. 2008 -# -# 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. - -common-objs = $(addprefix ../../../virt/kvm/, kvm_main.o) - -ccflags-y := -Ivirt/kvm -Iarch/s390/kvm - -kvm-objs := $(common-objs) kvm-s390.o intercept.o interrupt.o priv.o sigp.o diag.o -obj-$(CONFIG_KVM) += kvm.o diff --git a/ANDROID_3.4.5/arch/s390/kvm/diag.c b/ANDROID_3.4.5/arch/s390/kvm/diag.c deleted file mode 100644 index a353f0ea..00000000 --- a/ANDROID_3.4.5/arch/s390/kvm/diag.c +++ /dev/null @@ -1,97 +0,0 @@ -/* - * diag.c - handling diagnose instructions - * - * Copyright IBM Corp. 2008,2011 - * - * 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): Carsten Otte <cotte@de.ibm.com> - * Christian Borntraeger <borntraeger@de.ibm.com> - */ - -#include <linux/kvm.h> -#include <linux/kvm_host.h> -#include "kvm-s390.h" - -static int diag_release_pages(struct kvm_vcpu *vcpu) -{ - unsigned long start, end; - unsigned long prefix = vcpu->arch.sie_block->prefix; - - start = vcpu->run->s.regs.gprs[(vcpu->arch.sie_block->ipa & 0xf0) >> 4]; - end = vcpu->run->s.regs.gprs[vcpu->arch.sie_block->ipa & 0xf] + 4096; - - if (start & ~PAGE_MASK || end & ~PAGE_MASK || start > end - || start < 2 * PAGE_SIZE) - return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); - - VCPU_EVENT(vcpu, 5, "diag release pages %lX %lX", start, end); - vcpu->stat.diagnose_10++; - - /* we checked for start > end above */ - if (end < prefix || start >= prefix + 2 * PAGE_SIZE) { - gmap_discard(start, end, vcpu->arch.gmap); - } else { - if (start < prefix) - gmap_discard(start, prefix, vcpu->arch.gmap); - if (end >= prefix) - gmap_discard(prefix + 2 * PAGE_SIZE, - end, vcpu->arch.gmap); - } - return 0; -} - -static int __diag_time_slice_end(struct kvm_vcpu *vcpu) -{ - VCPU_EVENT(vcpu, 5, "%s", "diag time slice end"); - vcpu->stat.diagnose_44++; - vcpu_put(vcpu); - yield(); - vcpu_load(vcpu); - return 0; -} - -static int __diag_ipl_functions(struct kvm_vcpu *vcpu) -{ - unsigned int reg = vcpu->arch.sie_block->ipa & 0xf; - unsigned long subcode = vcpu->run->s.regs.gprs[reg] & 0xffff; - - VCPU_EVENT(vcpu, 5, "diag ipl functions, subcode %lx", subcode); - switch (subcode) { - case 3: - vcpu->run->s390_reset_flags = KVM_S390_RESET_CLEAR; - break; - case 4: - vcpu->run->s390_reset_flags = 0; - break; - default: - return -EOPNOTSUPP; - } - - atomic_set_mask(CPUSTAT_STOPPED, &vcpu->arch.sie_block->cpuflags); - vcpu->run->s390_reset_flags |= KVM_S390_RESET_SUBSYSTEM; - vcpu->run->s390_reset_flags |= KVM_S390_RESET_IPL; - vcpu->run->s390_reset_flags |= KVM_S390_RESET_CPU_INIT; - vcpu->run->exit_reason = KVM_EXIT_S390_RESET; - VCPU_EVENT(vcpu, 3, "requesting userspace resets %llx", - vcpu->run->s390_reset_flags); - return -EREMOTE; -} - -int kvm_s390_handle_diag(struct kvm_vcpu *vcpu) -{ - int code = (vcpu->arch.sie_block->ipb & 0xfff0000) >> 16; - - switch (code) { - case 0x10: - return diag_release_pages(vcpu); - case 0x44: - return __diag_time_slice_end(vcpu); - case 0x308: - return __diag_ipl_functions(vcpu); - default: - return -EOPNOTSUPP; - } -} diff --git a/ANDROID_3.4.5/arch/s390/kvm/gaccess.h b/ANDROID_3.4.5/arch/s390/kvm/gaccess.h deleted file mode 100644 index c86f6ae4..00000000 --- a/ANDROID_3.4.5/arch/s390/kvm/gaccess.h +++ /dev/null @@ -1,386 +0,0 @@ -/* - * access.h - access guest memory - * - * Copyright IBM Corp. 2008,2009 - * - * 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): Carsten Otte <cotte@de.ibm.com> - */ - -#ifndef __KVM_S390_GACCESS_H -#define __KVM_S390_GACCESS_H - -#include <linux/compiler.h> -#include <linux/kvm_host.h> -#include <asm/uaccess.h> -#include "kvm-s390.h" - -static inline void __user *__guestaddr_to_user(struct kvm_vcpu *vcpu, - unsigned long guestaddr) -{ - unsigned long prefix = vcpu->arch.sie_block->prefix; - - if (guestaddr < 2 * PAGE_SIZE) - guestaddr += prefix; - else if ((guestaddr >= prefix) && (guestaddr < prefix + 2 * PAGE_SIZE)) - guestaddr -= prefix; - - return (void __user *) gmap_fault(guestaddr, vcpu->arch.gmap); -} - -static inline int get_guest_u64(struct kvm_vcpu *vcpu, unsigned long guestaddr, - u64 *result) -{ - void __user *uptr = __guestaddr_to_user(vcpu, guestaddr); - - BUG_ON(guestaddr & 7); - - if (IS_ERR((void __force *) uptr)) - return PTR_ERR((void __force *) uptr); - - return get_user(*result, (unsigned long __user *) uptr); -} - -static inline int get_guest_u32(struct kvm_vcpu *vcpu, unsigned long guestaddr, - u32 *result) -{ - void __user *uptr = __guestaddr_to_user(vcpu, guestaddr); - - BUG_ON(guestaddr & 3); - - if (IS_ERR((void __force *) uptr)) - return PTR_ERR((void __force *) uptr); - - return get_user(*result, (u32 __user *) uptr); -} - -static inline int get_guest_u16(struct kvm_vcpu *vcpu, unsigned long guestaddr, - u16 *result) -{ - void __user *uptr = __guestaddr_to_user(vcpu, guestaddr); - - BUG_ON(guestaddr & 1); - - if (IS_ERR(uptr)) - return PTR_ERR(uptr); - - return get_user(*result, (u16 __user *) uptr); -} - -static inline int get_guest_u8(struct kvm_vcpu *vcpu, unsigned long guestaddr, - u8 *result) -{ - void __user *uptr = __guestaddr_to_user(vcpu, guestaddr); - - if (IS_ERR((void __force *) uptr)) - return PTR_ERR((void __force *) uptr); - - return get_user(*result, (u8 __user *) uptr); -} - -static inline int put_guest_u64(struct kvm_vcpu *vcpu, unsigned long guestaddr, - u64 value) -{ - void __user *uptr = __guestaddr_to_user(vcpu, guestaddr); - - BUG_ON(guestaddr & 7); - - if (IS_ERR((void __force *) uptr)) - return PTR_ERR((void __force *) uptr); - - return put_user(value, (u64 __user *) uptr); -} - -static inline int put_guest_u32(struct kvm_vcpu *vcpu, unsigned long guestaddr, - u32 value) -{ - void __user *uptr = __guestaddr_to_user(vcpu, guestaddr); - - BUG_ON(guestaddr & 3); - - if (IS_ERR((void __force *) uptr)) - return PTR_ERR((void __force *) uptr); - - return put_user(value, (u32 __user *) uptr); -} - -static inline int put_guest_u16(struct kvm_vcpu *vcpu, unsigned long guestaddr, - u16 value) -{ - void __user *uptr = __guestaddr_to_user(vcpu, guestaddr); - - BUG_ON(guestaddr & 1); - - if (IS_ERR((void __force *) uptr)) - return PTR_ERR((void __force *) uptr); - - return put_user(value, (u16 __user *) uptr); -} - -static inline int put_guest_u8(struct kvm_vcpu *vcpu, unsigned long guestaddr, - u8 value) -{ - void __user *uptr = __guestaddr_to_user(vcpu, guestaddr); - - if (IS_ERR((void __force *) uptr)) - return PTR_ERR((void __force *) uptr); - - return put_user(value, (u8 __user *) uptr); -} - - -static inline int __copy_to_guest_slow(struct kvm_vcpu *vcpu, - unsigned long guestdest, - void *from, unsigned long n) -{ - int rc; - unsigned long i; - u8 *data = from; - - for (i = 0; i < n; i++) { - rc = put_guest_u8(vcpu, guestdest++, *(data++)); - if (rc < 0) - return rc; - } - return 0; -} - -static inline int __copy_to_guest_fast(struct kvm_vcpu *vcpu, - unsigned long guestdest, - void *from, unsigned long n) -{ - int r; - void __user *uptr; - unsigned long size; - - if (guestdest + n < guestdest) - return -EFAULT; - - /* simple case: all within one segment table entry? */ - if ((guestdest & PMD_MASK) == ((guestdest+n) & PMD_MASK)) { - uptr = (void __user *) gmap_fault(guestdest, vcpu->arch.gmap); - - if (IS_ERR((void __force *) uptr)) - return PTR_ERR((void __force *) uptr); - - r = copy_to_user(uptr, from, n); - - if (r) - r = -EFAULT; - - goto out; - } - - /* copy first segment */ - uptr = (void __user *)gmap_fault(guestdest, vcpu->arch.gmap); - - if (IS_ERR((void __force *) uptr)) - return PTR_ERR((void __force *) uptr); - - size = PMD_SIZE - (guestdest & ~PMD_MASK); - - r = copy_to_user(uptr, from, size); - - if (r) { - r = -EFAULT; - goto out; - } - from += size; - n -= size; - guestdest += size; - - /* copy full segments */ - while (n >= PMD_SIZE) { - uptr = (void __user *)gmap_fault(guestdest, vcpu->arch.gmap); - - if (IS_ERR((void __force *) uptr)) - return PTR_ERR((void __force *) uptr); - - r = copy_to_user(uptr, from, PMD_SIZE); - - if (r) { - r = -EFAULT; - goto out; - } - from += PMD_SIZE; - n -= PMD_SIZE; - guestdest += PMD_SIZE; - } - - /* copy the tail segment */ - if (n) { - uptr = (void __user *)gmap_fault(guestdest, vcpu->arch.gmap); - - if (IS_ERR((void __force *) uptr)) - return PTR_ERR((void __force *) uptr); - - r = copy_to_user(uptr, from, n); - - if (r) - r = -EFAULT; - } -out: - return r; -} - -static inline int copy_to_guest_absolute(struct kvm_vcpu *vcpu, - unsigned long guestdest, - void *from, unsigned long n) -{ - return __copy_to_guest_fast(vcpu, guestdest, from, n); -} - -static inline int copy_to_guest(struct kvm_vcpu *vcpu, unsigned long guestdest, - void *from, unsigned long n) -{ - unsigned long prefix = vcpu->arch.sie_block->prefix; - - if ((guestdest < 2 * PAGE_SIZE) && (guestdest + n > 2 * PAGE_SIZE)) - goto slowpath; - - if ((guestdest < prefix) && (guestdest + n > prefix)) - goto slowpath; - - if ((guestdest < prefix + 2 * PAGE_SIZE) - && (guestdest + n > prefix + 2 * PAGE_SIZE)) - goto slowpath; - - if (guestdest < 2 * PAGE_SIZE) - guestdest += prefix; - else if ((guestdest >= prefix) && (guestdest < prefix + 2 * PAGE_SIZE)) - guestdest -= prefix; - - return __copy_to_guest_fast(vcpu, guestdest, from, n); -slowpath: - return __copy_to_guest_slow(vcpu, guestdest, from, n); -} - -static inline int __copy_from_guest_slow(struct kvm_vcpu *vcpu, void *to, - unsigned long guestsrc, - unsigned long n) -{ - int rc; - unsigned long i; - u8 *data = to; - - for (i = 0; i < n; i++) { - rc = get_guest_u8(vcpu, guestsrc++, data++); - if (rc < 0) - return rc; - } - return 0; -} - -static inline int __copy_from_guest_fast(struct kvm_vcpu *vcpu, void *to, - unsigned long guestsrc, - unsigned long n) -{ - int r; - void __user *uptr; - unsigned long size; - - if (guestsrc + n < guestsrc) - return -EFAULT; - - /* simple case: all within one segment table entry? */ - if ((guestsrc & PMD_MASK) == ((guestsrc+n) & PMD_MASK)) { - uptr = (void __user *) gmap_fault(guestsrc, vcpu->arch.gmap); - - if (IS_ERR((void __force *) uptr)) - return PTR_ERR((void __force *) uptr); - - r = copy_from_user(to, uptr, n); - - if (r) - r = -EFAULT; - - goto out; - } - - /* copy first segment */ - uptr = (void __user *)gmap_fault(guestsrc, vcpu->arch.gmap); - - if (IS_ERR((void __force *) uptr)) - return PTR_ERR((void __force *) uptr); - - size = PMD_SIZE - (guestsrc & ~PMD_MASK); - - r = copy_from_user(to, uptr, size); - - if (r) { - r = -EFAULT; - goto out; - } - to += size; - n -= size; - guestsrc += size; - - /* copy full segments */ - while (n >= PMD_SIZE) { - uptr = (void __user *)gmap_fault(guestsrc, vcpu->arch.gmap); - - if (IS_ERR((void __force *) uptr)) - return PTR_ERR((void __force *) uptr); - - r = copy_from_user(to, uptr, PMD_SIZE); - - if (r) { - r = -EFAULT; - goto out; - } - to += PMD_SIZE; - n -= PMD_SIZE; - guestsrc += PMD_SIZE; - } - - /* copy the tail segment */ - if (n) { - uptr = (void __user *)gmap_fault(guestsrc, vcpu->arch.gmap); - - if (IS_ERR((void __force *) uptr)) - return PTR_ERR((void __force *) uptr); - - r = copy_from_user(to, uptr, n); - - if (r) - r = -EFAULT; - } -out: - return r; -} - -static inline int copy_from_guest_absolute(struct kvm_vcpu *vcpu, void *to, - unsigned long guestsrc, - unsigned long n) -{ - return __copy_from_guest_fast(vcpu, to, guestsrc, n); -} - -static inline int copy_from_guest(struct kvm_vcpu *vcpu, void *to, - unsigned long guestsrc, unsigned long n) -{ - unsigned long prefix = vcpu->arch.sie_block->prefix; - - if ((guestsrc < 2 * PAGE_SIZE) && (guestsrc + n > 2 * PAGE_SIZE)) - goto slowpath; - - if ((guestsrc < prefix) && (guestsrc + n > prefix)) - goto slowpath; - - if ((guestsrc < prefix + 2 * PAGE_SIZE) - && (guestsrc + n > prefix + 2 * PAGE_SIZE)) - goto slowpath; - - if (guestsrc < 2 * PAGE_SIZE) - guestsrc += prefix; - else if ((guestsrc >= prefix) && (guestsrc < prefix + 2 * PAGE_SIZE)) - guestsrc -= prefix; - - return __copy_from_guest_fast(vcpu, to, guestsrc, n); -slowpath: - return __copy_from_guest_slow(vcpu, to, guestsrc, n); -} -#endif diff --git a/ANDROID_3.4.5/arch/s390/kvm/intercept.c b/ANDROID_3.4.5/arch/s390/kvm/intercept.c deleted file mode 100644 index 36145657..00000000 --- a/ANDROID_3.4.5/arch/s390/kvm/intercept.c +++ /dev/null @@ -1,265 +0,0 @@ -/* - * intercept.c - in-kernel handling for sie intercepts - * - * Copyright IBM Corp. 2008,2009 - * - * 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): Carsten Otte <cotte@de.ibm.com> - * Christian Borntraeger <borntraeger@de.ibm.com> - */ - -#include <linux/kvm_host.h> -#include <linux/errno.h> -#include <linux/pagemap.h> - -#include <asm/kvm_host.h> - -#include "kvm-s390.h" -#include "gaccess.h" - -static int handle_lctlg(struct kvm_vcpu *vcpu) -{ - int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4; - int reg3 = vcpu->arch.sie_block->ipa & 0x000f; - int base2 = vcpu->arch.sie_block->ipb >> 28; - int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16) + - ((vcpu->arch.sie_block->ipb & 0xff00) << 4); - u64 useraddr; - int reg, rc; - - vcpu->stat.instruction_lctlg++; - if ((vcpu->arch.sie_block->ipb & 0xff) != 0x2f) - return -EOPNOTSUPP; - - useraddr = disp2; - if (base2) - useraddr += vcpu->run->s.regs.gprs[base2]; - - if (useraddr & 7) - return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); - - reg = reg1; - - VCPU_EVENT(vcpu, 5, "lctlg r1:%x, r3:%x,b2:%x,d2:%x", reg1, reg3, base2, - disp2); - - do { - rc = get_guest_u64(vcpu, useraddr, - &vcpu->arch.sie_block->gcr[reg]); - if (rc == -EFAULT) { - kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); - break; - } - useraddr += 8; - if (reg == reg3) - break; - reg = (reg + 1) % 16; - } while (1); - return 0; -} - -static int handle_lctl(struct kvm_vcpu *vcpu) -{ - int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4; - int reg3 = vcpu->arch.sie_block->ipa & 0x000f; - int base2 = vcpu->arch.sie_block->ipb >> 28; - int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16); - u64 useraddr; - u32 val = 0; - int reg, rc; - - vcpu->stat.instruction_lctl++; - - useraddr = disp2; - if (base2) - useraddr += vcpu->run->s.regs.gprs[base2]; - - if (useraddr & 3) - return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); - - VCPU_EVENT(vcpu, 5, "lctl r1:%x, r3:%x,b2:%x,d2:%x", reg1, reg3, base2, - disp2); - - reg = reg1; - do { - rc = get_guest_u32(vcpu, useraddr, &val); - if (rc == -EFAULT) { - kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); - break; - } - vcpu->arch.sie_block->gcr[reg] &= 0xffffffff00000000ul; - vcpu->arch.sie_block->gcr[reg] |= val; - useraddr += 4; - if (reg == reg3) - break; - reg = (reg + 1) % 16; - } while (1); - return 0; -} - -static intercept_handler_t instruction_handlers[256] = { - [0x83] = kvm_s390_handle_diag, - [0xae] = kvm_s390_handle_sigp, - [0xb2] = kvm_s390_handle_b2, - [0xb7] = handle_lctl, - [0xe5] = kvm_s390_handle_e5, - [0xeb] = handle_lctlg, -}; - -static int handle_noop(struct kvm_vcpu *vcpu) -{ - switch (vcpu->arch.sie_block->icptcode) { - case 0x0: - vcpu->stat.exit_null++; - break; - case 0x10: - vcpu->stat.exit_external_request++; - break; - case 0x14: - vcpu->stat.exit_external_interrupt++; - break; - default: - break; /* nothing */ - } - return 0; -} - -static int handle_stop(struct kvm_vcpu *vcpu) -{ - int rc = 0; - - vcpu->stat.exit_stop_request++; - spin_lock_bh(&vcpu->arch.local_int.lock); - - if (vcpu->arch.local_int.action_bits & ACTION_RELOADVCPU_ON_STOP) { - vcpu->arch.local_int.action_bits &= ~ACTION_RELOADVCPU_ON_STOP; - rc = SIE_INTERCEPT_RERUNVCPU; - vcpu->run->exit_reason = KVM_EXIT_INTR; - } - - if (vcpu->arch.local_int.action_bits & ACTION_STOP_ON_STOP) { - atomic_set_mask(CPUSTAT_STOPPED, - &vcpu->arch.sie_block->cpuflags); - vcpu->arch.local_int.action_bits &= ~ACTION_STOP_ON_STOP; - VCPU_EVENT(vcpu, 3, "%s", "cpu stopped"); - rc = -EOPNOTSUPP; - } - - if (vcpu->arch.local_int.action_bits & ACTION_STORE_ON_STOP) { - vcpu->arch.local_int.action_bits &= ~ACTION_STORE_ON_STOP; - /* store status must be called unlocked. Since local_int.lock - * only protects local_int.* and not guest memory we can give - * up the lock here */ - spin_unlock_bh(&vcpu->arch.local_int.lock); - rc = kvm_s390_vcpu_store_status(vcpu, - KVM_S390_STORE_STATUS_NOADDR); - if (rc >= 0) - rc = -EOPNOTSUPP; - } else - spin_unlock_bh(&vcpu->arch.local_int.lock); - return rc; -} - -static int handle_validity(struct kvm_vcpu *vcpu) -{ - unsigned long vmaddr; - int viwhy = vcpu->arch.sie_block->ipb >> 16; - int rc; - - vcpu->stat.exit_validity++; - if (viwhy == 0x37) { - vmaddr = gmap_fault(vcpu->arch.sie_block->prefix, - vcpu->arch.gmap); - if (IS_ERR_VALUE(vmaddr)) { - rc = -EOPNOTSUPP; - goto out; - } - rc = fault_in_pages_writeable((char __user *) vmaddr, - PAGE_SIZE); - if (rc) { - /* user will receive sigsegv, exit to user */ - rc = -EOPNOTSUPP; - goto out; - } - vmaddr = gmap_fault(vcpu->arch.sie_block->prefix + PAGE_SIZE, - vcpu->arch.gmap); - if (IS_ERR_VALUE(vmaddr)) { - rc = -EOPNOTSUPP; - goto out; - } - rc = fault_in_pages_writeable((char __user *) vmaddr, - PAGE_SIZE); - if (rc) { - /* user will receive sigsegv, exit to user */ - rc = -EOPNOTSUPP; - goto out; - } - } else - rc = -EOPNOTSUPP; - -out: - if (rc) - VCPU_EVENT(vcpu, 2, "unhandled validity intercept code %d", - viwhy); - return rc; -} - -static int handle_instruction(struct kvm_vcpu *vcpu) -{ - intercept_handler_t handler; - - vcpu->stat.exit_instruction++; - handler = instruction_handlers[vcpu->arch.sie_block->ipa >> 8]; - if (handler) - return handler(vcpu); - return -EOPNOTSUPP; -} - -static int handle_prog(struct kvm_vcpu *vcpu) -{ - vcpu->stat.exit_program_interruption++; - return kvm_s390_inject_program_int(vcpu, vcpu->arch.sie_block->iprcc); -} - -static int handle_instruction_and_prog(struct kvm_vcpu *vcpu) -{ - int rc, rc2; - - vcpu->stat.exit_instr_and_program++; - rc = handle_instruction(vcpu); - rc2 = handle_prog(vcpu); - - if (rc == -EOPNOTSUPP) - vcpu->arch.sie_block->icptcode = 0x04; - if (rc) - return rc; - return rc2; -} - -static const intercept_handler_t intercept_funcs[] = { - [0x00 >> 2] = handle_noop, - [0x04 >> 2] = handle_instruction, - [0x08 >> 2] = handle_prog, - [0x0C >> 2] = handle_instruction_and_prog, - [0x10 >> 2] = handle_noop, - [0x14 >> 2] = handle_noop, - [0x1C >> 2] = kvm_s390_handle_wait, - [0x20 >> 2] = handle_validity, - [0x28 >> 2] = handle_stop, -}; - -int kvm_handle_sie_intercept(struct kvm_vcpu *vcpu) -{ - intercept_handler_t func; - u8 code = vcpu->arch.sie_block->icptcode; - - if (code & 3 || (code >> 2) >= ARRAY_SIZE(intercept_funcs)) - return -EOPNOTSUPP; - func = intercept_funcs[code >> 2]; - if (func) - return func(vcpu); - return -EOPNOTSUPP; -} diff --git a/ANDROID_3.4.5/arch/s390/kvm/interrupt.c b/ANDROID_3.4.5/arch/s390/kvm/interrupt.c deleted file mode 100644 index 2d9f9a72..00000000 --- a/ANDROID_3.4.5/arch/s390/kvm/interrupt.c +++ /dev/null @@ -1,641 +0,0 @@ -/* - * interrupt.c - handling kvm guest interrupts - * - * Copyright IBM Corp. 2008 - * - * 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): Carsten Otte <cotte@de.ibm.com> - */ - -#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" - -static int psw_extint_disabled(struct kvm_vcpu *vcpu) -{ - return !(vcpu->arch.sie_block->gpsw.mask & PSW_MASK_EXT); -} - -static int psw_interrupts_disabled(struct kvm_vcpu *vcpu) -{ - if ((vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PER) || - (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_IO) || - (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_EXT)) - return 0; - return 1; -} - -static int __interrupt_is_deliverable(struct kvm_vcpu *vcpu, - struct kvm_s390_interrupt_info *inti) -{ - switch (inti->type) { - case KVM_S390_INT_EXTERNAL_CALL: - if (psw_extint_disabled(vcpu)) - return 0; - if (vcpu->arch.sie_block->gcr[0] & 0x2000ul) - return 1; - case KVM_S390_INT_EMERGENCY: - if (psw_extint_disabled(vcpu)) - return 0; - if (vcpu->arch.sie_block->gcr[0] & 0x4000ul) - return 1; - return 0; - case KVM_S390_INT_SERVICE: - if (psw_extint_disabled(vcpu)) - return 0; - if (vcpu->arch.sie_block->gcr[0] & 0x200ul) - return 1; - return 0; - case KVM_S390_INT_VIRTIO: - if (psw_extint_disabled(vcpu)) - return 0; - if (vcpu->arch.sie_block->gcr[0] & 0x200ul) - return 1; - return 0; - case KVM_S390_PROGRAM_INT: - case KVM_S390_SIGP_STOP: - case KVM_S390_SIGP_SET_PREFIX: - case KVM_S390_RESTART: - return 1; - default: - BUG(); - } - return 0; -} - -static void __set_cpu_idle(struct kvm_vcpu *vcpu) -{ - BUG_ON(vcpu->vcpu_id > KVM_MAX_VCPUS - 1); - atomic_set_mask(CPUSTAT_WAIT, &vcpu->arch.sie_block->cpuflags); - set_bit(vcpu->vcpu_id, vcpu->arch.local_int.float_int->idle_mask); -} - -static void __unset_cpu_idle(struct kvm_vcpu *vcpu) -{ - BUG_ON(vcpu->vcpu_id > KVM_MAX_VCPUS - 1); - atomic_clear_mask(CPUSTAT_WAIT, &vcpu->arch.sie_block->cpuflags); - clear_bit(vcpu->vcpu_id, vcpu->arch.local_int.float_int->idle_mask); -} - -static void __reset_intercept_indicators(struct kvm_vcpu *vcpu) -{ - atomic_clear_mask(CPUSTAT_ECALL_PEND | - CPUSTAT_IO_INT | CPUSTAT_EXT_INT | CPUSTAT_STOP_INT, - &vcpu->arch.sie_block->cpuflags); - vcpu->arch.sie_block->lctl = 0x0000; -} - -static void __set_cpuflag(struct kvm_vcpu *vcpu, u32 flag) -{ - atomic_set_mask(flag, &vcpu->arch.sie_block->cpuflags); -} - -static void __set_intercept_indicator(struct kvm_vcpu *vcpu, - struct kvm_s390_interrupt_info *inti) -{ - switch (inti->type) { - case KVM_S390_INT_EXTERNAL_CALL: - case KVM_S390_INT_EMERGENCY: - case KVM_S390_INT_SERVICE: - case KVM_S390_INT_VIRTIO: - if (psw_extint_disabled(vcpu)) - __set_cpuflag(vcpu, CPUSTAT_EXT_INT); - else - vcpu->arch.sie_block->lctl |= LCTL_CR0; - break; - case KVM_S390_SIGP_STOP: - __set_cpuflag(vcpu, CPUSTAT_STOP_INT); - break; - default: - BUG(); - } -} - -static void __do_deliver_interrupt(struct kvm_vcpu *vcpu, - struct kvm_s390_interrupt_info *inti) -{ - const unsigned short table[] = { 2, 4, 4, 6 }; - int rc, exception = 0; - - switch (inti->type) { - case KVM_S390_INT_EMERGENCY: - VCPU_EVENT(vcpu, 4, "%s", "interrupt: sigp emerg"); - vcpu->stat.deliver_emergency_signal++; - rc = put_guest_u16(vcpu, __LC_EXT_INT_CODE, 0x1201); - if (rc == -EFAULT) - exception = 1; - - rc = put_guest_u16(vcpu, __LC_EXT_CPU_ADDR, inti->emerg.code); - if (rc == -EFAULT) - exception = 1; - - rc = copy_to_guest(vcpu, __LC_EXT_OLD_PSW, - &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); - if (rc == -EFAULT) - exception = 1; - - rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, - __LC_EXT_NEW_PSW, sizeof(psw_t)); - if (rc == -EFAULT) - exception = 1; - break; - - case KVM_S390_INT_EXTERNAL_CALL: - VCPU_EVENT(vcpu, 4, "%s", "interrupt: sigp ext call"); - vcpu->stat.deliver_external_call++; - rc = put_guest_u16(vcpu, __LC_EXT_INT_CODE, 0x1202); - if (rc == -EFAULT) - exception = 1; - - rc = put_guest_u16(vcpu, __LC_EXT_CPU_ADDR, inti->extcall.code); - if (rc == -EFAULT) - exception = 1; - - rc = copy_to_guest(vcpu, __LC_EXT_OLD_PSW, - &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); - if (rc == -EFAULT) - exception = 1; - - rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, - __LC_EXT_NEW_PSW, sizeof(psw_t)); - if (rc == -EFAULT) - exception = 1; - break; - - case KVM_S390_INT_SERVICE: - VCPU_EVENT(vcpu, 4, "interrupt: sclp parm:%x", - inti->ext.ext_params); - vcpu->stat.deliver_service_signal++; - rc = put_guest_u16(vcpu, __LC_EXT_INT_CODE, 0x2401); - if (rc == -EFAULT) - exception = 1; - - rc = copy_to_guest(vcpu, __LC_EXT_OLD_PSW, - &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); - if (rc == -EFAULT) - exception = 1; - - rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, - __LC_EXT_NEW_PSW, sizeof(psw_t)); - if (rc == -EFAULT) - exception = 1; - - rc = put_guest_u32(vcpu, __LC_EXT_PARAMS, inti->ext.ext_params); - if (rc == -EFAULT) - exception = 1; - break; - - case KVM_S390_INT_VIRTIO: - VCPU_EVENT(vcpu, 4, "interrupt: virtio parm:%x,parm64:%llx", - inti->ext.ext_params, inti->ext.ext_params2); - vcpu->stat.deliver_virtio_interrupt++; - rc = put_guest_u16(vcpu, __LC_EXT_INT_CODE, 0x2603); - if (rc == -EFAULT) - exception = 1; - - rc = put_guest_u16(vcpu, __LC_EXT_CPU_ADDR, 0x0d00); - if (rc == -EFAULT) - exception = 1; - - rc = copy_to_guest(vcpu, __LC_EXT_OLD_PSW, - &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); - if (rc == -EFAULT) - exception = 1; - - rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, - __LC_EXT_NEW_PSW, sizeof(psw_t)); - if (rc == -EFAULT) - exception = 1; - - rc = put_guest_u32(vcpu, __LC_EXT_PARAMS, inti->ext.ext_params); - if (rc == -EFAULT) - exception = 1; - - rc = put_guest_u64(vcpu, __LC_EXT_PARAMS2, - inti->ext.ext_params2); - if (rc == -EFAULT) - exception = 1; - break; - - case KVM_S390_SIGP_STOP: - VCPU_EVENT(vcpu, 4, "%s", "interrupt: cpu stop"); - vcpu->stat.deliver_stop_signal++; - __set_intercept_indicator(vcpu, inti); - break; - - case KVM_S390_SIGP_SET_PREFIX: - VCPU_EVENT(vcpu, 4, "interrupt: set prefix to %x", - inti->prefix.address); - vcpu->stat.deliver_prefix_signal++; - kvm_s390_set_prefix(vcpu, inti->prefix.address); - break; - - case KVM_S390_RESTART: - VCPU_EVENT(vcpu, 4, "%s", "interrupt: cpu restart"); - vcpu->stat.deliver_restart_signal++; - rc = copy_to_guest(vcpu, offsetof(struct _lowcore, - restart_old_psw), &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); - if (rc == -EFAULT) - exception = 1; - - rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, - offsetof(struct _lowcore, restart_psw), sizeof(psw_t)); - if (rc == -EFAULT) - exception = 1; - atomic_clear_mask(CPUSTAT_STOPPED, &vcpu->arch.sie_block->cpuflags); - break; - - case KVM_S390_PROGRAM_INT: - VCPU_EVENT(vcpu, 4, "interrupt: pgm check code:%x, ilc:%x", - inti->pgm.code, - table[vcpu->arch.sie_block->ipa >> 14]); - vcpu->stat.deliver_program_int++; - rc = put_guest_u16(vcpu, __LC_PGM_INT_CODE, inti->pgm.code); - if (rc == -EFAULT) - exception = 1; - - rc = put_guest_u16(vcpu, __LC_PGM_ILC, - table[vcpu->arch.sie_block->ipa >> 14]); - if (rc == -EFAULT) - exception = 1; - - rc = copy_to_guest(vcpu, __LC_PGM_OLD_PSW, - &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); - if (rc == -EFAULT) - exception = 1; - - rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, - __LC_PGM_NEW_PSW, sizeof(psw_t)); - if (rc == -EFAULT) - exception = 1; - break; - - default: - BUG(); - } - if (exception) { - printk("kvm: The guest lowcore is not mapped during interrupt " - "delivery, killing userspace\n"); - do_exit(SIGKILL); - } -} - -static int __try_deliver_ckc_interrupt(struct kvm_vcpu *vcpu) -{ - int rc, exception = 0; - - if (psw_extint_disabled(vcpu)) - return 0; - if (!(vcpu->arch.sie_block->gcr[0] & 0x800ul)) - return 0; - rc = put_guest_u16(vcpu, __LC_EXT_INT_CODE, 0x1004); - if (rc == -EFAULT) - exception = 1; - rc = copy_to_guest(vcpu, __LC_EXT_OLD_PSW, - &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); - if (rc == -EFAULT) - exception = 1; - rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, - __LC_EXT_NEW_PSW, sizeof(psw_t)); - if (rc == -EFAULT) - exception = 1; - if (exception) { - printk("kvm: The guest lowcore is not mapped during interrupt " - "delivery, killing userspace\n"); - do_exit(SIGKILL); - } - return 1; -} - -static int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu) -{ - struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; - struct kvm_s390_float_interrupt *fi = vcpu->arch.local_int.float_int; - struct kvm_s390_interrupt_info *inti; - int rc = 0; - - if (atomic_read(&li->active)) { - spin_lock_bh(&li->lock); - list_for_each_entry(inti, &li->list, list) - if (__interrupt_is_deliverable(vcpu, inti)) { - rc = 1; - break; - } - spin_unlock_bh(&li->lock); - } - - if ((!rc) && atomic_read(&fi->active)) { - spin_lock(&fi->lock); - list_for_each_entry(inti, &fi->list, list) - if (__interrupt_is_deliverable(vcpu, inti)) { - rc = 1; - break; - } - spin_unlock(&fi->lock); - } - - if ((!rc) && (vcpu->arch.sie_block->ckc < - get_clock() + vcpu->arch.sie_block->epoch)) { - if ((!psw_extint_disabled(vcpu)) && - (vcpu->arch.sie_block->gcr[0] & 0x800ul)) - rc = 1; - } - - return rc; -} - -int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu) -{ - return 0; -} - -int kvm_s390_handle_wait(struct kvm_vcpu *vcpu) -{ - u64 now, sltime; - DECLARE_WAITQUEUE(wait, current); - - vcpu->stat.exit_wait_state++; - if (kvm_cpu_has_interrupt(vcpu)) - return 0; - - __set_cpu_idle(vcpu); - spin_lock_bh(&vcpu->arch.local_int.lock); - vcpu->arch.local_int.timer_due = 0; - spin_unlock_bh(&vcpu->arch.local_int.lock); - - if (psw_interrupts_disabled(vcpu)) { - VCPU_EVENT(vcpu, 3, "%s", "disabled wait"); - __unset_cpu_idle(vcpu); - return -EOPNOTSUPP; /* disabled wait */ - } - - if (psw_extint_disabled(vcpu) || - (!(vcpu->arch.sie_block->gcr[0] & 0x800ul))) { - VCPU_EVENT(vcpu, 3, "%s", "enabled wait w/o timer"); - goto no_timer; - } - - now = get_clock() + vcpu->arch.sie_block->epoch; - if (vcpu->arch.sie_block->ckc < now) { - __unset_cpu_idle(vcpu); - return 0; - } - - sltime = ((vcpu->arch.sie_block->ckc - now)*125)>>9; - - hrtimer_start(&vcpu->arch.ckc_timer, ktime_set (0, sltime) , HRTIMER_MODE_REL); - VCPU_EVENT(vcpu, 5, "enabled wait via clock comparator: %llx ns", sltime); -no_timer: - spin_lock(&vcpu->arch.local_int.float_int->lock); - spin_lock_bh(&vcpu->arch.local_int.lock); - add_wait_queue(&vcpu->arch.local_int.wq, &wait); - while (list_empty(&vcpu->arch.local_int.list) && - list_empty(&vcpu->arch.local_int.float_int->list) && - (!vcpu->arch.local_int.timer_due) && - !signal_pending(current)) { - set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_bh(&vcpu->arch.local_int.lock); - spin_unlock(&vcpu->arch.local_int.float_int->lock); - vcpu_put(vcpu); - schedule(); - vcpu_load(vcpu); - spin_lock(&vcpu->arch.local_int.float_int->lock); - spin_lock_bh(&vcpu->arch.local_int.lock); - } - __unset_cpu_idle(vcpu); - __set_current_state(TASK_RUNNING); - remove_wait_queue(&vcpu->arch.local_int.wq, &wait); - spin_unlock_bh(&vcpu->arch.local_int.lock); - spin_unlock(&vcpu->arch.local_int.float_int->lock); - hrtimer_try_to_cancel(&vcpu->arch.ckc_timer); - return 0; -} - -void kvm_s390_tasklet(unsigned long parm) -{ - struct kvm_vcpu *vcpu = (struct kvm_vcpu *) parm; - - spin_lock(&vcpu->arch.local_int.lock); - vcpu->arch.local_int.timer_due = 1; - if (waitqueue_active(&vcpu->arch.local_int.wq)) - wake_up_interruptible(&vcpu->arch.local_int.wq); - spin_unlock(&vcpu->arch.local_int.lock); -} - -/* - * low level hrtimer wake routine. Because this runs in hardirq context - * we schedule a tasklet to do the real work. - */ -enum hrtimer_restart kvm_s390_idle_wakeup(struct hrtimer *timer) -{ - struct kvm_vcpu *vcpu; - - vcpu = container_of(timer, struct kvm_vcpu, arch.ckc_timer); - tasklet_schedule(&vcpu->arch.tasklet); - - return HRTIMER_NORESTART; -} - -void kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu) -{ - struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; - struct kvm_s390_float_interrupt *fi = vcpu->arch.local_int.float_int; - struct kvm_s390_interrupt_info *n, *inti = NULL; - int deliver; - - __reset_intercept_indicators(vcpu); - if (atomic_read(&li->active)) { - do { - deliver = 0; - spin_lock_bh(&li->lock); - list_for_each_entry_safe(inti, n, &li->list, list) { - if (__interrupt_is_deliverable(vcpu, inti)) { - list_del(&inti->list); - deliver = 1; - break; - } - __set_intercept_indicator(vcpu, inti); - } - if (list_empty(&li->list)) - atomic_set(&li->active, 0); - spin_unlock_bh(&li->lock); - if (deliver) { - __do_deliver_interrupt(vcpu, inti); - kfree(inti); - } - } while (deliver); - } - - if ((vcpu->arch.sie_block->ckc < - get_clock() + vcpu->arch.sie_block->epoch)) - __try_deliver_ckc_interrupt(vcpu); - - if (atomic_read(&fi->active)) { - do { - deliver = 0; - spin_lock(&fi->lock); - list_for_each_entry_safe(inti, n, &fi->list, list) { - if (__interrupt_is_deliverable(vcpu, inti)) { - list_del(&inti->list); - deliver = 1; - break; - } - __set_intercept_indicator(vcpu, inti); - } - if (list_empty(&fi->list)) - atomic_set(&fi->active, 0); - spin_unlock(&fi->lock); - if (deliver) { - __do_deliver_interrupt(vcpu, inti); - kfree(inti); - } - } while (deliver); - } -} - -int kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code) -{ - struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; - struct kvm_s390_interrupt_info *inti; - - inti = kzalloc(sizeof(*inti), GFP_KERNEL); - if (!inti) - return -ENOMEM; - - inti->type = KVM_S390_PROGRAM_INT; - inti->pgm.code = code; - - VCPU_EVENT(vcpu, 3, "inject: program check %d (from kernel)", code); - spin_lock_bh(&li->lock); - list_add(&inti->list, &li->list); - atomic_set(&li->active, 1); - BUG_ON(waitqueue_active(&li->wq)); - spin_unlock_bh(&li->lock); - return 0; -} - -int kvm_s390_inject_vm(struct kvm *kvm, - struct kvm_s390_interrupt *s390int) -{ - struct kvm_s390_local_interrupt *li; - struct kvm_s390_float_interrupt *fi; - struct kvm_s390_interrupt_info *inti; - int sigcpu; - - inti = kzalloc(sizeof(*inti), GFP_KERNEL); - if (!inti) - return -ENOMEM; - - switch (s390int->type) { - case KVM_S390_INT_VIRTIO: - VM_EVENT(kvm, 5, "inject: virtio parm:%x,parm64:%llx", - s390int->parm, s390int->parm64); - inti->type = s390int->type; - inti->ext.ext_params = s390int->parm; - inti->ext.ext_params2 = s390int->parm64; - break; - case KVM_S390_INT_SERVICE: - VM_EVENT(kvm, 5, "inject: sclp parm:%x", s390int->parm); - inti->type = s390int->type; - inti->ext.ext_params = s390int->parm; - break; - case KVM_S390_PROGRAM_INT: - case KVM_S390_SIGP_STOP: - case KVM_S390_INT_EXTERNAL_CALL: - case KVM_S390_INT_EMERGENCY: - default: - kfree(inti); - return -EINVAL; - } - - mutex_lock(&kvm->lock); - fi = &kvm->arch.float_int; - spin_lock(&fi->lock); - list_add_tail(&inti->list, &fi->list); - atomic_set(&fi->active, 1); - sigcpu = find_first_bit(fi->idle_mask, KVM_MAX_VCPUS); - if (sigcpu == KVM_MAX_VCPUS) { - do { - sigcpu = fi->next_rr_cpu++; - if (sigcpu == KVM_MAX_VCPUS) - sigcpu = fi->next_rr_cpu = 0; - } while (fi->local_int[sigcpu] == NULL); - } - li = fi->local_int[sigcpu]; - spin_lock_bh(&li->lock); - atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags); - if (waitqueue_active(&li->wq)) - wake_up_interruptible(&li->wq); - spin_unlock_bh(&li->lock); - spin_unlock(&fi->lock); - mutex_unlock(&kvm->lock); - return 0; -} - -int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu, - struct kvm_s390_interrupt *s390int) -{ - struct kvm_s390_local_interrupt *li; - struct kvm_s390_interrupt_info *inti; - - inti = kzalloc(sizeof(*inti), GFP_KERNEL); - if (!inti) - return -ENOMEM; - - switch (s390int->type) { - case KVM_S390_PROGRAM_INT: - if (s390int->parm & 0xffff0000) { - kfree(inti); - return -EINVAL; - } - inti->type = s390int->type; - inti->pgm.code = s390int->parm; - VCPU_EVENT(vcpu, 3, "inject: program check %d (from user)", - s390int->parm); - break; - case KVM_S390_SIGP_SET_PREFIX: - inti->prefix.address = s390int->parm; - inti->type = s390int->type; - VCPU_EVENT(vcpu, 3, "inject: set prefix to %x (from user)", - s390int->parm); - break; - case KVM_S390_SIGP_STOP: - case KVM_S390_RESTART: - case KVM_S390_INT_EXTERNAL_CALL: - case KVM_S390_INT_EMERGENCY: - VCPU_EVENT(vcpu, 3, "inject: type %x", s390int->type); - inti->type = s390int->type; - break; - case KVM_S390_INT_VIRTIO: - case KVM_S390_INT_SERVICE: - default: - kfree(inti); - return -EINVAL; - } - - mutex_lock(&vcpu->kvm->lock); - li = &vcpu->arch.local_int; - spin_lock_bh(&li->lock); - if (inti->type == KVM_S390_PROGRAM_INT) - list_add(&inti->list, &li->list); - else - list_add_tail(&inti->list, &li->list); - atomic_set(&li->active, 1); - if (inti->type == KVM_S390_SIGP_STOP) - li->action_bits |= ACTION_STOP_ON_STOP; - atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags); - if (waitqueue_active(&li->wq)) - wake_up_interruptible(&vcpu->arch.local_int.wq); - spin_unlock_bh(&li->lock); - mutex_unlock(&vcpu->kvm->lock); - return 0; -} diff --git a/ANDROID_3.4.5/arch/s390/kvm/kvm-s390.c b/ANDROID_3.4.5/arch/s390/kvm/kvm-s390.c deleted file mode 100644 index 217ce443..00000000 --- a/ANDROID_3.4.5/arch/s390/kvm/kvm-s390.c +++ /dev/null @@ -1,908 +0,0 @@ -/* - * s390host.c -- hosting zSeries kernel virtual machines - * - * Copyright IBM Corp. 2008,2009 - * - * 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): Carsten Otte <cotte@de.ibm.com> - * Christian Borntraeger <borntraeger@de.ibm.com> - * Heiko Carstens <heiko.carstens@de.ibm.com> - * Christian Ehrhardt <ehrhardt@de.ibm.com> - */ - -#include <linux/compiler.h> -#include <linux/err.h> -#include <linux/fs.h> -#include <linux/hrtimer.h> -#include <linux/init.h> -#include <linux/kvm.h> -#include <linux/kvm_host.h> -#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> -#include <asm/switch_to.h> -#include "kvm-s390.h" -#include "gaccess.h" - -#define VCPU_STAT(x) offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU - -struct kvm_stats_debugfs_item debugfs_entries[] = { - { "userspace_handled", VCPU_STAT(exit_userspace) }, - { "exit_null", VCPU_STAT(exit_null) }, - { "exit_validity", VCPU_STAT(exit_validity) }, - { "exit_stop_request", VCPU_STAT(exit_stop_request) }, - { "exit_external_request", VCPU_STAT(exit_external_request) }, - { "exit_external_interrupt", VCPU_STAT(exit_external_interrupt) }, - { "exit_instruction", VCPU_STAT(exit_instruction) }, - { "exit_program_interruption", VCPU_STAT(exit_program_interruption) }, - { "exit_instr_and_program_int", VCPU_STAT(exit_instr_and_program) }, - { "instruction_lctlg", VCPU_STAT(instruction_lctlg) }, - { "instruction_lctl", VCPU_STAT(instruction_lctl) }, - { "deliver_emergency_signal", VCPU_STAT(deliver_emergency_signal) }, - { "deliver_external_call", VCPU_STAT(deliver_external_call) }, - { "deliver_service_signal", VCPU_STAT(deliver_service_signal) }, - { "deliver_virtio_interrupt", VCPU_STAT(deliver_virtio_interrupt) }, - { "deliver_stop_signal", VCPU_STAT(deliver_stop_signal) }, - { "deliver_prefix_signal", VCPU_STAT(deliver_prefix_signal) }, - { "deliver_restart_signal", VCPU_STAT(deliver_restart_signal) }, - { "deliver_program_interruption", VCPU_STAT(deliver_program_int) }, - { "exit_wait_state", VCPU_STAT(exit_wait_state) }, - { "instruction_stidp", VCPU_STAT(instruction_stidp) }, - { "instruction_spx", VCPU_STAT(instruction_spx) }, - { "instruction_stpx", VCPU_STAT(instruction_stpx) }, - { "instruction_stap", VCPU_STAT(instruction_stap) }, - { "instruction_storage_key", VCPU_STAT(instruction_storage_key) }, - { "instruction_stsch", VCPU_STAT(instruction_stsch) }, - { "instruction_chsc", VCPU_STAT(instruction_chsc) }, - { "instruction_stsi", VCPU_STAT(instruction_stsi) }, - { "instruction_stfl", VCPU_STAT(instruction_stfl) }, - { "instruction_tprot", VCPU_STAT(instruction_tprot) }, - { "instruction_sigp_sense", VCPU_STAT(instruction_sigp_sense) }, - { "instruction_sigp_sense_running", VCPU_STAT(instruction_sigp_sense_running) }, - { "instruction_sigp_external_call", VCPU_STAT(instruction_sigp_external_call) }, - { "instruction_sigp_emergency", VCPU_STAT(instruction_sigp_emergency) }, - { "instruction_sigp_stop", VCPU_STAT(instruction_sigp_stop) }, - { "instruction_sigp_set_arch", VCPU_STAT(instruction_sigp_arch) }, - { "instruction_sigp_set_prefix", VCPU_STAT(instruction_sigp_prefix) }, - { "instruction_sigp_restart", VCPU_STAT(instruction_sigp_restart) }, - { "diagnose_10", VCPU_STAT(diagnose_10) }, - { "diagnose_44", VCPU_STAT(diagnose_44) }, - { NULL } -}; - -static unsigned long long *facilities; - -/* Section: not file related */ -int kvm_arch_hardware_enable(void *garbage) -{ - /* every s390 is virtualization enabled ;-) */ - return 0; -} - -void kvm_arch_hardware_disable(void *garbage) -{ -} - -int kvm_arch_hardware_setup(void) -{ - return 0; -} - -void kvm_arch_hardware_unsetup(void) -{ -} - -void kvm_arch_check_processor_compat(void *rtn) -{ -} - -int kvm_arch_init(void *opaque) -{ - return 0; -} - -void kvm_arch_exit(void) -{ -} - -/* Section: device related */ -long kvm_arch_dev_ioctl(struct file *filp, - unsigned int ioctl, unsigned long arg) -{ - if (ioctl == KVM_S390_ENABLE_SIE) - return s390_enable_sie(); - return -EINVAL; -} - -int kvm_dev_ioctl_check_extension(long ext) -{ - int r; - - switch (ext) { - case KVM_CAP_S390_PSW: - case KVM_CAP_S390_GMAP: - case KVM_CAP_SYNC_MMU: -#ifdef CONFIG_KVM_S390_UCONTROL - case KVM_CAP_S390_UCONTROL: -#endif - case KVM_CAP_SYNC_REGS: - r = 1; - break; - default: - r = 0; - } - return r; -} - -/* Section: vm related */ -/* - * Get (and clear) the dirty memory log for a memory slot. - */ -int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, - struct kvm_dirty_log *log) -{ - return 0; -} - -long kvm_arch_vm_ioctl(struct file *filp, - unsigned int ioctl, unsigned long arg) -{ - struct kvm *kvm = filp->private_data; - void __user *argp = (void __user *)arg; - int r; - - switch (ioctl) { - case KVM_S390_INTERRUPT: { - struct kvm_s390_interrupt s390int; - - r = -EFAULT; - if (copy_from_user(&s390int, argp, sizeof(s390int))) - break; - r = kvm_s390_inject_vm(kvm, &s390int); - break; - } - default: - r = -ENOTTY; - } - - return r; -} - -int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) -{ - int rc; - char debug_name[16]; - - rc = -EINVAL; -#ifdef CONFIG_KVM_S390_UCONTROL - if (type & ~KVM_VM_S390_UCONTROL) - goto out_err; - if ((type & KVM_VM_S390_UCONTROL) && (!capable(CAP_SYS_ADMIN))) - goto out_err; -#else - if (type) - goto out_err; -#endif - - rc = s390_enable_sie(); - if (rc) - goto out_err; - - rc = -ENOMEM; - - kvm->arch.sca = (struct sca_block *) get_zeroed_page(GFP_KERNEL); - if (!kvm->arch.sca) - goto out_err; - - sprintf(debug_name, "kvm-%u", current->pid); - - kvm->arch.dbf = debug_register(debug_name, 8, 2, 8 * sizeof(long)); - if (!kvm->arch.dbf) - goto out_nodbf; - - spin_lock_init(&kvm->arch.float_int.lock); - INIT_LIST_HEAD(&kvm->arch.float_int.list); - - debug_register_view(kvm->arch.dbf, &debug_sprintf_view); - VM_EVENT(kvm, 3, "%s", "vm created"); - - if (type & KVM_VM_S390_UCONTROL) { - kvm->arch.gmap = NULL; - } else { - kvm->arch.gmap = gmap_alloc(current->mm); - if (!kvm->arch.gmap) - goto out_nogmap; - } - return 0; -out_nogmap: - debug_unregister(kvm->arch.dbf); -out_nodbf: - free_page((unsigned long)(kvm->arch.sca)); -out_err: - return rc; -} - -void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu) -{ - VCPU_EVENT(vcpu, 3, "%s", "free cpu"); - if (!kvm_is_ucontrol(vcpu->kvm)) { - 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; - } - smp_mb(); - - if (kvm_is_ucontrol(vcpu->kvm)) - gmap_free(vcpu->arch.gmap); - - free_page((unsigned long)(vcpu->arch.sie_block)); - kvm_vcpu_uninit(vcpu); - kfree(vcpu); -} - -static void kvm_free_vcpus(struct kvm *kvm) -{ - unsigned int i; - struct kvm_vcpu *vcpu; - - kvm_for_each_vcpu(i, vcpu, kvm) - kvm_arch_vcpu_destroy(vcpu); - - mutex_lock(&kvm->lock); - for (i = 0; i < atomic_read(&kvm->online_vcpus); i++) - kvm->vcpus[i] = NULL; - - atomic_set(&kvm->online_vcpus, 0); - mutex_unlock(&kvm->lock); -} - -void kvm_arch_sync_events(struct kvm *kvm) -{ -} - -void kvm_arch_destroy_vm(struct kvm *kvm) -{ - kvm_free_vcpus(kvm); - free_page((unsigned long)(kvm->arch.sca)); - debug_unregister(kvm->arch.dbf); - if (!kvm_is_ucontrol(kvm)) - gmap_free(kvm->arch.gmap); -} - -/* Section: vcpu related */ -int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu) -{ - if (kvm_is_ucontrol(vcpu->kvm)) { - vcpu->arch.gmap = gmap_alloc(current->mm); - if (!vcpu->arch.gmap) - return -ENOMEM; - return 0; - } - - vcpu->arch.gmap = vcpu->kvm->arch.gmap; - vcpu->run->kvm_valid_regs = KVM_SYNC_PREFIX | - KVM_SYNC_GPRS | - KVM_SYNC_ACRS | - KVM_SYNC_CRS; - return 0; -} - -void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu) -{ - /* Nothing todo */ -} - -void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) -{ - save_fp_regs(&vcpu->arch.host_fpregs); - save_access_regs(vcpu->arch.host_acrs); - vcpu->arch.guest_fpregs.fpc &= FPC_VALID_MASK; - restore_fp_regs(&vcpu->arch.guest_fpregs); - restore_access_regs(vcpu->run->s.regs.acrs); - gmap_enable(vcpu->arch.gmap); - atomic_set_mask(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags); -} - -void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) -{ - atomic_clear_mask(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags); - gmap_disable(vcpu->arch.gmap); - save_fp_regs(&vcpu->arch.guest_fpregs); - save_access_regs(vcpu->run->s.regs.acrs); - restore_fp_regs(&vcpu->arch.host_fpregs); - restore_access_regs(vcpu->arch.host_acrs); -} - -static void kvm_s390_vcpu_initial_reset(struct kvm_vcpu *vcpu) -{ - /* this equals initial cpu reset in pop, but we don't switch to ESA */ - vcpu->arch.sie_block->gpsw.mask = 0UL; - vcpu->arch.sie_block->gpsw.addr = 0UL; - kvm_s390_set_prefix(vcpu, 0); - vcpu->arch.sie_block->cputm = 0UL; - vcpu->arch.sie_block->ckc = 0UL; - vcpu->arch.sie_block->todpr = 0; - memset(vcpu->arch.sie_block->gcr, 0, 16 * sizeof(__u64)); - vcpu->arch.sie_block->gcr[0] = 0xE0UL; - vcpu->arch.sie_block->gcr[14] = 0xC2000000UL; - vcpu->arch.guest_fpregs.fpc = 0; - asm volatile("lfpc %0" : : "Q" (vcpu->arch.guest_fpregs.fpc)); - vcpu->arch.sie_block->gbea = 1; -} - -int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu) -{ - atomic_set(&vcpu->arch.sie_block->cpuflags, CPUSTAT_ZARCH | - CPUSTAT_SM | - CPUSTAT_STOPPED); - 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); - tasklet_init(&vcpu->arch.tasklet, kvm_s390_tasklet, - (unsigned long) vcpu); - vcpu->arch.ckc_timer.function = kvm_s390_idle_wakeup; - get_cpu_id(&vcpu->arch.cpu_id); - vcpu->arch.cpu_id.version = 0xff; - return 0; -} - -struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, - unsigned int id) -{ - struct kvm_vcpu *vcpu; - int rc = -EINVAL; - - if (id >= KVM_MAX_VCPUS) - goto out; - - rc = -ENOMEM; - - vcpu = kzalloc(sizeof(struct kvm_vcpu), GFP_KERNEL); - if (!vcpu) - goto out; - - vcpu->arch.sie_block = (struct kvm_s390_sie_block *) - get_zeroed_page(GFP_KERNEL); - - if (!vcpu->arch.sie_block) - goto out_free_cpu; - - vcpu->arch.sie_block->icpua = id; - if (!kvm_is_ucontrol(kvm)) { - if (!kvm->arch.sca) { - WARN_ON_ONCE(1); - goto out_free_cpu; - } - if (!kvm->arch.sca->cpu[id].sda) - 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); - vcpu->arch.local_int.float_int = &kvm->arch.float_int; - spin_lock(&kvm->arch.float_int.lock); - kvm->arch.float_int.local_int[id] = &vcpu->arch.local_int; - init_waitqueue_head(&vcpu->arch.local_int.wq); - vcpu->arch.local_int.cpuflags = &vcpu->arch.sie_block->cpuflags; - spin_unlock(&kvm->arch.float_int.lock); - - rc = kvm_vcpu_init(vcpu, kvm, id); - if (rc) - 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: - return ERR_PTR(rc); -} - -int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu) -{ - /* kvm common code refers to this, but never calls it */ - BUG(); - return 0; -} - -static int kvm_arch_vcpu_ioctl_initial_reset(struct kvm_vcpu *vcpu) -{ - kvm_s390_vcpu_initial_reset(vcpu); - return 0; -} - -int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) -{ - memcpy(&vcpu->run->s.regs.gprs, ®s->gprs, sizeof(regs->gprs)); - return 0; -} - -int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) -{ - memcpy(®s->gprs, &vcpu->run->s.regs.gprs, sizeof(regs->gprs)); - return 0; -} - -int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu, - struct kvm_sregs *sregs) -{ - memcpy(&vcpu->run->s.regs.acrs, &sregs->acrs, sizeof(sregs->acrs)); - memcpy(&vcpu->arch.sie_block->gcr, &sregs->crs, sizeof(sregs->crs)); - restore_access_regs(vcpu->run->s.regs.acrs); - return 0; -} - -int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu, - struct kvm_sregs *sregs) -{ - memcpy(&sregs->acrs, &vcpu->run->s.regs.acrs, sizeof(sregs->acrs)); - memcpy(&sregs->crs, &vcpu->arch.sie_block->gcr, sizeof(sregs->crs)); - return 0; -} - -int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) -{ - memcpy(&vcpu->arch.guest_fpregs.fprs, &fpu->fprs, sizeof(fpu->fprs)); - vcpu->arch.guest_fpregs.fpc = fpu->fpc & FPC_VALID_MASK; - restore_fp_regs(&vcpu->arch.guest_fpregs); - return 0; -} - -int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) -{ - memcpy(&fpu->fprs, &vcpu->arch.guest_fpregs.fprs, sizeof(fpu->fprs)); - fpu->fpc = vcpu->arch.guest_fpregs.fpc; - return 0; -} - -static int kvm_arch_vcpu_ioctl_set_initial_psw(struct kvm_vcpu *vcpu, psw_t psw) -{ - int rc = 0; - - if (!(atomic_read(&vcpu->arch.sie_block->cpuflags) & CPUSTAT_STOPPED)) - rc = -EBUSY; - else { - vcpu->run->psw_mask = psw.mask; - vcpu->run->psw_addr = psw.addr; - } - return rc; -} - -int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu, - struct kvm_translation *tr) -{ - return -EINVAL; /* not implemented yet */ -} - -int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, - struct kvm_guest_debug *dbg) -{ - return -EINVAL; /* not implemented yet */ -} - -int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu, - struct kvm_mp_state *mp_state) -{ - return -EINVAL; /* not implemented yet */ -} - -int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu, - struct kvm_mp_state *mp_state) -{ - return -EINVAL; /* not implemented yet */ -} - -static int __vcpu_run(struct kvm_vcpu *vcpu) -{ - int rc; - - memcpy(&vcpu->arch.sie_block->gg14, &vcpu->run->s.regs.gprs[14], 16); - - if (need_resched()) - schedule(); - - if (test_thread_flag(TIF_MCCK_PENDING)) - s390_handle_mcck(); - - if (!kvm_is_ucontrol(vcpu->kvm)) - kvm_s390_deliver_pending_interrupts(vcpu); - - vcpu->arch.sie_block->icptcode = 0; - local_irq_disable(); - kvm_guest_enter(); - local_irq_enable(); - VCPU_EVENT(vcpu, 6, "entering sie flags %x", - atomic_read(&vcpu->arch.sie_block->cpuflags)); - rc = sie64a(vcpu->arch.sie_block, vcpu->run->s.regs.gprs); - if (rc) { - if (kvm_is_ucontrol(vcpu->kvm)) { - rc = SIE_INTERCEPT_UCONTROL; - } else { - VCPU_EVENT(vcpu, 3, "%s", "fault in sie instruction"); - kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); - rc = 0; - } - } - VCPU_EVENT(vcpu, 6, "exit sie icptcode %d", - vcpu->arch.sie_block->icptcode); - local_irq_disable(); - kvm_guest_exit(); - local_irq_enable(); - - memcpy(&vcpu->run->s.regs.gprs[14], &vcpu->arch.sie_block->gg14, 16); - return rc; -} - -int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) -{ - int rc; - sigset_t sigsaved; - -rerun_vcpu: - if (vcpu->sigset_active) - sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved); - - atomic_clear_mask(CPUSTAT_STOPPED, &vcpu->arch.sie_block->cpuflags); - - BUG_ON(vcpu->kvm->arch.float_int.local_int[vcpu->vcpu_id] == NULL); - - switch (kvm_run->exit_reason) { - case KVM_EXIT_S390_SIEIC: - case KVM_EXIT_UNKNOWN: - case KVM_EXIT_INTR: - case KVM_EXIT_S390_RESET: - case KVM_EXIT_S390_UCONTROL: - break; - default: - BUG(); - } - - vcpu->arch.sie_block->gpsw.mask = kvm_run->psw_mask; - vcpu->arch.sie_block->gpsw.addr = kvm_run->psw_addr; - if (kvm_run->kvm_dirty_regs & KVM_SYNC_PREFIX) { - kvm_run->kvm_dirty_regs &= ~KVM_SYNC_PREFIX; - kvm_s390_set_prefix(vcpu, kvm_run->s.regs.prefix); - } - if (kvm_run->kvm_dirty_regs & KVM_SYNC_CRS) { - kvm_run->kvm_dirty_regs &= ~KVM_SYNC_CRS; - memcpy(&vcpu->arch.sie_block->gcr, &kvm_run->s.regs.crs, 128); - kvm_s390_set_prefix(vcpu, kvm_run->s.regs.prefix); - } - - might_fault(); - - do { - rc = __vcpu_run(vcpu); - if (rc) - break; - if (kvm_is_ucontrol(vcpu->kvm)) - rc = -EOPNOTSUPP; - else - rc = kvm_handle_sie_intercept(vcpu); - } while (!signal_pending(current) && !rc); - - if (rc == SIE_INTERCEPT_RERUNVCPU) - goto rerun_vcpu; - - if (signal_pending(current) && !rc) { - kvm_run->exit_reason = KVM_EXIT_INTR; - rc = -EINTR; - } - -#ifdef CONFIG_KVM_S390_UCONTROL - if (rc == SIE_INTERCEPT_UCONTROL) { - kvm_run->exit_reason = KVM_EXIT_S390_UCONTROL; - kvm_run->s390_ucontrol.trans_exc_code = - current->thread.gmap_addr; - kvm_run->s390_ucontrol.pgm_code = 0x10; - rc = 0; - } -#endif - - 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; - kvm_run->s390_sieic.ipa = vcpu->arch.sie_block->ipa; - kvm_run->s390_sieic.ipb = vcpu->arch.sie_block->ipb; - rc = 0; - } - - if (rc == -EREMOTE) { - /* intercept was handled, but userspace support is needed - * kvm_run has been prepared by the handler */ - rc = 0; - } - - kvm_run->psw_mask = vcpu->arch.sie_block->gpsw.mask; - kvm_run->psw_addr = vcpu->arch.sie_block->gpsw.addr; - kvm_run->s.regs.prefix = vcpu->arch.sie_block->prefix; - memcpy(&kvm_run->s.regs.crs, &vcpu->arch.sie_block->gcr, 128); - - if (vcpu->sigset_active) - sigprocmask(SIG_SETMASK, &sigsaved, NULL); - - vcpu->stat.exit_userspace++; - return rc; -} - -static int __guestcopy(struct kvm_vcpu *vcpu, u64 guestdest, void *from, - unsigned long n, int prefix) -{ - if (prefix) - return copy_to_guest(vcpu, guestdest, from, n); - else - return copy_to_guest_absolute(vcpu, guestdest, from, n); -} - -/* - * store status at address - * we use have two special cases: - * 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) -{ - unsigned char archmode = 1; - int prefix; - - if (addr == KVM_S390_STORE_STATUS_NOADDR) { - if (copy_to_guest_absolute(vcpu, 163ul, &archmode, 1)) - return -EFAULT; - addr = SAVE_AREA_BASE; - prefix = 0; - } else if (addr == KVM_S390_STORE_STATUS_PREFIXED) { - if (copy_to_guest(vcpu, 163ul, &archmode, 1)) - return -EFAULT; - addr = SAVE_AREA_BASE; - prefix = 1; - } else - prefix = 0; - - 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, gp_regs), - vcpu->run->s.regs.gprs, 128, prefix)) - return -EFAULT; - - 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, pref_reg), - &vcpu->arch.sie_block->prefix, 4, prefix)) - return -EFAULT; - - if (__guestcopy(vcpu, - 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, tod_reg), - &vcpu->arch.sie_block->todpr, 4, prefix)) - return -EFAULT; - - 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, clk_cmp), - &vcpu->arch.sie_block->ckc, 8, prefix)) - return -EFAULT; - - if (__guestcopy(vcpu, addr + offsetof(struct save_area, acc_regs), - &vcpu->run->s.regs.acrs, 64, prefix)) - return -EFAULT; - - if (__guestcopy(vcpu, - addr + offsetof(struct save_area, ctrl_regs), - &vcpu->arch.sie_block->gcr, 128, prefix)) - return -EFAULT; - return 0; -} - -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))) - break; - r = kvm_s390_inject_vcpu(vcpu, &s390int); - break; - } - case KVM_S390_STORE_STATUS: - 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))) - break; - r = kvm_arch_vcpu_ioctl_set_initial_psw(vcpu, psw); - break; - } - case KVM_S390_INITIAL_RESET: - r = kvm_arch_vcpu_ioctl_initial_reset(vcpu); - break; -#ifdef CONFIG_KVM_S390_UCONTROL - case KVM_S390_UCAS_MAP: { - struct kvm_s390_ucas_mapping ucasmap; - - if (copy_from_user(&ucasmap, argp, sizeof(ucasmap))) { - r = -EFAULT; - break; - } - - if (!kvm_is_ucontrol(vcpu->kvm)) { - r = -EINVAL; - break; - } - - r = gmap_map_segment(vcpu->arch.gmap, ucasmap.user_addr, - ucasmap.vcpu_addr, ucasmap.length); - break; - } - case KVM_S390_UCAS_UNMAP: { - struct kvm_s390_ucas_mapping ucasmap; - - if (copy_from_user(&ucasmap, argp, sizeof(ucasmap))) { - r = -EFAULT; - break; - } - - if (!kvm_is_ucontrol(vcpu->kvm)) { - r = -EINVAL; - break; - } - - r = gmap_unmap_segment(vcpu->arch.gmap, ucasmap.vcpu_addr, - ucasmap.length); - break; - } -#endif - case KVM_S390_VCPU_FAULT: { - r = gmap_fault(arg, vcpu->arch.gmap); - if (!IS_ERR_VALUE(r)) - r = 0; - break; - } - default: - r = -ENOTTY; - } - return r; -} - -int kvm_arch_vcpu_fault(struct kvm_vcpu *vcpu, struct vm_fault *vmf) -{ -#ifdef CONFIG_KVM_S390_UCONTROL - if ((vmf->pgoff == KVM_S390_SIE_PAGE_OFFSET) - && (kvm_is_ucontrol(vcpu->kvm))) { - vmf->page = virt_to_page(vcpu->arch.sie_block); - get_page(vmf->page); - return 0; - } -#endif - return VM_FAULT_SIGBUS; -} - -void kvm_arch_free_memslot(struct kvm_memory_slot *free, - struct kvm_memory_slot *dont) -{ -} - -int kvm_arch_create_memslot(struct kvm_memory_slot *slot, unsigned long npages) -{ - return 0; -} - -/* Section: memory related */ -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) -{ - /* 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. - The memory in userland is ok to be fragmented into various different - vmas. It is okay to mmap() and munmap() stuff in this slot after - doing this call at any time */ - - if (mem->slot) - return -EINVAL; - - if (mem->guest_phys_addr) - return -EINVAL; - - if (mem->userspace_addr & 0xffffful) - return -EINVAL; - - if (mem->memory_size & 0xffffful) - return -EINVAL; - - 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 rc; - - - rc = gmap_map_segment(kvm->arch.gmap, mem->userspace_addr, - mem->guest_phys_addr, mem->memory_size); - if (rc) - printk(KERN_WARNING "kvm-s390: failed to commit memory region\n"); - return; -} - -void kvm_arch_flush_shadow(struct kvm *kvm) -{ -} - -static int __init kvm_s390_init(void) -{ - int ret; - ret = kvm_init(NULL, sizeof(struct kvm_vcpu), 0, 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 facilities. On the other hand, we - * only set facilities that are known to work in KVM. - */ - facilities = (unsigned long long *) get_zeroed_page(GFP_KERNEL|GFP_DMA); - if (!facilities) { - kvm_exit(); - return -ENOMEM; - } - memcpy(facilities, S390_lowcore.stfle_fac_list, 16); - facilities[0] &= 0xff00fff3f47c0000ULL; - facilities[1] &= 0x201c000000000000ULL; - return 0; -} - -static void __exit kvm_s390_exit(void) -{ - free_page((unsigned long) facilities); - kvm_exit(); -} - -module_init(kvm_s390_init); -module_exit(kvm_s390_exit); diff --git a/ANDROID_3.4.5/arch/s390/kvm/kvm-s390.h b/ANDROID_3.4.5/arch/s390/kvm/kvm-s390.h deleted file mode 100644 index ff28f9d1..00000000 --- a/ANDROID_3.4.5/arch/s390/kvm/kvm-s390.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * kvm_s390.h - definition for kvm on s390 - * - * Copyright IBM Corp. 2008,2009 - * - * 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): Carsten Otte <cotte@de.ibm.com> - * Christian Borntraeger <borntraeger@de.ibm.com> - * Christian Ehrhardt <ehrhardt@de.ibm.com> - */ - -#ifndef ARCH_S390_KVM_S390_H -#define ARCH_S390_KVM_S390_H - -#include <linux/hrtimer.h> -#include <linux/kvm.h> -#include <linux/kvm_host.h> - -/* The current code can have up to 256 pages for virtio */ -#define VIRTIODESCSPACE (256ul * 4096ul) - -typedef int (*intercept_handler_t)(struct kvm_vcpu *vcpu); - -/* negativ values are error codes, positive values for internal conditions */ -#define SIE_INTERCEPT_RERUNVCPU (1<<0) -#define SIE_INTERCEPT_UCONTROL (1<<1) -int kvm_handle_sie_intercept(struct kvm_vcpu *vcpu); - -#define VM_EVENT(d_kvm, d_loglevel, d_string, d_args...)\ -do { \ - debug_sprintf_event(d_kvm->arch.dbf, d_loglevel, d_string "\n", \ - d_args); \ -} while (0) - -#define VCPU_EVENT(d_vcpu, d_loglevel, d_string, d_args...)\ -do { \ - debug_sprintf_event(d_vcpu->kvm->arch.dbf, d_loglevel, \ - "%02d[%016lx-%016lx]: " d_string "\n", d_vcpu->vcpu_id, \ - d_vcpu->arch.sie_block->gpsw.mask, d_vcpu->arch.sie_block->gpsw.addr,\ - d_args); \ -} while (0) - -static inline int __cpu_is_stopped(struct kvm_vcpu *vcpu) -{ - return atomic_read(&vcpu->arch.sie_block->cpuflags) & CPUSTAT_STOP_INT; -} - -static inline int kvm_is_ucontrol(struct kvm *kvm) -{ -#ifdef CONFIG_KVM_S390_UCONTROL - if (kvm->arch.gmap) - return 0; - return 1; -#else - return 0; -#endif -} - -static inline void kvm_s390_set_prefix(struct kvm_vcpu *vcpu, u32 prefix) -{ - vcpu->arch.sie_block->prefix = prefix & 0x7fffe000u; - vcpu->arch.sie_block->ihcpu = 0xffff; -} - -int kvm_s390_handle_wait(struct kvm_vcpu *vcpu); -enum hrtimer_restart kvm_s390_idle_wakeup(struct hrtimer *timer); -void kvm_s390_tasklet(unsigned long parm); -void kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu); -int kvm_s390_inject_vm(struct kvm *kvm, - struct kvm_s390_interrupt *s390int); -int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu, - struct kvm_s390_interrupt *s390int); -int kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code); -int kvm_s390_inject_sigp_stop(struct kvm_vcpu *vcpu, int action); - -/* implemented in priv.c */ -int kvm_s390_handle_b2(struct kvm_vcpu *vcpu); -int kvm_s390_handle_e5(struct kvm_vcpu *vcpu); - -/* implemented in sigp.c */ -int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu); - -/* implemented in kvm-s390.c */ -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); - -#endif diff --git a/ANDROID_3.4.5/arch/s390/kvm/priv.c b/ANDROID_3.4.5/arch/s390/kvm/priv.c deleted file mode 100644 index e5a45dbd..00000000 --- a/ANDROID_3.4.5/arch/s390/kvm/priv.c +++ /dev/null @@ -1,382 +0,0 @@ -/* - * priv.c - handling privileged instructions - * - * Copyright IBM Corp. 2008 - * - * 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): Carsten Otte <cotte@de.ibm.com> - * Christian Borntraeger <borntraeger@de.ibm.com> - */ - -#include <linux/kvm.h> -#include <linux/gfp.h> -#include <linux/errno.h> -#include <asm/current.h> -#include <asm/debug.h> -#include <asm/ebcdic.h> -#include <asm/sysinfo.h> -#include "gaccess.h" -#include "kvm-s390.h" - -static int handle_set_prefix(struct kvm_vcpu *vcpu) -{ - int base2 = vcpu->arch.sie_block->ipb >> 28; - int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16); - u64 operand2; - u32 address = 0; - u8 tmp; - - vcpu->stat.instruction_spx++; - - operand2 = disp2; - if (base2) - operand2 += vcpu->run->s.regs.gprs[base2]; - - /* must be word boundary */ - if (operand2 & 3) { - kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); - goto out; - } - - /* get the value */ - if (get_guest_u32(vcpu, operand2, &address)) { - kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); - goto out; - } - - address = address & 0x7fffe000u; - - /* make sure that the new value is valid memory */ - if (copy_from_guest_absolute(vcpu, &tmp, address, 1) || - (copy_from_guest_absolute(vcpu, &tmp, address + PAGE_SIZE, 1))) { - kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); - goto out; - } - - kvm_s390_set_prefix(vcpu, address); - - VCPU_EVENT(vcpu, 5, "setting prefix to %x", address); -out: - return 0; -} - -static int handle_store_prefix(struct kvm_vcpu *vcpu) -{ - int base2 = vcpu->arch.sie_block->ipb >> 28; - int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16); - u64 operand2; - u32 address; - - vcpu->stat.instruction_stpx++; - operand2 = disp2; - if (base2) - operand2 += vcpu->run->s.regs.gprs[base2]; - - /* must be word boundary */ - if (operand2 & 3) { - kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); - goto out; - } - - address = vcpu->arch.sie_block->prefix; - address = address & 0x7fffe000u; - - /* get the value */ - if (put_guest_u32(vcpu, operand2, address)) { - kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); - goto out; - } - - VCPU_EVENT(vcpu, 5, "storing prefix to %x", address); -out: - return 0; -} - -static int handle_store_cpu_address(struct kvm_vcpu *vcpu) -{ - int base2 = vcpu->arch.sie_block->ipb >> 28; - int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16); - u64 useraddr; - int rc; - - vcpu->stat.instruction_stap++; - useraddr = disp2; - if (base2) - useraddr += vcpu->run->s.regs.gprs[base2]; - - if (useraddr & 1) { - kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); - goto out; - } - - rc = put_guest_u16(vcpu, useraddr, vcpu->vcpu_id); - if (rc == -EFAULT) { - kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); - goto out; - } - - VCPU_EVENT(vcpu, 5, "storing cpu address to %llx", useraddr); -out: - return 0; -} - -static int handle_skey(struct kvm_vcpu *vcpu) -{ - vcpu->stat.instruction_storage_key++; - vcpu->arch.sie_block->gpsw.addr -= 4; - VCPU_EVENT(vcpu, 4, "%s", "retrying storage key operation"); - return 0; -} - -static int handle_stsch(struct kvm_vcpu *vcpu) -{ - vcpu->stat.instruction_stsch++; - VCPU_EVENT(vcpu, 4, "%s", "store subchannel - CC3"); - /* condition code 3 */ - vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44); - vcpu->arch.sie_block->gpsw.mask |= (3 & 3ul) << 44; - return 0; -} - -static int handle_chsc(struct kvm_vcpu *vcpu) -{ - vcpu->stat.instruction_chsc++; - VCPU_EVENT(vcpu, 4, "%s", "channel subsystem call - CC3"); - /* condition code 3 */ - vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44); - vcpu->arch.sie_block->gpsw.mask |= (3 & 3ul) << 44; - return 0; -} - -static int handle_stfl(struct kvm_vcpu *vcpu) -{ - unsigned int facility_list; - int rc; - - vcpu->stat.instruction_stfl++; - /* only pass the facility bits, which we can handle */ - facility_list = S390_lowcore.stfl_fac_list & 0xff00fff3; - - rc = copy_to_guest(vcpu, offsetof(struct _lowcore, stfl_fac_list), - &facility_list, sizeof(facility_list)); - if (rc == -EFAULT) - kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); - else - VCPU_EVENT(vcpu, 5, "store facility list value %x", - facility_list); - return 0; -} - -static int handle_stidp(struct kvm_vcpu *vcpu) -{ - int base2 = vcpu->arch.sie_block->ipb >> 28; - int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16); - u64 operand2; - int rc; - - vcpu->stat.instruction_stidp++; - operand2 = disp2; - if (base2) - operand2 += vcpu->run->s.regs.gprs[base2]; - - if (operand2 & 7) { - kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); - goto out; - } - - rc = put_guest_u64(vcpu, operand2, vcpu->arch.stidp_data); - if (rc == -EFAULT) { - kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); - goto out; - } - - VCPU_EVENT(vcpu, 5, "%s", "store cpu id"); -out: - return 0; -} - -static void handle_stsi_3_2_2(struct kvm_vcpu *vcpu, struct sysinfo_3_2_2 *mem) -{ - struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int; - int cpus = 0; - int n; - - spin_lock(&fi->lock); - for (n = 0; n < KVM_MAX_VCPUS; n++) - if (fi->local_int[n]) - cpus++; - spin_unlock(&fi->lock); - - /* deal with other level 3 hypervisors */ - if (stsi(mem, 3, 2, 2) == -ENOSYS) - mem->count = 0; - if (mem->count < 8) - mem->count++; - for (n = mem->count - 1; n > 0 ; n--) - memcpy(&mem->vm[n], &mem->vm[n - 1], sizeof(mem->vm[0])); - - mem->vm[0].cpus_total = cpus; - mem->vm[0].cpus_configured = cpus; - mem->vm[0].cpus_standby = 0; - mem->vm[0].cpus_reserved = 0; - mem->vm[0].caf = 1000; - memcpy(mem->vm[0].name, "KVMguest", 8); - ASCEBC(mem->vm[0].name, 8); - memcpy(mem->vm[0].cpi, "KVM/Linux ", 16); - ASCEBC(mem->vm[0].cpi, 16); -} - -static int handle_stsi(struct kvm_vcpu *vcpu) -{ - int fc = (vcpu->run->s.regs.gprs[0] & 0xf0000000) >> 28; - int sel1 = vcpu->run->s.regs.gprs[0] & 0xff; - int sel2 = vcpu->run->s.regs.gprs[1] & 0xffff; - int base2 = vcpu->arch.sie_block->ipb >> 28; - int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16); - u64 operand2; - unsigned long mem; - - vcpu->stat.instruction_stsi++; - VCPU_EVENT(vcpu, 4, "stsi: fc: %x sel1: %x sel2: %x", fc, sel1, sel2); - - operand2 = disp2; - if (base2) - operand2 += vcpu->run->s.regs.gprs[base2]; - - if (operand2 & 0xfff && fc > 0) - return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); - - switch (fc) { - case 0: - vcpu->run->s.regs.gprs[0] = 3 << 28; - vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44); - return 0; - case 1: /* same handling for 1 and 2 */ - case 2: - mem = get_zeroed_page(GFP_KERNEL); - if (!mem) - goto out_fail; - if (stsi((void *) mem, fc, sel1, sel2) == -ENOSYS) - goto out_mem; - break; - case 3: - if (sel1 != 2 || sel2 != 2) - goto out_fail; - mem = get_zeroed_page(GFP_KERNEL); - if (!mem) - goto out_fail; - handle_stsi_3_2_2(vcpu, (void *) mem); - break; - default: - goto out_fail; - } - - if (copy_to_guest_absolute(vcpu, operand2, (void *) mem, PAGE_SIZE)) { - kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); - goto out_mem; - } - free_page(mem); - vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44); - vcpu->run->s.regs.gprs[0] = 0; - return 0; -out_mem: - free_page(mem); -out_fail: - /* condition code 3 */ - vcpu->arch.sie_block->gpsw.mask |= 3ul << 44; - return 0; -} - -static intercept_handler_t priv_handlers[256] = { - [0x02] = handle_stidp, - [0x10] = handle_set_prefix, - [0x11] = handle_store_prefix, - [0x12] = handle_store_cpu_address, - [0x29] = handle_skey, - [0x2a] = handle_skey, - [0x2b] = handle_skey, - [0x34] = handle_stsch, - [0x5f] = handle_chsc, - [0x7d] = handle_stsi, - [0xb1] = handle_stfl, -}; - -int kvm_s390_handle_b2(struct kvm_vcpu *vcpu) -{ - intercept_handler_t handler; - - /* - * a lot of B2 instructions are priviledged. We first check for - * the privileged ones, that we can handle in the kernel. If the - * kernel can handle this instruction, we check for the problem - * state bit and (a) handle the instruction or (b) send a code 2 - * program check. - * Anything else goes to userspace.*/ - handler = priv_handlers[vcpu->arch.sie_block->ipa & 0x00ff]; - if (handler) { - if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) - return kvm_s390_inject_program_int(vcpu, - PGM_PRIVILEGED_OPERATION); - else - return handler(vcpu); - } - return -EOPNOTSUPP; -} - -static int handle_tprot(struct kvm_vcpu *vcpu) -{ - int base1 = (vcpu->arch.sie_block->ipb & 0xf0000000) >> 28; - int disp1 = (vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16; - int base2 = (vcpu->arch.sie_block->ipb & 0xf000) >> 12; - int disp2 = vcpu->arch.sie_block->ipb & 0x0fff; - u64 address1 = disp1 + base1 ? vcpu->run->s.regs.gprs[base1] : 0; - u64 address2 = disp2 + base2 ? vcpu->run->s.regs.gprs[base2] : 0; - struct vm_area_struct *vma; - unsigned long user_address; - - vcpu->stat.instruction_tprot++; - - /* we only handle the Linux memory detection case: - * access key == 0 - * guest DAT == off - * everything else goes to userspace. */ - if (address2 & 0xf0) - return -EOPNOTSUPP; - if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_DAT) - return -EOPNOTSUPP; - - - /* we must resolve the address without holding the mmap semaphore. - * This is ok since the userspace hypervisor is not supposed to change - * the mapping while the guest queries the memory. Otherwise the guest - * might crash or get wrong info anyway. */ - user_address = (unsigned long) __guestaddr_to_user(vcpu, address1); - - down_read(¤t->mm->mmap_sem); - vma = find_vma(current->mm, user_address); - if (!vma) { - up_read(¤t->mm->mmap_sem); - return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); - } - - vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44); - if (!(vma->vm_flags & VM_WRITE) && (vma->vm_flags & VM_READ)) - vcpu->arch.sie_block->gpsw.mask |= (1ul << 44); - if (!(vma->vm_flags & VM_WRITE) && !(vma->vm_flags & VM_READ)) - vcpu->arch.sie_block->gpsw.mask |= (2ul << 44); - - up_read(¤t->mm->mmap_sem); - return 0; -} - -int kvm_s390_handle_e5(struct kvm_vcpu *vcpu) -{ - /* For e5xx... instructions we only handle TPROT */ - if ((vcpu->arch.sie_block->ipa & 0x00ff) == 0x01) - return handle_tprot(vcpu); - return -EOPNOTSUPP; -} - diff --git a/ANDROID_3.4.5/arch/s390/kvm/sigp.c b/ANDROID_3.4.5/arch/s390/kvm/sigp.c deleted file mode 100644 index 0ad4cf23..00000000 --- a/ANDROID_3.4.5/arch/s390/kvm/sigp.c +++ /dev/null @@ -1,421 +0,0 @@ -/* - * sigp.c - handlinge interprocessor communication - * - * Copyright IBM Corp. 2008,2009 - * - * 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): Carsten Otte <cotte@de.ibm.com> - * Christian Borntraeger <borntraeger@de.ibm.com> - * Christian Ehrhardt <ehrhardt@de.ibm.com> - */ - -#include <linux/kvm.h> -#include <linux/kvm_host.h> -#include <linux/slab.h> -#include "gaccess.h" -#include "kvm-s390.h" - -/* sigp order codes */ -#define SIGP_SENSE 0x01 -#define SIGP_EXTERNAL_CALL 0x02 -#define SIGP_EMERGENCY 0x03 -#define SIGP_START 0x04 -#define SIGP_STOP 0x05 -#define SIGP_RESTART 0x06 -#define SIGP_STOP_STORE_STATUS 0x09 -#define SIGP_INITIAL_CPU_RESET 0x0b -#define SIGP_CPU_RESET 0x0c -#define SIGP_SET_PREFIX 0x0d -#define SIGP_STORE_STATUS_ADDR 0x0e -#define SIGP_SET_ARCH 0x12 -#define SIGP_SENSE_RUNNING 0x15 - -/* cpu status bits */ -#define SIGP_STAT_EQUIPMENT_CHECK 0x80000000UL -#define SIGP_STAT_NOT_RUNNING 0x00000400UL -#define SIGP_STAT_INCORRECT_STATE 0x00000200UL -#define SIGP_STAT_INVALID_PARAMETER 0x00000100UL -#define SIGP_STAT_EXT_CALL_PENDING 0x00000080UL -#define SIGP_STAT_STOPPED 0x00000040UL -#define SIGP_STAT_OPERATOR_INTERV 0x00000020UL -#define SIGP_STAT_CHECK_STOP 0x00000010UL -#define SIGP_STAT_INOPERATIVE 0x00000004UL -#define SIGP_STAT_INVALID_ORDER 0x00000002UL -#define SIGP_STAT_RECEIVER_CHECK 0x00000001UL - - -static int __sigp_sense(struct kvm_vcpu *vcpu, u16 cpu_addr, - u64 *reg) -{ - struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int; - int rc; - - if (cpu_addr >= KVM_MAX_VCPUS) - return 3; /* not operational */ - - spin_lock(&fi->lock); - if (fi->local_int[cpu_addr] == NULL) - rc = 3; /* not operational */ - else if (!(atomic_read(fi->local_int[cpu_addr]->cpuflags) - & CPUSTAT_STOPPED)) { - *reg &= 0xffffffff00000000UL; - rc = 1; /* status stored */ - } else { - *reg &= 0xffffffff00000000UL; - *reg |= SIGP_STAT_STOPPED; - rc = 1; /* status stored */ - } - spin_unlock(&fi->lock); - - VCPU_EVENT(vcpu, 4, "sensed status of cpu %x rc %x", cpu_addr, rc); - return rc; -} - -static int __sigp_emergency(struct kvm_vcpu *vcpu, u16 cpu_addr) -{ - struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int; - struct kvm_s390_local_interrupt *li; - struct kvm_s390_interrupt_info *inti; - int rc; - - if (cpu_addr >= KVM_MAX_VCPUS) - return 3; /* not operational */ - - inti = kzalloc(sizeof(*inti), GFP_KERNEL); - if (!inti) - return -ENOMEM; - - inti->type = KVM_S390_INT_EMERGENCY; - inti->emerg.code = vcpu->vcpu_id; - - spin_lock(&fi->lock); - li = fi->local_int[cpu_addr]; - if (li == NULL) { - rc = 3; /* not operational */ - kfree(inti); - goto unlock; - } - spin_lock_bh(&li->lock); - list_add_tail(&inti->list, &li->list); - atomic_set(&li->active, 1); - atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags); - if (waitqueue_active(&li->wq)) - wake_up_interruptible(&li->wq); - spin_unlock_bh(&li->lock); - rc = 0; /* order accepted */ - VCPU_EVENT(vcpu, 4, "sent sigp emerg to cpu %x", cpu_addr); -unlock: - spin_unlock(&fi->lock); - return rc; -} - -static int __sigp_external_call(struct kvm_vcpu *vcpu, u16 cpu_addr) -{ - struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int; - struct kvm_s390_local_interrupt *li; - struct kvm_s390_interrupt_info *inti; - int rc; - - if (cpu_addr >= KVM_MAX_VCPUS) - return 3; /* not operational */ - - inti = kzalloc(sizeof(*inti), GFP_KERNEL); - if (!inti) - return -ENOMEM; - - inti->type = KVM_S390_INT_EXTERNAL_CALL; - inti->extcall.code = vcpu->vcpu_id; - - spin_lock(&fi->lock); - li = fi->local_int[cpu_addr]; - if (li == NULL) { - rc = 3; /* not operational */ - kfree(inti); - goto unlock; - } - spin_lock_bh(&li->lock); - list_add_tail(&inti->list, &li->list); - atomic_set(&li->active, 1); - atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags); - if (waitqueue_active(&li->wq)) - wake_up_interruptible(&li->wq); - spin_unlock_bh(&li->lock); - rc = 0; /* order accepted */ - VCPU_EVENT(vcpu, 4, "sent sigp ext call to cpu %x", cpu_addr); -unlock: - spin_unlock(&fi->lock); - return rc; -} - -static int __inject_sigp_stop(struct kvm_s390_local_interrupt *li, int action) -{ - struct kvm_s390_interrupt_info *inti; - - inti = kzalloc(sizeof(*inti), GFP_ATOMIC); - if (!inti) - return -ENOMEM; - inti->type = KVM_S390_SIGP_STOP; - - spin_lock_bh(&li->lock); - if ((atomic_read(li->cpuflags) & CPUSTAT_STOPPED)) - goto out; - list_add_tail(&inti->list, &li->list); - atomic_set(&li->active, 1); - atomic_set_mask(CPUSTAT_STOP_INT, li->cpuflags); - li->action_bits |= action; - if (waitqueue_active(&li->wq)) - wake_up_interruptible(&li->wq); -out: - spin_unlock_bh(&li->lock); - - return 0; /* order accepted */ -} - -static int __sigp_stop(struct kvm_vcpu *vcpu, u16 cpu_addr, int action) -{ - struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int; - struct kvm_s390_local_interrupt *li; - int rc; - - if (cpu_addr >= KVM_MAX_VCPUS) - return 3; /* not operational */ - - spin_lock(&fi->lock); - li = fi->local_int[cpu_addr]; - if (li == NULL) { - rc = 3; /* not operational */ - goto unlock; - } - - rc = __inject_sigp_stop(li, action); - -unlock: - spin_unlock(&fi->lock); - VCPU_EVENT(vcpu, 4, "sent sigp stop to cpu %x", cpu_addr); - return rc; -} - -int kvm_s390_inject_sigp_stop(struct kvm_vcpu *vcpu, int action) -{ - struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; - return __inject_sigp_stop(li, action); -} - -static int __sigp_set_arch(struct kvm_vcpu *vcpu, u32 parameter) -{ - int rc; - - switch (parameter & 0xff) { - case 0: - rc = 3; /* not operational */ - break; - case 1: - case 2: - rc = 0; /* order accepted */ - break; - default: - rc = -EOPNOTSUPP; - } - return rc; -} - -static int __sigp_set_prefix(struct kvm_vcpu *vcpu, u16 cpu_addr, u32 address, - u64 *reg) -{ - struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int; - struct kvm_s390_local_interrupt *li = NULL; - struct kvm_s390_interrupt_info *inti; - int rc; - u8 tmp; - - /* make sure that the new value is valid memory */ - address = address & 0x7fffe000u; - if (copy_from_guest_absolute(vcpu, &tmp, address, 1) || - copy_from_guest_absolute(vcpu, &tmp, address + PAGE_SIZE, 1)) { - *reg |= SIGP_STAT_INVALID_PARAMETER; - return 1; /* invalid parameter */ - } - - inti = kzalloc(sizeof(*inti), GFP_KERNEL); - if (!inti) - return 2; /* busy */ - - spin_lock(&fi->lock); - if (cpu_addr < KVM_MAX_VCPUS) - li = fi->local_int[cpu_addr]; - - if (li == NULL) { - rc = 1; /* incorrect state */ - *reg &= SIGP_STAT_INCORRECT_STATE; - kfree(inti); - goto out_fi; - } - - spin_lock_bh(&li->lock); - /* cpu must be in stopped state */ - if (!(atomic_read(li->cpuflags) & CPUSTAT_STOPPED)) { - rc = 1; /* incorrect state */ - *reg &= SIGP_STAT_INCORRECT_STATE; - kfree(inti); - goto out_li; - } - - inti->type = KVM_S390_SIGP_SET_PREFIX; - inti->prefix.address = address; - - list_add_tail(&inti->list, &li->list); - atomic_set(&li->active, 1); - if (waitqueue_active(&li->wq)) - wake_up_interruptible(&li->wq); - rc = 0; /* order accepted */ - - VCPU_EVENT(vcpu, 4, "set prefix of cpu %02x to %x", cpu_addr, address); -out_li: - spin_unlock_bh(&li->lock); -out_fi: - spin_unlock(&fi->lock); - return rc; -} - -static int __sigp_sense_running(struct kvm_vcpu *vcpu, u16 cpu_addr, - u64 *reg) -{ - int rc; - struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int; - - if (cpu_addr >= KVM_MAX_VCPUS) - return 3; /* not operational */ - - spin_lock(&fi->lock); - if (fi->local_int[cpu_addr] == NULL) - rc = 3; /* not operational */ - else { - if (atomic_read(fi->local_int[cpu_addr]->cpuflags) - & CPUSTAT_RUNNING) { - /* running */ - rc = 1; - } else { - /* not running */ - *reg &= 0xffffffff00000000UL; - *reg |= SIGP_STAT_NOT_RUNNING; - rc = 0; - } - } - spin_unlock(&fi->lock); - - VCPU_EVENT(vcpu, 4, "sensed running status of cpu %x rc %x", cpu_addr, - rc); - - return rc; -} - -static int __sigp_restart(struct kvm_vcpu *vcpu, u16 cpu_addr) -{ - int rc = 0; - struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int; - struct kvm_s390_local_interrupt *li; - - if (cpu_addr >= KVM_MAX_VCPUS) - return 3; /* not operational */ - - spin_lock(&fi->lock); - li = fi->local_int[cpu_addr]; - if (li == NULL) { - rc = 3; /* not operational */ - goto out; - } - - spin_lock_bh(&li->lock); - if (li->action_bits & ACTION_STOP_ON_STOP) - rc = 2; /* busy */ - else - VCPU_EVENT(vcpu, 4, "sigp restart %x to handle userspace", - cpu_addr); - spin_unlock_bh(&li->lock); -out: - spin_unlock(&fi->lock); - return rc; -} - -int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu) -{ - int r1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4; - int r3 = vcpu->arch.sie_block->ipa & 0x000f; - int base2 = vcpu->arch.sie_block->ipb >> 28; - int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16); - u32 parameter; - u16 cpu_addr = vcpu->run->s.regs.gprs[r3]; - u8 order_code; - int rc; - - /* sigp in userspace can exit */ - if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) - return kvm_s390_inject_program_int(vcpu, - PGM_PRIVILEGED_OPERATION); - - order_code = disp2; - if (base2) - order_code += vcpu->run->s.regs.gprs[base2]; - - if (r1 % 2) - parameter = vcpu->run->s.regs.gprs[r1]; - else - parameter = vcpu->run->s.regs.gprs[r1 + 1]; - - switch (order_code) { - case SIGP_SENSE: - vcpu->stat.instruction_sigp_sense++; - rc = __sigp_sense(vcpu, cpu_addr, - &vcpu->run->s.regs.gprs[r1]); - break; - case SIGP_EXTERNAL_CALL: - vcpu->stat.instruction_sigp_external_call++; - rc = __sigp_external_call(vcpu, cpu_addr); - break; - case SIGP_EMERGENCY: - vcpu->stat.instruction_sigp_emergency++; - rc = __sigp_emergency(vcpu, cpu_addr); - break; - case SIGP_STOP: - vcpu->stat.instruction_sigp_stop++; - rc = __sigp_stop(vcpu, cpu_addr, ACTION_STOP_ON_STOP); - break; - case SIGP_STOP_STORE_STATUS: - vcpu->stat.instruction_sigp_stop++; - rc = __sigp_stop(vcpu, cpu_addr, ACTION_STORE_ON_STOP | - ACTION_STOP_ON_STOP); - break; - case SIGP_SET_ARCH: - vcpu->stat.instruction_sigp_arch++; - rc = __sigp_set_arch(vcpu, parameter); - break; - case SIGP_SET_PREFIX: - vcpu->stat.instruction_sigp_prefix++; - rc = __sigp_set_prefix(vcpu, cpu_addr, parameter, - &vcpu->run->s.regs.gprs[r1]); - break; - case SIGP_SENSE_RUNNING: - vcpu->stat.instruction_sigp_sense_running++; - rc = __sigp_sense_running(vcpu, cpu_addr, - &vcpu->run->s.regs.gprs[r1]); - break; - case SIGP_RESTART: - vcpu->stat.instruction_sigp_restart++; - rc = __sigp_restart(vcpu, cpu_addr); - if (rc == 2) /* busy */ - break; - /* user space must know about restart */ - default: - return -EOPNOTSUPP; - } - - if (rc < 0) - return rc; - - vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44); - vcpu->arch.sie_block->gpsw.mask |= (rc & 3ul) << 44; - return 0; -} |