diff options
Diffstat (limited to 'ANDROID_3.4.5/arch/s390/kvm/priv.c')
-rw-r--r-- | ANDROID_3.4.5/arch/s390/kvm/priv.c | 382 |
1 files changed, 0 insertions, 382 deletions
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; -} - |