/*
 * 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"
#include "trace.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);
	trace_kvm_s390_handle_prefix(vcpu, 1, 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);
	trace_kvm_s390_handle_prefix(vcpu, 0, 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);
	trace_kvm_s390_handle_stap(vcpu, 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);
		trace_kvm_s390_handle_stfl(vcpu, 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))
		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))
			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;
	}
	trace_kvm_s390_handle_stsi(vcpu, fc, sel1, sel2, operand2);
	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(&current->mm->mmap_sem);
	vma = find_vma(current->mm, user_address);
	if (!vma) {
		up_read(&current->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(&current->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;
}

static int handle_sckpf(struct kvm_vcpu *vcpu)
{
	u32 value;

	if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
		return kvm_s390_inject_program_int(vcpu,
						   PGM_PRIVILEGED_OPERATION);

	if (vcpu->run->s.regs.gprs[0] & 0x00000000ffff0000)
		return kvm_s390_inject_program_int(vcpu,
						   PGM_SPECIFICATION);

	value = vcpu->run->s.regs.gprs[0] & 0x000000000000ffff;
	vcpu->arch.sie_block->todpr = value;

	return 0;
}

static intercept_handler_t x01_handlers[256] = {
	[0x07] = handle_sckpf,
};

int kvm_s390_handle_01(struct kvm_vcpu *vcpu)
{
	intercept_handler_t handler;

	handler = x01_handlers[vcpu->arch.sie_block->ipa & 0x00ff];
	if (handler)
		return handler(vcpu);
	return -EOPNOTSUPP;
}
