162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
362306a36Sopenharmony_ci * License.  See the file "COPYING" in the main directory of this archive
462306a36Sopenharmony_ci * for more details.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * KVM/MIPS: Instruction/Exception emulation
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Copyright (C) 2012  MIPS Technologies, Inc.  All rights reserved.
962306a36Sopenharmony_ci * Authors: Sanjay Lal <sanjayl@kymasys.com>
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <linux/errno.h>
1362306a36Sopenharmony_ci#include <linux/err.h>
1462306a36Sopenharmony_ci#include <linux/ktime.h>
1562306a36Sopenharmony_ci#include <linux/kvm_host.h>
1662306a36Sopenharmony_ci#include <linux/vmalloc.h>
1762306a36Sopenharmony_ci#include <linux/fs.h>
1862306a36Sopenharmony_ci#include <linux/memblock.h>
1962306a36Sopenharmony_ci#include <linux/random.h>
2062306a36Sopenharmony_ci#include <asm/page.h>
2162306a36Sopenharmony_ci#include <asm/cacheflush.h>
2262306a36Sopenharmony_ci#include <asm/cacheops.h>
2362306a36Sopenharmony_ci#include <asm/cpu-info.h>
2462306a36Sopenharmony_ci#include <asm/mmu_context.h>
2562306a36Sopenharmony_ci#include <asm/tlbflush.h>
2662306a36Sopenharmony_ci#include <asm/inst.h>
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#undef CONFIG_MIPS_MT
2962306a36Sopenharmony_ci#include <asm/r4kcache.h>
3062306a36Sopenharmony_ci#define CONFIG_MIPS_MT
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#include "interrupt.h"
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci#include "trace.h"
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci/*
3762306a36Sopenharmony_ci * Compute the return address and do emulate branch simulation, if required.
3862306a36Sopenharmony_ci * This function should be called only in branch delay slot active.
3962306a36Sopenharmony_ci */
4062306a36Sopenharmony_cistatic int kvm_compute_return_epc(struct kvm_vcpu *vcpu, unsigned long instpc,
4162306a36Sopenharmony_ci				  unsigned long *out)
4262306a36Sopenharmony_ci{
4362306a36Sopenharmony_ci	unsigned int dspcontrol;
4462306a36Sopenharmony_ci	union mips_instruction insn;
4562306a36Sopenharmony_ci	struct kvm_vcpu_arch *arch = &vcpu->arch;
4662306a36Sopenharmony_ci	long epc = instpc;
4762306a36Sopenharmony_ci	long nextpc;
4862306a36Sopenharmony_ci	int err;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	if (epc & 3) {
5162306a36Sopenharmony_ci		kvm_err("%s: unaligned epc\n", __func__);
5262306a36Sopenharmony_ci		return -EINVAL;
5362306a36Sopenharmony_ci	}
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	/* Read the instruction */
5662306a36Sopenharmony_ci	err = kvm_get_badinstrp((u32 *)epc, vcpu, &insn.word);
5762306a36Sopenharmony_ci	if (err)
5862306a36Sopenharmony_ci		return err;
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	switch (insn.i_format.opcode) {
6162306a36Sopenharmony_ci		/* jr and jalr are in r_format format. */
6262306a36Sopenharmony_ci	case spec_op:
6362306a36Sopenharmony_ci		switch (insn.r_format.func) {
6462306a36Sopenharmony_ci		case jalr_op:
6562306a36Sopenharmony_ci			arch->gprs[insn.r_format.rd] = epc + 8;
6662306a36Sopenharmony_ci			fallthrough;
6762306a36Sopenharmony_ci		case jr_op:
6862306a36Sopenharmony_ci			nextpc = arch->gprs[insn.r_format.rs];
6962306a36Sopenharmony_ci			break;
7062306a36Sopenharmony_ci		default:
7162306a36Sopenharmony_ci			return -EINVAL;
7262306a36Sopenharmony_ci		}
7362306a36Sopenharmony_ci		break;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci		/*
7662306a36Sopenharmony_ci		 * This group contains:
7762306a36Sopenharmony_ci		 * bltz_op, bgez_op, bltzl_op, bgezl_op,
7862306a36Sopenharmony_ci		 * bltzal_op, bgezal_op, bltzall_op, bgezall_op.
7962306a36Sopenharmony_ci		 */
8062306a36Sopenharmony_ci	case bcond_op:
8162306a36Sopenharmony_ci		switch (insn.i_format.rt) {
8262306a36Sopenharmony_ci		case bltz_op:
8362306a36Sopenharmony_ci		case bltzl_op:
8462306a36Sopenharmony_ci			if ((long)arch->gprs[insn.i_format.rs] < 0)
8562306a36Sopenharmony_ci				epc = epc + 4 + (insn.i_format.simmediate << 2);
8662306a36Sopenharmony_ci			else
8762306a36Sopenharmony_ci				epc += 8;
8862306a36Sopenharmony_ci			nextpc = epc;
8962306a36Sopenharmony_ci			break;
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci		case bgez_op:
9262306a36Sopenharmony_ci		case bgezl_op:
9362306a36Sopenharmony_ci			if ((long)arch->gprs[insn.i_format.rs] >= 0)
9462306a36Sopenharmony_ci				epc = epc + 4 + (insn.i_format.simmediate << 2);
9562306a36Sopenharmony_ci			else
9662306a36Sopenharmony_ci				epc += 8;
9762306a36Sopenharmony_ci			nextpc = epc;
9862306a36Sopenharmony_ci			break;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci		case bltzal_op:
10162306a36Sopenharmony_ci		case bltzall_op:
10262306a36Sopenharmony_ci			arch->gprs[31] = epc + 8;
10362306a36Sopenharmony_ci			if ((long)arch->gprs[insn.i_format.rs] < 0)
10462306a36Sopenharmony_ci				epc = epc + 4 + (insn.i_format.simmediate << 2);
10562306a36Sopenharmony_ci			else
10662306a36Sopenharmony_ci				epc += 8;
10762306a36Sopenharmony_ci			nextpc = epc;
10862306a36Sopenharmony_ci			break;
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci		case bgezal_op:
11162306a36Sopenharmony_ci		case bgezall_op:
11262306a36Sopenharmony_ci			arch->gprs[31] = epc + 8;
11362306a36Sopenharmony_ci			if ((long)arch->gprs[insn.i_format.rs] >= 0)
11462306a36Sopenharmony_ci				epc = epc + 4 + (insn.i_format.simmediate << 2);
11562306a36Sopenharmony_ci			else
11662306a36Sopenharmony_ci				epc += 8;
11762306a36Sopenharmony_ci			nextpc = epc;
11862306a36Sopenharmony_ci			break;
11962306a36Sopenharmony_ci		case bposge32_op:
12062306a36Sopenharmony_ci			if (!cpu_has_dsp) {
12162306a36Sopenharmony_ci				kvm_err("%s: DSP branch but not DSP ASE\n",
12262306a36Sopenharmony_ci					__func__);
12362306a36Sopenharmony_ci				return -EINVAL;
12462306a36Sopenharmony_ci			}
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci			dspcontrol = rddsp(0x01);
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci			if (dspcontrol >= 32)
12962306a36Sopenharmony_ci				epc = epc + 4 + (insn.i_format.simmediate << 2);
13062306a36Sopenharmony_ci			else
13162306a36Sopenharmony_ci				epc += 8;
13262306a36Sopenharmony_ci			nextpc = epc;
13362306a36Sopenharmony_ci			break;
13462306a36Sopenharmony_ci		default:
13562306a36Sopenharmony_ci			return -EINVAL;
13662306a36Sopenharmony_ci		}
13762306a36Sopenharmony_ci		break;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci		/* These are unconditional and in j_format. */
14062306a36Sopenharmony_ci	case jal_op:
14162306a36Sopenharmony_ci		arch->gprs[31] = instpc + 8;
14262306a36Sopenharmony_ci		fallthrough;
14362306a36Sopenharmony_ci	case j_op:
14462306a36Sopenharmony_ci		epc += 4;
14562306a36Sopenharmony_ci		epc >>= 28;
14662306a36Sopenharmony_ci		epc <<= 28;
14762306a36Sopenharmony_ci		epc |= (insn.j_format.target << 2);
14862306a36Sopenharmony_ci		nextpc = epc;
14962306a36Sopenharmony_ci		break;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci		/* These are conditional and in i_format. */
15262306a36Sopenharmony_ci	case beq_op:
15362306a36Sopenharmony_ci	case beql_op:
15462306a36Sopenharmony_ci		if (arch->gprs[insn.i_format.rs] ==
15562306a36Sopenharmony_ci		    arch->gprs[insn.i_format.rt])
15662306a36Sopenharmony_ci			epc = epc + 4 + (insn.i_format.simmediate << 2);
15762306a36Sopenharmony_ci		else
15862306a36Sopenharmony_ci			epc += 8;
15962306a36Sopenharmony_ci		nextpc = epc;
16062306a36Sopenharmony_ci		break;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	case bne_op:
16362306a36Sopenharmony_ci	case bnel_op:
16462306a36Sopenharmony_ci		if (arch->gprs[insn.i_format.rs] !=
16562306a36Sopenharmony_ci		    arch->gprs[insn.i_format.rt])
16662306a36Sopenharmony_ci			epc = epc + 4 + (insn.i_format.simmediate << 2);
16762306a36Sopenharmony_ci		else
16862306a36Sopenharmony_ci			epc += 8;
16962306a36Sopenharmony_ci		nextpc = epc;
17062306a36Sopenharmony_ci		break;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	case blez_op:	/* POP06 */
17362306a36Sopenharmony_ci#ifndef CONFIG_CPU_MIPSR6
17462306a36Sopenharmony_ci	case blezl_op:	/* removed in R6 */
17562306a36Sopenharmony_ci#endif
17662306a36Sopenharmony_ci		if (insn.i_format.rt != 0)
17762306a36Sopenharmony_ci			goto compact_branch;
17862306a36Sopenharmony_ci		if ((long)arch->gprs[insn.i_format.rs] <= 0)
17962306a36Sopenharmony_ci			epc = epc + 4 + (insn.i_format.simmediate << 2);
18062306a36Sopenharmony_ci		else
18162306a36Sopenharmony_ci			epc += 8;
18262306a36Sopenharmony_ci		nextpc = epc;
18362306a36Sopenharmony_ci		break;
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	case bgtz_op:	/* POP07 */
18662306a36Sopenharmony_ci#ifndef CONFIG_CPU_MIPSR6
18762306a36Sopenharmony_ci	case bgtzl_op:	/* removed in R6 */
18862306a36Sopenharmony_ci#endif
18962306a36Sopenharmony_ci		if (insn.i_format.rt != 0)
19062306a36Sopenharmony_ci			goto compact_branch;
19162306a36Sopenharmony_ci		if ((long)arch->gprs[insn.i_format.rs] > 0)
19262306a36Sopenharmony_ci			epc = epc + 4 + (insn.i_format.simmediate << 2);
19362306a36Sopenharmony_ci		else
19462306a36Sopenharmony_ci			epc += 8;
19562306a36Sopenharmony_ci		nextpc = epc;
19662306a36Sopenharmony_ci		break;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci		/* And now the FPA/cp1 branch instructions. */
19962306a36Sopenharmony_ci	case cop1_op:
20062306a36Sopenharmony_ci		kvm_err("%s: unsupported cop1_op\n", __func__);
20162306a36Sopenharmony_ci		return -EINVAL;
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci#ifdef CONFIG_CPU_MIPSR6
20462306a36Sopenharmony_ci	/* R6 added the following compact branches with forbidden slots */
20562306a36Sopenharmony_ci	case blezl_op:	/* POP26 */
20662306a36Sopenharmony_ci	case bgtzl_op:	/* POP27 */
20762306a36Sopenharmony_ci		/* only rt == 0 isn't compact branch */
20862306a36Sopenharmony_ci		if (insn.i_format.rt != 0)
20962306a36Sopenharmony_ci			goto compact_branch;
21062306a36Sopenharmony_ci		return -EINVAL;
21162306a36Sopenharmony_ci	case pop10_op:
21262306a36Sopenharmony_ci	case pop30_op:
21362306a36Sopenharmony_ci		/* only rs == rt == 0 is reserved, rest are compact branches */
21462306a36Sopenharmony_ci		if (insn.i_format.rs != 0 || insn.i_format.rt != 0)
21562306a36Sopenharmony_ci			goto compact_branch;
21662306a36Sopenharmony_ci		return -EINVAL;
21762306a36Sopenharmony_ci	case pop66_op:
21862306a36Sopenharmony_ci	case pop76_op:
21962306a36Sopenharmony_ci		/* only rs == 0 isn't compact branch */
22062306a36Sopenharmony_ci		if (insn.i_format.rs != 0)
22162306a36Sopenharmony_ci			goto compact_branch;
22262306a36Sopenharmony_ci		return -EINVAL;
22362306a36Sopenharmony_cicompact_branch:
22462306a36Sopenharmony_ci		/*
22562306a36Sopenharmony_ci		 * If we've hit an exception on the forbidden slot, then
22662306a36Sopenharmony_ci		 * the branch must not have been taken.
22762306a36Sopenharmony_ci		 */
22862306a36Sopenharmony_ci		epc += 8;
22962306a36Sopenharmony_ci		nextpc = epc;
23062306a36Sopenharmony_ci		break;
23162306a36Sopenharmony_ci#else
23262306a36Sopenharmony_cicompact_branch:
23362306a36Sopenharmony_ci		/* Fall through - Compact branches not supported before R6 */
23462306a36Sopenharmony_ci#endif
23562306a36Sopenharmony_ci	default:
23662306a36Sopenharmony_ci		return -EINVAL;
23762306a36Sopenharmony_ci	}
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	*out = nextpc;
24062306a36Sopenharmony_ci	return 0;
24162306a36Sopenharmony_ci}
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_cienum emulation_result update_pc(struct kvm_vcpu *vcpu, u32 cause)
24462306a36Sopenharmony_ci{
24562306a36Sopenharmony_ci	int err;
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	if (cause & CAUSEF_BD) {
24862306a36Sopenharmony_ci		err = kvm_compute_return_epc(vcpu, vcpu->arch.pc,
24962306a36Sopenharmony_ci					     &vcpu->arch.pc);
25062306a36Sopenharmony_ci		if (err)
25162306a36Sopenharmony_ci			return EMULATE_FAIL;
25262306a36Sopenharmony_ci	} else {
25362306a36Sopenharmony_ci		vcpu->arch.pc += 4;
25462306a36Sopenharmony_ci	}
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	kvm_debug("update_pc(): New PC: %#lx\n", vcpu->arch.pc);
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	return EMULATE_DONE;
25962306a36Sopenharmony_ci}
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci/**
26262306a36Sopenharmony_ci * kvm_get_badinstr() - Get bad instruction encoding.
26362306a36Sopenharmony_ci * @opc:	Guest pointer to faulting instruction.
26462306a36Sopenharmony_ci * @vcpu:	KVM VCPU information.
26562306a36Sopenharmony_ci *
26662306a36Sopenharmony_ci * Gets the instruction encoding of the faulting instruction, using the saved
26762306a36Sopenharmony_ci * BadInstr register value if it exists, otherwise falling back to reading guest
26862306a36Sopenharmony_ci * memory at @opc.
26962306a36Sopenharmony_ci *
27062306a36Sopenharmony_ci * Returns:	The instruction encoding of the faulting instruction.
27162306a36Sopenharmony_ci */
27262306a36Sopenharmony_ciint kvm_get_badinstr(u32 *opc, struct kvm_vcpu *vcpu, u32 *out)
27362306a36Sopenharmony_ci{
27462306a36Sopenharmony_ci	if (cpu_has_badinstr) {
27562306a36Sopenharmony_ci		*out = vcpu->arch.host_cp0_badinstr;
27662306a36Sopenharmony_ci		return 0;
27762306a36Sopenharmony_ci	} else {
27862306a36Sopenharmony_ci		WARN_ONCE(1, "CPU doesn't have BadInstr register\n");
27962306a36Sopenharmony_ci		return -EINVAL;
28062306a36Sopenharmony_ci	}
28162306a36Sopenharmony_ci}
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci/**
28462306a36Sopenharmony_ci * kvm_get_badinstrp() - Get bad prior instruction encoding.
28562306a36Sopenharmony_ci * @opc:	Guest pointer to prior faulting instruction.
28662306a36Sopenharmony_ci * @vcpu:	KVM VCPU information.
28762306a36Sopenharmony_ci *
28862306a36Sopenharmony_ci * Gets the instruction encoding of the prior faulting instruction (the branch
28962306a36Sopenharmony_ci * containing the delay slot which faulted), using the saved BadInstrP register
29062306a36Sopenharmony_ci * value if it exists, otherwise falling back to reading guest memory at @opc.
29162306a36Sopenharmony_ci *
29262306a36Sopenharmony_ci * Returns:	The instruction encoding of the prior faulting instruction.
29362306a36Sopenharmony_ci */
29462306a36Sopenharmony_ciint kvm_get_badinstrp(u32 *opc, struct kvm_vcpu *vcpu, u32 *out)
29562306a36Sopenharmony_ci{
29662306a36Sopenharmony_ci	if (cpu_has_badinstrp) {
29762306a36Sopenharmony_ci		*out = vcpu->arch.host_cp0_badinstrp;
29862306a36Sopenharmony_ci		return 0;
29962306a36Sopenharmony_ci	} else {
30062306a36Sopenharmony_ci		WARN_ONCE(1, "CPU doesn't have BadInstrp register\n");
30162306a36Sopenharmony_ci		return -EINVAL;
30262306a36Sopenharmony_ci	}
30362306a36Sopenharmony_ci}
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci/**
30662306a36Sopenharmony_ci * kvm_mips_count_disabled() - Find whether the CP0_Count timer is disabled.
30762306a36Sopenharmony_ci * @vcpu:	Virtual CPU.
30862306a36Sopenharmony_ci *
30962306a36Sopenharmony_ci * Returns:	1 if the CP0_Count timer is disabled by either the guest
31062306a36Sopenharmony_ci *		CP0_Cause.DC bit or the count_ctl.DC bit.
31162306a36Sopenharmony_ci *		0 otherwise (in which case CP0_Count timer is running).
31262306a36Sopenharmony_ci */
31362306a36Sopenharmony_ciint kvm_mips_count_disabled(struct kvm_vcpu *vcpu)
31462306a36Sopenharmony_ci{
31562306a36Sopenharmony_ci	struct mips_coproc *cop0 = &vcpu->arch.cop0;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	return	(vcpu->arch.count_ctl & KVM_REG_MIPS_COUNT_CTL_DC) ||
31862306a36Sopenharmony_ci		(kvm_read_c0_guest_cause(cop0) & CAUSEF_DC);
31962306a36Sopenharmony_ci}
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci/**
32262306a36Sopenharmony_ci * kvm_mips_ktime_to_count() - Scale ktime_t to a 32-bit count.
32362306a36Sopenharmony_ci *
32462306a36Sopenharmony_ci * Caches the dynamic nanosecond bias in vcpu->arch.count_dyn_bias.
32562306a36Sopenharmony_ci *
32662306a36Sopenharmony_ci * Assumes !kvm_mips_count_disabled(@vcpu) (guest CP0_Count timer is running).
32762306a36Sopenharmony_ci */
32862306a36Sopenharmony_cistatic u32 kvm_mips_ktime_to_count(struct kvm_vcpu *vcpu, ktime_t now)
32962306a36Sopenharmony_ci{
33062306a36Sopenharmony_ci	s64 now_ns, periods;
33162306a36Sopenharmony_ci	u64 delta;
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	now_ns = ktime_to_ns(now);
33462306a36Sopenharmony_ci	delta = now_ns + vcpu->arch.count_dyn_bias;
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	if (delta >= vcpu->arch.count_period) {
33762306a36Sopenharmony_ci		/* If delta is out of safe range the bias needs adjusting */
33862306a36Sopenharmony_ci		periods = div64_s64(now_ns, vcpu->arch.count_period);
33962306a36Sopenharmony_ci		vcpu->arch.count_dyn_bias = -periods * vcpu->arch.count_period;
34062306a36Sopenharmony_ci		/* Recalculate delta with new bias */
34162306a36Sopenharmony_ci		delta = now_ns + vcpu->arch.count_dyn_bias;
34262306a36Sopenharmony_ci	}
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	/*
34562306a36Sopenharmony_ci	 * We've ensured that:
34662306a36Sopenharmony_ci	 *   delta < count_period
34762306a36Sopenharmony_ci	 *
34862306a36Sopenharmony_ci	 * Therefore the intermediate delta*count_hz will never overflow since
34962306a36Sopenharmony_ci	 * at the boundary condition:
35062306a36Sopenharmony_ci	 *   delta = count_period
35162306a36Sopenharmony_ci	 *   delta = NSEC_PER_SEC * 2^32 / count_hz
35262306a36Sopenharmony_ci	 *   delta * count_hz = NSEC_PER_SEC * 2^32
35362306a36Sopenharmony_ci	 */
35462306a36Sopenharmony_ci	return div_u64(delta * vcpu->arch.count_hz, NSEC_PER_SEC);
35562306a36Sopenharmony_ci}
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci/**
35862306a36Sopenharmony_ci * kvm_mips_count_time() - Get effective current time.
35962306a36Sopenharmony_ci * @vcpu:	Virtual CPU.
36062306a36Sopenharmony_ci *
36162306a36Sopenharmony_ci * Get effective monotonic ktime. This is usually a straightforward ktime_get(),
36262306a36Sopenharmony_ci * except when the master disable bit is set in count_ctl, in which case it is
36362306a36Sopenharmony_ci * count_resume, i.e. the time that the count was disabled.
36462306a36Sopenharmony_ci *
36562306a36Sopenharmony_ci * Returns:	Effective monotonic ktime for CP0_Count.
36662306a36Sopenharmony_ci */
36762306a36Sopenharmony_cistatic inline ktime_t kvm_mips_count_time(struct kvm_vcpu *vcpu)
36862306a36Sopenharmony_ci{
36962306a36Sopenharmony_ci	if (unlikely(vcpu->arch.count_ctl & KVM_REG_MIPS_COUNT_CTL_DC))
37062306a36Sopenharmony_ci		return vcpu->arch.count_resume;
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	return ktime_get();
37362306a36Sopenharmony_ci}
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci/**
37662306a36Sopenharmony_ci * kvm_mips_read_count_running() - Read the current count value as if running.
37762306a36Sopenharmony_ci * @vcpu:	Virtual CPU.
37862306a36Sopenharmony_ci * @now:	Kernel time to read CP0_Count at.
37962306a36Sopenharmony_ci *
38062306a36Sopenharmony_ci * Returns the current guest CP0_Count register at time @now and handles if the
38162306a36Sopenharmony_ci * timer interrupt is pending and hasn't been handled yet.
38262306a36Sopenharmony_ci *
38362306a36Sopenharmony_ci * Returns:	The current value of the guest CP0_Count register.
38462306a36Sopenharmony_ci */
38562306a36Sopenharmony_cistatic u32 kvm_mips_read_count_running(struct kvm_vcpu *vcpu, ktime_t now)
38662306a36Sopenharmony_ci{
38762306a36Sopenharmony_ci	struct mips_coproc *cop0 = &vcpu->arch.cop0;
38862306a36Sopenharmony_ci	ktime_t expires, threshold;
38962306a36Sopenharmony_ci	u32 count, compare;
39062306a36Sopenharmony_ci	int running;
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	/* Calculate the biased and scaled guest CP0_Count */
39362306a36Sopenharmony_ci	count = vcpu->arch.count_bias + kvm_mips_ktime_to_count(vcpu, now);
39462306a36Sopenharmony_ci	compare = kvm_read_c0_guest_compare(cop0);
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	/*
39762306a36Sopenharmony_ci	 * Find whether CP0_Count has reached the closest timer interrupt. If
39862306a36Sopenharmony_ci	 * not, we shouldn't inject it.
39962306a36Sopenharmony_ci	 */
40062306a36Sopenharmony_ci	if ((s32)(count - compare) < 0)
40162306a36Sopenharmony_ci		return count;
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	/*
40462306a36Sopenharmony_ci	 * The CP0_Count we're going to return has already reached the closest
40562306a36Sopenharmony_ci	 * timer interrupt. Quickly check if it really is a new interrupt by
40662306a36Sopenharmony_ci	 * looking at whether the interval until the hrtimer expiry time is
40762306a36Sopenharmony_ci	 * less than 1/4 of the timer period.
40862306a36Sopenharmony_ci	 */
40962306a36Sopenharmony_ci	expires = hrtimer_get_expires(&vcpu->arch.comparecount_timer);
41062306a36Sopenharmony_ci	threshold = ktime_add_ns(now, vcpu->arch.count_period / 4);
41162306a36Sopenharmony_ci	if (ktime_before(expires, threshold)) {
41262306a36Sopenharmony_ci		/*
41362306a36Sopenharmony_ci		 * Cancel it while we handle it so there's no chance of
41462306a36Sopenharmony_ci		 * interference with the timeout handler.
41562306a36Sopenharmony_ci		 */
41662306a36Sopenharmony_ci		running = hrtimer_cancel(&vcpu->arch.comparecount_timer);
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci		/* Nothing should be waiting on the timeout */
41962306a36Sopenharmony_ci		kvm_mips_callbacks->queue_timer_int(vcpu);
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci		/*
42262306a36Sopenharmony_ci		 * Restart the timer if it was running based on the expiry time
42362306a36Sopenharmony_ci		 * we read, so that we don't push it back 2 periods.
42462306a36Sopenharmony_ci		 */
42562306a36Sopenharmony_ci		if (running) {
42662306a36Sopenharmony_ci			expires = ktime_add_ns(expires,
42762306a36Sopenharmony_ci					       vcpu->arch.count_period);
42862306a36Sopenharmony_ci			hrtimer_start(&vcpu->arch.comparecount_timer, expires,
42962306a36Sopenharmony_ci				      HRTIMER_MODE_ABS);
43062306a36Sopenharmony_ci		}
43162306a36Sopenharmony_ci	}
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	return count;
43462306a36Sopenharmony_ci}
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci/**
43762306a36Sopenharmony_ci * kvm_mips_read_count() - Read the current count value.
43862306a36Sopenharmony_ci * @vcpu:	Virtual CPU.
43962306a36Sopenharmony_ci *
44062306a36Sopenharmony_ci * Read the current guest CP0_Count value, taking into account whether the timer
44162306a36Sopenharmony_ci * is stopped.
44262306a36Sopenharmony_ci *
44362306a36Sopenharmony_ci * Returns:	The current guest CP0_Count value.
44462306a36Sopenharmony_ci */
44562306a36Sopenharmony_ciu32 kvm_mips_read_count(struct kvm_vcpu *vcpu)
44662306a36Sopenharmony_ci{
44762306a36Sopenharmony_ci	struct mips_coproc *cop0 = &vcpu->arch.cop0;
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	/* If count disabled just read static copy of count */
45062306a36Sopenharmony_ci	if (kvm_mips_count_disabled(vcpu))
45162306a36Sopenharmony_ci		return kvm_read_c0_guest_count(cop0);
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	return kvm_mips_read_count_running(vcpu, ktime_get());
45462306a36Sopenharmony_ci}
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci/**
45762306a36Sopenharmony_ci * kvm_mips_freeze_hrtimer() - Safely stop the hrtimer.
45862306a36Sopenharmony_ci * @vcpu:	Virtual CPU.
45962306a36Sopenharmony_ci * @count:	Output pointer for CP0_Count value at point of freeze.
46062306a36Sopenharmony_ci *
46162306a36Sopenharmony_ci * Freeze the hrtimer safely and return both the ktime and the CP0_Count value
46262306a36Sopenharmony_ci * at the point it was frozen. It is guaranteed that any pending interrupts at
46362306a36Sopenharmony_ci * the point it was frozen are handled, and none after that point.
46462306a36Sopenharmony_ci *
46562306a36Sopenharmony_ci * This is useful where the time/CP0_Count is needed in the calculation of the
46662306a36Sopenharmony_ci * new parameters.
46762306a36Sopenharmony_ci *
46862306a36Sopenharmony_ci * Assumes !kvm_mips_count_disabled(@vcpu) (guest CP0_Count timer is running).
46962306a36Sopenharmony_ci *
47062306a36Sopenharmony_ci * Returns:	The ktime at the point of freeze.
47162306a36Sopenharmony_ci */
47262306a36Sopenharmony_ciktime_t kvm_mips_freeze_hrtimer(struct kvm_vcpu *vcpu, u32 *count)
47362306a36Sopenharmony_ci{
47462306a36Sopenharmony_ci	ktime_t now;
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	/* stop hrtimer before finding time */
47762306a36Sopenharmony_ci	hrtimer_cancel(&vcpu->arch.comparecount_timer);
47862306a36Sopenharmony_ci	now = ktime_get();
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	/* find count at this point and handle pending hrtimer */
48162306a36Sopenharmony_ci	*count = kvm_mips_read_count_running(vcpu, now);
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	return now;
48462306a36Sopenharmony_ci}
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci/**
48762306a36Sopenharmony_ci * kvm_mips_resume_hrtimer() - Resume hrtimer, updating expiry.
48862306a36Sopenharmony_ci * @vcpu:	Virtual CPU.
48962306a36Sopenharmony_ci * @now:	ktime at point of resume.
49062306a36Sopenharmony_ci * @count:	CP0_Count at point of resume.
49162306a36Sopenharmony_ci *
49262306a36Sopenharmony_ci * Resumes the timer and updates the timer expiry based on @now and @count.
49362306a36Sopenharmony_ci * This can be used in conjunction with kvm_mips_freeze_timer() when timer
49462306a36Sopenharmony_ci * parameters need to be changed.
49562306a36Sopenharmony_ci *
49662306a36Sopenharmony_ci * It is guaranteed that a timer interrupt immediately after resume will be
49762306a36Sopenharmony_ci * handled, but not if CP_Compare is exactly at @count. That case is already
49862306a36Sopenharmony_ci * handled by kvm_mips_freeze_timer().
49962306a36Sopenharmony_ci *
50062306a36Sopenharmony_ci * Assumes !kvm_mips_count_disabled(@vcpu) (guest CP0_Count timer is running).
50162306a36Sopenharmony_ci */
50262306a36Sopenharmony_cistatic void kvm_mips_resume_hrtimer(struct kvm_vcpu *vcpu,
50362306a36Sopenharmony_ci				    ktime_t now, u32 count)
50462306a36Sopenharmony_ci{
50562306a36Sopenharmony_ci	struct mips_coproc *cop0 = &vcpu->arch.cop0;
50662306a36Sopenharmony_ci	u32 compare;
50762306a36Sopenharmony_ci	u64 delta;
50862306a36Sopenharmony_ci	ktime_t expire;
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci	/* Calculate timeout (wrap 0 to 2^32) */
51162306a36Sopenharmony_ci	compare = kvm_read_c0_guest_compare(cop0);
51262306a36Sopenharmony_ci	delta = (u64)(u32)(compare - count - 1) + 1;
51362306a36Sopenharmony_ci	delta = div_u64(delta * NSEC_PER_SEC, vcpu->arch.count_hz);
51462306a36Sopenharmony_ci	expire = ktime_add_ns(now, delta);
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	/* Update hrtimer to use new timeout */
51762306a36Sopenharmony_ci	hrtimer_cancel(&vcpu->arch.comparecount_timer);
51862306a36Sopenharmony_ci	hrtimer_start(&vcpu->arch.comparecount_timer, expire, HRTIMER_MODE_ABS);
51962306a36Sopenharmony_ci}
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci/**
52262306a36Sopenharmony_ci * kvm_mips_restore_hrtimer() - Restore hrtimer after a gap, updating expiry.
52362306a36Sopenharmony_ci * @vcpu:	Virtual CPU.
52462306a36Sopenharmony_ci * @before:	Time before Count was saved, lower bound of drift calculation.
52562306a36Sopenharmony_ci * @count:	CP0_Count at point of restore.
52662306a36Sopenharmony_ci * @min_drift:	Minimum amount of drift permitted before correction.
52762306a36Sopenharmony_ci *		Must be <= 0.
52862306a36Sopenharmony_ci *
52962306a36Sopenharmony_ci * Restores the timer from a particular @count, accounting for drift. This can
53062306a36Sopenharmony_ci * be used in conjunction with kvm_mips_freeze_timer() when a hardware timer is
53162306a36Sopenharmony_ci * to be used for a period of time, but the exact ktime corresponding to the
53262306a36Sopenharmony_ci * final Count that must be restored is not known.
53362306a36Sopenharmony_ci *
53462306a36Sopenharmony_ci * It is gauranteed that a timer interrupt immediately after restore will be
53562306a36Sopenharmony_ci * handled, but not if CP0_Compare is exactly at @count. That case should
53662306a36Sopenharmony_ci * already be handled when the hardware timer state is saved.
53762306a36Sopenharmony_ci *
53862306a36Sopenharmony_ci * Assumes !kvm_mips_count_disabled(@vcpu) (guest CP0_Count timer is not
53962306a36Sopenharmony_ci * stopped).
54062306a36Sopenharmony_ci *
54162306a36Sopenharmony_ci * Returns:	Amount of correction to count_bias due to drift.
54262306a36Sopenharmony_ci */
54362306a36Sopenharmony_ciint kvm_mips_restore_hrtimer(struct kvm_vcpu *vcpu, ktime_t before,
54462306a36Sopenharmony_ci			     u32 count, int min_drift)
54562306a36Sopenharmony_ci{
54662306a36Sopenharmony_ci	ktime_t now, count_time;
54762306a36Sopenharmony_ci	u32 now_count, before_count;
54862306a36Sopenharmony_ci	u64 delta;
54962306a36Sopenharmony_ci	int drift, ret = 0;
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	/* Calculate expected count at before */
55262306a36Sopenharmony_ci	before_count = vcpu->arch.count_bias +
55362306a36Sopenharmony_ci			kvm_mips_ktime_to_count(vcpu, before);
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	/*
55662306a36Sopenharmony_ci	 * Detect significantly negative drift, where count is lower than
55762306a36Sopenharmony_ci	 * expected. Some negative drift is expected when hardware counter is
55862306a36Sopenharmony_ci	 * set after kvm_mips_freeze_timer(), and it is harmless to allow the
55962306a36Sopenharmony_ci	 * time to jump forwards a little, within reason. If the drift is too
56062306a36Sopenharmony_ci	 * significant, adjust the bias to avoid a big Guest.CP0_Count jump.
56162306a36Sopenharmony_ci	 */
56262306a36Sopenharmony_ci	drift = count - before_count;
56362306a36Sopenharmony_ci	if (drift < min_drift) {
56462306a36Sopenharmony_ci		count_time = before;
56562306a36Sopenharmony_ci		vcpu->arch.count_bias += drift;
56662306a36Sopenharmony_ci		ret = drift;
56762306a36Sopenharmony_ci		goto resume;
56862306a36Sopenharmony_ci	}
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci	/* Calculate expected count right now */
57162306a36Sopenharmony_ci	now = ktime_get();
57262306a36Sopenharmony_ci	now_count = vcpu->arch.count_bias + kvm_mips_ktime_to_count(vcpu, now);
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci	/*
57562306a36Sopenharmony_ci	 * Detect positive drift, where count is higher than expected, and
57662306a36Sopenharmony_ci	 * adjust the bias to avoid guest time going backwards.
57762306a36Sopenharmony_ci	 */
57862306a36Sopenharmony_ci	drift = count - now_count;
57962306a36Sopenharmony_ci	if (drift > 0) {
58062306a36Sopenharmony_ci		count_time = now;
58162306a36Sopenharmony_ci		vcpu->arch.count_bias += drift;
58262306a36Sopenharmony_ci		ret = drift;
58362306a36Sopenharmony_ci		goto resume;
58462306a36Sopenharmony_ci	}
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	/* Subtract nanosecond delta to find ktime when count was read */
58762306a36Sopenharmony_ci	delta = (u64)(u32)(now_count - count);
58862306a36Sopenharmony_ci	delta = div_u64(delta * NSEC_PER_SEC, vcpu->arch.count_hz);
58962306a36Sopenharmony_ci	count_time = ktime_sub_ns(now, delta);
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ciresume:
59262306a36Sopenharmony_ci	/* Resume using the calculated ktime */
59362306a36Sopenharmony_ci	kvm_mips_resume_hrtimer(vcpu, count_time, count);
59462306a36Sopenharmony_ci	return ret;
59562306a36Sopenharmony_ci}
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci/**
59862306a36Sopenharmony_ci * kvm_mips_write_count() - Modify the count and update timer.
59962306a36Sopenharmony_ci * @vcpu:	Virtual CPU.
60062306a36Sopenharmony_ci * @count:	Guest CP0_Count value to set.
60162306a36Sopenharmony_ci *
60262306a36Sopenharmony_ci * Sets the CP0_Count value and updates the timer accordingly.
60362306a36Sopenharmony_ci */
60462306a36Sopenharmony_civoid kvm_mips_write_count(struct kvm_vcpu *vcpu, u32 count)
60562306a36Sopenharmony_ci{
60662306a36Sopenharmony_ci	struct mips_coproc *cop0 = &vcpu->arch.cop0;
60762306a36Sopenharmony_ci	ktime_t now;
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	/* Calculate bias */
61062306a36Sopenharmony_ci	now = kvm_mips_count_time(vcpu);
61162306a36Sopenharmony_ci	vcpu->arch.count_bias = count - kvm_mips_ktime_to_count(vcpu, now);
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	if (kvm_mips_count_disabled(vcpu))
61462306a36Sopenharmony_ci		/* The timer's disabled, adjust the static count */
61562306a36Sopenharmony_ci		kvm_write_c0_guest_count(cop0, count);
61662306a36Sopenharmony_ci	else
61762306a36Sopenharmony_ci		/* Update timeout */
61862306a36Sopenharmony_ci		kvm_mips_resume_hrtimer(vcpu, now, count);
61962306a36Sopenharmony_ci}
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci/**
62262306a36Sopenharmony_ci * kvm_mips_init_count() - Initialise timer.
62362306a36Sopenharmony_ci * @vcpu:	Virtual CPU.
62462306a36Sopenharmony_ci * @count_hz:	Frequency of timer.
62562306a36Sopenharmony_ci *
62662306a36Sopenharmony_ci * Initialise the timer to the specified frequency, zero it, and set it going if
62762306a36Sopenharmony_ci * it's enabled.
62862306a36Sopenharmony_ci */
62962306a36Sopenharmony_civoid kvm_mips_init_count(struct kvm_vcpu *vcpu, unsigned long count_hz)
63062306a36Sopenharmony_ci{
63162306a36Sopenharmony_ci	vcpu->arch.count_hz = count_hz;
63262306a36Sopenharmony_ci	vcpu->arch.count_period = div_u64((u64)NSEC_PER_SEC << 32, count_hz);
63362306a36Sopenharmony_ci	vcpu->arch.count_dyn_bias = 0;
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	/* Starting at 0 */
63662306a36Sopenharmony_ci	kvm_mips_write_count(vcpu, 0);
63762306a36Sopenharmony_ci}
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci/**
64062306a36Sopenharmony_ci * kvm_mips_set_count_hz() - Update the frequency of the timer.
64162306a36Sopenharmony_ci * @vcpu:	Virtual CPU.
64262306a36Sopenharmony_ci * @count_hz:	Frequency of CP0_Count timer in Hz.
64362306a36Sopenharmony_ci *
64462306a36Sopenharmony_ci * Change the frequency of the CP0_Count timer. This is done atomically so that
64562306a36Sopenharmony_ci * CP0_Count is continuous and no timer interrupt is lost.
64662306a36Sopenharmony_ci *
64762306a36Sopenharmony_ci * Returns:	-EINVAL if @count_hz is out of range.
64862306a36Sopenharmony_ci *		0 on success.
64962306a36Sopenharmony_ci */
65062306a36Sopenharmony_ciint kvm_mips_set_count_hz(struct kvm_vcpu *vcpu, s64 count_hz)
65162306a36Sopenharmony_ci{
65262306a36Sopenharmony_ci	struct mips_coproc *cop0 = &vcpu->arch.cop0;
65362306a36Sopenharmony_ci	int dc;
65462306a36Sopenharmony_ci	ktime_t now;
65562306a36Sopenharmony_ci	u32 count;
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	/* ensure the frequency is in a sensible range... */
65862306a36Sopenharmony_ci	if (count_hz <= 0 || count_hz > NSEC_PER_SEC)
65962306a36Sopenharmony_ci		return -EINVAL;
66062306a36Sopenharmony_ci	/* ... and has actually changed */
66162306a36Sopenharmony_ci	if (vcpu->arch.count_hz == count_hz)
66262306a36Sopenharmony_ci		return 0;
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	/* Safely freeze timer so we can keep it continuous */
66562306a36Sopenharmony_ci	dc = kvm_mips_count_disabled(vcpu);
66662306a36Sopenharmony_ci	if (dc) {
66762306a36Sopenharmony_ci		now = kvm_mips_count_time(vcpu);
66862306a36Sopenharmony_ci		count = kvm_read_c0_guest_count(cop0);
66962306a36Sopenharmony_ci	} else {
67062306a36Sopenharmony_ci		now = kvm_mips_freeze_hrtimer(vcpu, &count);
67162306a36Sopenharmony_ci	}
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci	/* Update the frequency */
67462306a36Sopenharmony_ci	vcpu->arch.count_hz = count_hz;
67562306a36Sopenharmony_ci	vcpu->arch.count_period = div_u64((u64)NSEC_PER_SEC << 32, count_hz);
67662306a36Sopenharmony_ci	vcpu->arch.count_dyn_bias = 0;
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci	/* Calculate adjusted bias so dynamic count is unchanged */
67962306a36Sopenharmony_ci	vcpu->arch.count_bias = count - kvm_mips_ktime_to_count(vcpu, now);
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	/* Update and resume hrtimer */
68262306a36Sopenharmony_ci	if (!dc)
68362306a36Sopenharmony_ci		kvm_mips_resume_hrtimer(vcpu, now, count);
68462306a36Sopenharmony_ci	return 0;
68562306a36Sopenharmony_ci}
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci/**
68862306a36Sopenharmony_ci * kvm_mips_write_compare() - Modify compare and update timer.
68962306a36Sopenharmony_ci * @vcpu:	Virtual CPU.
69062306a36Sopenharmony_ci * @compare:	New CP0_Compare value.
69162306a36Sopenharmony_ci * @ack:	Whether to acknowledge timer interrupt.
69262306a36Sopenharmony_ci *
69362306a36Sopenharmony_ci * Update CP0_Compare to a new value and update the timeout.
69462306a36Sopenharmony_ci * If @ack, atomically acknowledge any pending timer interrupt, otherwise ensure
69562306a36Sopenharmony_ci * any pending timer interrupt is preserved.
69662306a36Sopenharmony_ci */
69762306a36Sopenharmony_civoid kvm_mips_write_compare(struct kvm_vcpu *vcpu, u32 compare, bool ack)
69862306a36Sopenharmony_ci{
69962306a36Sopenharmony_ci	struct mips_coproc *cop0 = &vcpu->arch.cop0;
70062306a36Sopenharmony_ci	int dc;
70162306a36Sopenharmony_ci	u32 old_compare = kvm_read_c0_guest_compare(cop0);
70262306a36Sopenharmony_ci	s32 delta = compare - old_compare;
70362306a36Sopenharmony_ci	u32 cause;
70462306a36Sopenharmony_ci	ktime_t now = ktime_set(0, 0); /* silence bogus GCC warning */
70562306a36Sopenharmony_ci	u32 count;
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci	/* if unchanged, must just be an ack */
70862306a36Sopenharmony_ci	if (old_compare == compare) {
70962306a36Sopenharmony_ci		if (!ack)
71062306a36Sopenharmony_ci			return;
71162306a36Sopenharmony_ci		kvm_mips_callbacks->dequeue_timer_int(vcpu);
71262306a36Sopenharmony_ci		kvm_write_c0_guest_compare(cop0, compare);
71362306a36Sopenharmony_ci		return;
71462306a36Sopenharmony_ci	}
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ci	/*
71762306a36Sopenharmony_ci	 * If guest CP0_Compare moves forward, CP0_GTOffset should be adjusted
71862306a36Sopenharmony_ci	 * too to prevent guest CP0_Count hitting guest CP0_Compare.
71962306a36Sopenharmony_ci	 *
72062306a36Sopenharmony_ci	 * The new GTOffset corresponds to the new value of CP0_Compare, and is
72162306a36Sopenharmony_ci	 * set prior to it being written into the guest context. We disable
72262306a36Sopenharmony_ci	 * preemption until the new value is written to prevent restore of a
72362306a36Sopenharmony_ci	 * GTOffset corresponding to the old CP0_Compare value.
72462306a36Sopenharmony_ci	 */
72562306a36Sopenharmony_ci	if (delta > 0) {
72662306a36Sopenharmony_ci		preempt_disable();
72762306a36Sopenharmony_ci		write_c0_gtoffset(compare - read_c0_count());
72862306a36Sopenharmony_ci		back_to_back_c0_hazard();
72962306a36Sopenharmony_ci	}
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	/* freeze_hrtimer() takes care of timer interrupts <= count */
73262306a36Sopenharmony_ci	dc = kvm_mips_count_disabled(vcpu);
73362306a36Sopenharmony_ci	if (!dc)
73462306a36Sopenharmony_ci		now = kvm_mips_freeze_hrtimer(vcpu, &count);
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	if (ack)
73762306a36Sopenharmony_ci		kvm_mips_callbacks->dequeue_timer_int(vcpu);
73862306a36Sopenharmony_ci	else
73962306a36Sopenharmony_ci		/*
74062306a36Sopenharmony_ci		 * With VZ, writing CP0_Compare acks (clears) CP0_Cause.TI, so
74162306a36Sopenharmony_ci		 * preserve guest CP0_Cause.TI if we don't want to ack it.
74262306a36Sopenharmony_ci		 */
74362306a36Sopenharmony_ci		cause = kvm_read_c0_guest_cause(cop0);
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci	kvm_write_c0_guest_compare(cop0, compare);
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	if (delta > 0)
74862306a36Sopenharmony_ci		preempt_enable();
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci	back_to_back_c0_hazard();
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci	if (!ack && cause & CAUSEF_TI)
75362306a36Sopenharmony_ci		kvm_write_c0_guest_cause(cop0, cause);
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci	/* resume_hrtimer() takes care of timer interrupts > count */
75662306a36Sopenharmony_ci	if (!dc)
75762306a36Sopenharmony_ci		kvm_mips_resume_hrtimer(vcpu, now, count);
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_ci	/*
76062306a36Sopenharmony_ci	 * If guest CP0_Compare is moving backward, we delay CP0_GTOffset change
76162306a36Sopenharmony_ci	 * until after the new CP0_Compare is written, otherwise new guest
76262306a36Sopenharmony_ci	 * CP0_Count could hit new guest CP0_Compare.
76362306a36Sopenharmony_ci	 */
76462306a36Sopenharmony_ci	if (delta <= 0)
76562306a36Sopenharmony_ci		write_c0_gtoffset(compare - read_c0_count());
76662306a36Sopenharmony_ci}
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci/**
76962306a36Sopenharmony_ci * kvm_mips_count_disable() - Disable count.
77062306a36Sopenharmony_ci * @vcpu:	Virtual CPU.
77162306a36Sopenharmony_ci *
77262306a36Sopenharmony_ci * Disable the CP0_Count timer. A timer interrupt on or before the final stop
77362306a36Sopenharmony_ci * time will be handled but not after.
77462306a36Sopenharmony_ci *
77562306a36Sopenharmony_ci * Assumes CP0_Count was previously enabled but now Guest.CP0_Cause.DC or
77662306a36Sopenharmony_ci * count_ctl.DC has been set (count disabled).
77762306a36Sopenharmony_ci *
77862306a36Sopenharmony_ci * Returns:	The time that the timer was stopped.
77962306a36Sopenharmony_ci */
78062306a36Sopenharmony_cistatic ktime_t kvm_mips_count_disable(struct kvm_vcpu *vcpu)
78162306a36Sopenharmony_ci{
78262306a36Sopenharmony_ci	struct mips_coproc *cop0 = &vcpu->arch.cop0;
78362306a36Sopenharmony_ci	u32 count;
78462306a36Sopenharmony_ci	ktime_t now;
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci	/* Stop hrtimer */
78762306a36Sopenharmony_ci	hrtimer_cancel(&vcpu->arch.comparecount_timer);
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci	/* Set the static count from the dynamic count, handling pending TI */
79062306a36Sopenharmony_ci	now = ktime_get();
79162306a36Sopenharmony_ci	count = kvm_mips_read_count_running(vcpu, now);
79262306a36Sopenharmony_ci	kvm_write_c0_guest_count(cop0, count);
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci	return now;
79562306a36Sopenharmony_ci}
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci/**
79862306a36Sopenharmony_ci * kvm_mips_count_disable_cause() - Disable count using CP0_Cause.DC.
79962306a36Sopenharmony_ci * @vcpu:	Virtual CPU.
80062306a36Sopenharmony_ci *
80162306a36Sopenharmony_ci * Disable the CP0_Count timer and set CP0_Cause.DC. A timer interrupt on or
80262306a36Sopenharmony_ci * before the final stop time will be handled if the timer isn't disabled by
80362306a36Sopenharmony_ci * count_ctl.DC, but not after.
80462306a36Sopenharmony_ci *
80562306a36Sopenharmony_ci * Assumes CP0_Cause.DC is clear (count enabled).
80662306a36Sopenharmony_ci */
80762306a36Sopenharmony_civoid kvm_mips_count_disable_cause(struct kvm_vcpu *vcpu)
80862306a36Sopenharmony_ci{
80962306a36Sopenharmony_ci	struct mips_coproc *cop0 = &vcpu->arch.cop0;
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci	kvm_set_c0_guest_cause(cop0, CAUSEF_DC);
81262306a36Sopenharmony_ci	if (!(vcpu->arch.count_ctl & KVM_REG_MIPS_COUNT_CTL_DC))
81362306a36Sopenharmony_ci		kvm_mips_count_disable(vcpu);
81462306a36Sopenharmony_ci}
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci/**
81762306a36Sopenharmony_ci * kvm_mips_count_enable_cause() - Enable count using CP0_Cause.DC.
81862306a36Sopenharmony_ci * @vcpu:	Virtual CPU.
81962306a36Sopenharmony_ci *
82062306a36Sopenharmony_ci * Enable the CP0_Count timer and clear CP0_Cause.DC. A timer interrupt after
82162306a36Sopenharmony_ci * the start time will be handled if the timer isn't disabled by count_ctl.DC,
82262306a36Sopenharmony_ci * potentially before even returning, so the caller should be careful with
82362306a36Sopenharmony_ci * ordering of CP0_Cause modifications so as not to lose it.
82462306a36Sopenharmony_ci *
82562306a36Sopenharmony_ci * Assumes CP0_Cause.DC is set (count disabled).
82662306a36Sopenharmony_ci */
82762306a36Sopenharmony_civoid kvm_mips_count_enable_cause(struct kvm_vcpu *vcpu)
82862306a36Sopenharmony_ci{
82962306a36Sopenharmony_ci	struct mips_coproc *cop0 = &vcpu->arch.cop0;
83062306a36Sopenharmony_ci	u32 count;
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci	kvm_clear_c0_guest_cause(cop0, CAUSEF_DC);
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci	/*
83562306a36Sopenharmony_ci	 * Set the dynamic count to match the static count.
83662306a36Sopenharmony_ci	 * This starts the hrtimer if count_ctl.DC allows it.
83762306a36Sopenharmony_ci	 * Otherwise it conveniently updates the biases.
83862306a36Sopenharmony_ci	 */
83962306a36Sopenharmony_ci	count = kvm_read_c0_guest_count(cop0);
84062306a36Sopenharmony_ci	kvm_mips_write_count(vcpu, count);
84162306a36Sopenharmony_ci}
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci/**
84462306a36Sopenharmony_ci * kvm_mips_set_count_ctl() - Update the count control KVM register.
84562306a36Sopenharmony_ci * @vcpu:	Virtual CPU.
84662306a36Sopenharmony_ci * @count_ctl:	Count control register new value.
84762306a36Sopenharmony_ci *
84862306a36Sopenharmony_ci * Set the count control KVM register. The timer is updated accordingly.
84962306a36Sopenharmony_ci *
85062306a36Sopenharmony_ci * Returns:	-EINVAL if reserved bits are set.
85162306a36Sopenharmony_ci *		0 on success.
85262306a36Sopenharmony_ci */
85362306a36Sopenharmony_ciint kvm_mips_set_count_ctl(struct kvm_vcpu *vcpu, s64 count_ctl)
85462306a36Sopenharmony_ci{
85562306a36Sopenharmony_ci	struct mips_coproc *cop0 = &vcpu->arch.cop0;
85662306a36Sopenharmony_ci	s64 changed = count_ctl ^ vcpu->arch.count_ctl;
85762306a36Sopenharmony_ci	s64 delta;
85862306a36Sopenharmony_ci	ktime_t expire, now;
85962306a36Sopenharmony_ci	u32 count, compare;
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_ci	/* Only allow defined bits to be changed */
86262306a36Sopenharmony_ci	if (changed & ~(s64)(KVM_REG_MIPS_COUNT_CTL_DC))
86362306a36Sopenharmony_ci		return -EINVAL;
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci	/* Apply new value */
86662306a36Sopenharmony_ci	vcpu->arch.count_ctl = count_ctl;
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci	/* Master CP0_Count disable */
86962306a36Sopenharmony_ci	if (changed & KVM_REG_MIPS_COUNT_CTL_DC) {
87062306a36Sopenharmony_ci		/* Is CP0_Cause.DC already disabling CP0_Count? */
87162306a36Sopenharmony_ci		if (kvm_read_c0_guest_cause(cop0) & CAUSEF_DC) {
87262306a36Sopenharmony_ci			if (count_ctl & KVM_REG_MIPS_COUNT_CTL_DC)
87362306a36Sopenharmony_ci				/* Just record the current time */
87462306a36Sopenharmony_ci				vcpu->arch.count_resume = ktime_get();
87562306a36Sopenharmony_ci		} else if (count_ctl & KVM_REG_MIPS_COUNT_CTL_DC) {
87662306a36Sopenharmony_ci			/* disable timer and record current time */
87762306a36Sopenharmony_ci			vcpu->arch.count_resume = kvm_mips_count_disable(vcpu);
87862306a36Sopenharmony_ci		} else {
87962306a36Sopenharmony_ci			/*
88062306a36Sopenharmony_ci			 * Calculate timeout relative to static count at resume
88162306a36Sopenharmony_ci			 * time (wrap 0 to 2^32).
88262306a36Sopenharmony_ci			 */
88362306a36Sopenharmony_ci			count = kvm_read_c0_guest_count(cop0);
88462306a36Sopenharmony_ci			compare = kvm_read_c0_guest_compare(cop0);
88562306a36Sopenharmony_ci			delta = (u64)(u32)(compare - count - 1) + 1;
88662306a36Sopenharmony_ci			delta = div_u64(delta * NSEC_PER_SEC,
88762306a36Sopenharmony_ci					vcpu->arch.count_hz);
88862306a36Sopenharmony_ci			expire = ktime_add_ns(vcpu->arch.count_resume, delta);
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci			/* Handle pending interrupt */
89162306a36Sopenharmony_ci			now = ktime_get();
89262306a36Sopenharmony_ci			if (ktime_compare(now, expire) >= 0)
89362306a36Sopenharmony_ci				/* Nothing should be waiting on the timeout */
89462306a36Sopenharmony_ci				kvm_mips_callbacks->queue_timer_int(vcpu);
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_ci			/* Resume hrtimer without changing bias */
89762306a36Sopenharmony_ci			count = kvm_mips_read_count_running(vcpu, now);
89862306a36Sopenharmony_ci			kvm_mips_resume_hrtimer(vcpu, now, count);
89962306a36Sopenharmony_ci		}
90062306a36Sopenharmony_ci	}
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci	return 0;
90362306a36Sopenharmony_ci}
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_ci/**
90662306a36Sopenharmony_ci * kvm_mips_set_count_resume() - Update the count resume KVM register.
90762306a36Sopenharmony_ci * @vcpu:		Virtual CPU.
90862306a36Sopenharmony_ci * @count_resume:	Count resume register new value.
90962306a36Sopenharmony_ci *
91062306a36Sopenharmony_ci * Set the count resume KVM register.
91162306a36Sopenharmony_ci *
91262306a36Sopenharmony_ci * Returns:	-EINVAL if out of valid range (0..now).
91362306a36Sopenharmony_ci *		0 on success.
91462306a36Sopenharmony_ci */
91562306a36Sopenharmony_ciint kvm_mips_set_count_resume(struct kvm_vcpu *vcpu, s64 count_resume)
91662306a36Sopenharmony_ci{
91762306a36Sopenharmony_ci	/*
91862306a36Sopenharmony_ci	 * It doesn't make sense for the resume time to be in the future, as it
91962306a36Sopenharmony_ci	 * would be possible for the next interrupt to be more than a full
92062306a36Sopenharmony_ci	 * period in the future.
92162306a36Sopenharmony_ci	 */
92262306a36Sopenharmony_ci	if (count_resume < 0 || count_resume > ktime_to_ns(ktime_get()))
92362306a36Sopenharmony_ci		return -EINVAL;
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci	vcpu->arch.count_resume = ns_to_ktime(count_resume);
92662306a36Sopenharmony_ci	return 0;
92762306a36Sopenharmony_ci}
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci/**
93062306a36Sopenharmony_ci * kvm_mips_count_timeout() - Push timer forward on timeout.
93162306a36Sopenharmony_ci * @vcpu:	Virtual CPU.
93262306a36Sopenharmony_ci *
93362306a36Sopenharmony_ci * Handle an hrtimer event by push the hrtimer forward a period.
93462306a36Sopenharmony_ci *
93562306a36Sopenharmony_ci * Returns:	The hrtimer_restart value to return to the hrtimer subsystem.
93662306a36Sopenharmony_ci */
93762306a36Sopenharmony_cienum hrtimer_restart kvm_mips_count_timeout(struct kvm_vcpu *vcpu)
93862306a36Sopenharmony_ci{
93962306a36Sopenharmony_ci	/* Add the Count period to the current expiry time */
94062306a36Sopenharmony_ci	hrtimer_add_expires_ns(&vcpu->arch.comparecount_timer,
94162306a36Sopenharmony_ci			       vcpu->arch.count_period);
94262306a36Sopenharmony_ci	return HRTIMER_RESTART;
94362306a36Sopenharmony_ci}
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_cienum emulation_result kvm_mips_emul_wait(struct kvm_vcpu *vcpu)
94662306a36Sopenharmony_ci{
94762306a36Sopenharmony_ci	kvm_debug("[%#lx] !!!WAIT!!! (%#lx)\n", vcpu->arch.pc,
94862306a36Sopenharmony_ci		  vcpu->arch.pending_exceptions);
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci	++vcpu->stat.wait_exits;
95162306a36Sopenharmony_ci	trace_kvm_exit(vcpu, KVM_TRACE_EXIT_WAIT);
95262306a36Sopenharmony_ci	if (!vcpu->arch.pending_exceptions) {
95362306a36Sopenharmony_ci		kvm_vz_lose_htimer(vcpu);
95462306a36Sopenharmony_ci		vcpu->arch.wait = 1;
95562306a36Sopenharmony_ci		kvm_vcpu_halt(vcpu);
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci		/*
95862306a36Sopenharmony_ci		 * We are runnable, then definitely go off to user space to
95962306a36Sopenharmony_ci		 * check if any I/O interrupts are pending.
96062306a36Sopenharmony_ci		 */
96162306a36Sopenharmony_ci		if (kvm_arch_vcpu_runnable(vcpu))
96262306a36Sopenharmony_ci			vcpu->run->exit_reason = KVM_EXIT_IRQ_WINDOW_OPEN;
96362306a36Sopenharmony_ci	}
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci	return EMULATE_DONE;
96662306a36Sopenharmony_ci}
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_cienum emulation_result kvm_mips_emulate_store(union mips_instruction inst,
96962306a36Sopenharmony_ci					     u32 cause,
97062306a36Sopenharmony_ci					     struct kvm_vcpu *vcpu)
97162306a36Sopenharmony_ci{
97262306a36Sopenharmony_ci	int r;
97362306a36Sopenharmony_ci	enum emulation_result er;
97462306a36Sopenharmony_ci	u32 rt;
97562306a36Sopenharmony_ci	struct kvm_run *run = vcpu->run;
97662306a36Sopenharmony_ci	void *data = run->mmio.data;
97762306a36Sopenharmony_ci	unsigned int imme;
97862306a36Sopenharmony_ci	unsigned long curr_pc;
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci	/*
98162306a36Sopenharmony_ci	 * Update PC and hold onto current PC in case there is
98262306a36Sopenharmony_ci	 * an error and we want to rollback the PC
98362306a36Sopenharmony_ci	 */
98462306a36Sopenharmony_ci	curr_pc = vcpu->arch.pc;
98562306a36Sopenharmony_ci	er = update_pc(vcpu, cause);
98662306a36Sopenharmony_ci	if (er == EMULATE_FAIL)
98762306a36Sopenharmony_ci		return er;
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci	rt = inst.i_format.rt;
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ci	run->mmio.phys_addr = kvm_mips_callbacks->gva_to_gpa(
99262306a36Sopenharmony_ci						vcpu->arch.host_cp0_badvaddr);
99362306a36Sopenharmony_ci	if (run->mmio.phys_addr == KVM_INVALID_ADDR)
99462306a36Sopenharmony_ci		goto out_fail;
99562306a36Sopenharmony_ci
99662306a36Sopenharmony_ci	switch (inst.i_format.opcode) {
99762306a36Sopenharmony_ci#if defined(CONFIG_64BIT)
99862306a36Sopenharmony_ci	case sd_op:
99962306a36Sopenharmony_ci		run->mmio.len = 8;
100062306a36Sopenharmony_ci		*(u64 *)data = vcpu->arch.gprs[rt];
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_ci		kvm_debug("[%#lx] OP_SD: eaddr: %#lx, gpr: %#lx, data: %#llx\n",
100362306a36Sopenharmony_ci			  vcpu->arch.pc, vcpu->arch.host_cp0_badvaddr,
100462306a36Sopenharmony_ci			  vcpu->arch.gprs[rt], *(u64 *)data);
100562306a36Sopenharmony_ci		break;
100662306a36Sopenharmony_ci#endif
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci	case sw_op:
100962306a36Sopenharmony_ci		run->mmio.len = 4;
101062306a36Sopenharmony_ci		*(u32 *)data = vcpu->arch.gprs[rt];
101162306a36Sopenharmony_ci
101262306a36Sopenharmony_ci		kvm_debug("[%#lx] OP_SW: eaddr: %#lx, gpr: %#lx, data: %#x\n",
101362306a36Sopenharmony_ci			  vcpu->arch.pc, vcpu->arch.host_cp0_badvaddr,
101462306a36Sopenharmony_ci			  vcpu->arch.gprs[rt], *(u32 *)data);
101562306a36Sopenharmony_ci		break;
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_ci	case sh_op:
101862306a36Sopenharmony_ci		run->mmio.len = 2;
101962306a36Sopenharmony_ci		*(u16 *)data = vcpu->arch.gprs[rt];
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci		kvm_debug("[%#lx] OP_SH: eaddr: %#lx, gpr: %#lx, data: %#x\n",
102262306a36Sopenharmony_ci			  vcpu->arch.pc, vcpu->arch.host_cp0_badvaddr,
102362306a36Sopenharmony_ci			  vcpu->arch.gprs[rt], *(u16 *)data);
102462306a36Sopenharmony_ci		break;
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_ci	case sb_op:
102762306a36Sopenharmony_ci		run->mmio.len = 1;
102862306a36Sopenharmony_ci		*(u8 *)data = vcpu->arch.gprs[rt];
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci		kvm_debug("[%#lx] OP_SB: eaddr: %#lx, gpr: %#lx, data: %#x\n",
103162306a36Sopenharmony_ci			  vcpu->arch.pc, vcpu->arch.host_cp0_badvaddr,
103262306a36Sopenharmony_ci			  vcpu->arch.gprs[rt], *(u8 *)data);
103362306a36Sopenharmony_ci		break;
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_ci	case swl_op:
103662306a36Sopenharmony_ci		run->mmio.phys_addr = kvm_mips_callbacks->gva_to_gpa(
103762306a36Sopenharmony_ci					vcpu->arch.host_cp0_badvaddr) & (~0x3);
103862306a36Sopenharmony_ci		run->mmio.len = 4;
103962306a36Sopenharmony_ci		imme = vcpu->arch.host_cp0_badvaddr & 0x3;
104062306a36Sopenharmony_ci		switch (imme) {
104162306a36Sopenharmony_ci		case 0:
104262306a36Sopenharmony_ci			*(u32 *)data = ((*(u32 *)data) & 0xffffff00) |
104362306a36Sopenharmony_ci					(vcpu->arch.gprs[rt] >> 24);
104462306a36Sopenharmony_ci			break;
104562306a36Sopenharmony_ci		case 1:
104662306a36Sopenharmony_ci			*(u32 *)data = ((*(u32 *)data) & 0xffff0000) |
104762306a36Sopenharmony_ci					(vcpu->arch.gprs[rt] >> 16);
104862306a36Sopenharmony_ci			break;
104962306a36Sopenharmony_ci		case 2:
105062306a36Sopenharmony_ci			*(u32 *)data = ((*(u32 *)data) & 0xff000000) |
105162306a36Sopenharmony_ci					(vcpu->arch.gprs[rt] >> 8);
105262306a36Sopenharmony_ci			break;
105362306a36Sopenharmony_ci		case 3:
105462306a36Sopenharmony_ci			*(u32 *)data = vcpu->arch.gprs[rt];
105562306a36Sopenharmony_ci			break;
105662306a36Sopenharmony_ci		default:
105762306a36Sopenharmony_ci			break;
105862306a36Sopenharmony_ci		}
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci		kvm_debug("[%#lx] OP_SWL: eaddr: %#lx, gpr: %#lx, data: %#x\n",
106162306a36Sopenharmony_ci			  vcpu->arch.pc, vcpu->arch.host_cp0_badvaddr,
106262306a36Sopenharmony_ci			  vcpu->arch.gprs[rt], *(u32 *)data);
106362306a36Sopenharmony_ci		break;
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci	case swr_op:
106662306a36Sopenharmony_ci		run->mmio.phys_addr = kvm_mips_callbacks->gva_to_gpa(
106762306a36Sopenharmony_ci					vcpu->arch.host_cp0_badvaddr) & (~0x3);
106862306a36Sopenharmony_ci		run->mmio.len = 4;
106962306a36Sopenharmony_ci		imme = vcpu->arch.host_cp0_badvaddr & 0x3;
107062306a36Sopenharmony_ci		switch (imme) {
107162306a36Sopenharmony_ci		case 0:
107262306a36Sopenharmony_ci			*(u32 *)data = vcpu->arch.gprs[rt];
107362306a36Sopenharmony_ci			break;
107462306a36Sopenharmony_ci		case 1:
107562306a36Sopenharmony_ci			*(u32 *)data = ((*(u32 *)data) & 0xff) |
107662306a36Sopenharmony_ci					(vcpu->arch.gprs[rt] << 8);
107762306a36Sopenharmony_ci			break;
107862306a36Sopenharmony_ci		case 2:
107962306a36Sopenharmony_ci			*(u32 *)data = ((*(u32 *)data) & 0xffff) |
108062306a36Sopenharmony_ci					(vcpu->arch.gprs[rt] << 16);
108162306a36Sopenharmony_ci			break;
108262306a36Sopenharmony_ci		case 3:
108362306a36Sopenharmony_ci			*(u32 *)data = ((*(u32 *)data) & 0xffffff) |
108462306a36Sopenharmony_ci					(vcpu->arch.gprs[rt] << 24);
108562306a36Sopenharmony_ci			break;
108662306a36Sopenharmony_ci		default:
108762306a36Sopenharmony_ci			break;
108862306a36Sopenharmony_ci		}
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_ci		kvm_debug("[%#lx] OP_SWR: eaddr: %#lx, gpr: %#lx, data: %#x\n",
109162306a36Sopenharmony_ci			  vcpu->arch.pc, vcpu->arch.host_cp0_badvaddr,
109262306a36Sopenharmony_ci			  vcpu->arch.gprs[rt], *(u32 *)data);
109362306a36Sopenharmony_ci		break;
109462306a36Sopenharmony_ci
109562306a36Sopenharmony_ci#if defined(CONFIG_64BIT)
109662306a36Sopenharmony_ci	case sdl_op:
109762306a36Sopenharmony_ci		run->mmio.phys_addr = kvm_mips_callbacks->gva_to_gpa(
109862306a36Sopenharmony_ci					vcpu->arch.host_cp0_badvaddr) & (~0x7);
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci		run->mmio.len = 8;
110162306a36Sopenharmony_ci		imme = vcpu->arch.host_cp0_badvaddr & 0x7;
110262306a36Sopenharmony_ci		switch (imme) {
110362306a36Sopenharmony_ci		case 0:
110462306a36Sopenharmony_ci			*(u64 *)data = ((*(u64 *)data) & 0xffffffffffffff00) |
110562306a36Sopenharmony_ci					((vcpu->arch.gprs[rt] >> 56) & 0xff);
110662306a36Sopenharmony_ci			break;
110762306a36Sopenharmony_ci		case 1:
110862306a36Sopenharmony_ci			*(u64 *)data = ((*(u64 *)data) & 0xffffffffffff0000) |
110962306a36Sopenharmony_ci					((vcpu->arch.gprs[rt] >> 48) & 0xffff);
111062306a36Sopenharmony_ci			break;
111162306a36Sopenharmony_ci		case 2:
111262306a36Sopenharmony_ci			*(u64 *)data = ((*(u64 *)data) & 0xffffffffff000000) |
111362306a36Sopenharmony_ci					((vcpu->arch.gprs[rt] >> 40) & 0xffffff);
111462306a36Sopenharmony_ci			break;
111562306a36Sopenharmony_ci		case 3:
111662306a36Sopenharmony_ci			*(u64 *)data = ((*(u64 *)data) & 0xffffffff00000000) |
111762306a36Sopenharmony_ci					((vcpu->arch.gprs[rt] >> 32) & 0xffffffff);
111862306a36Sopenharmony_ci			break;
111962306a36Sopenharmony_ci		case 4:
112062306a36Sopenharmony_ci			*(u64 *)data = ((*(u64 *)data) & 0xffffff0000000000) |
112162306a36Sopenharmony_ci					((vcpu->arch.gprs[rt] >> 24) & 0xffffffffff);
112262306a36Sopenharmony_ci			break;
112362306a36Sopenharmony_ci		case 5:
112462306a36Sopenharmony_ci			*(u64 *)data = ((*(u64 *)data) & 0xffff000000000000) |
112562306a36Sopenharmony_ci					((vcpu->arch.gprs[rt] >> 16) & 0xffffffffffff);
112662306a36Sopenharmony_ci			break;
112762306a36Sopenharmony_ci		case 6:
112862306a36Sopenharmony_ci			*(u64 *)data = ((*(u64 *)data) & 0xff00000000000000) |
112962306a36Sopenharmony_ci					((vcpu->arch.gprs[rt] >> 8) & 0xffffffffffffff);
113062306a36Sopenharmony_ci			break;
113162306a36Sopenharmony_ci		case 7:
113262306a36Sopenharmony_ci			*(u64 *)data = vcpu->arch.gprs[rt];
113362306a36Sopenharmony_ci			break;
113462306a36Sopenharmony_ci		default:
113562306a36Sopenharmony_ci			break;
113662306a36Sopenharmony_ci		}
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci		kvm_debug("[%#lx] OP_SDL: eaddr: %#lx, gpr: %#lx, data: %llx\n",
113962306a36Sopenharmony_ci			  vcpu->arch.pc, vcpu->arch.host_cp0_badvaddr,
114062306a36Sopenharmony_ci			  vcpu->arch.gprs[rt], *(u64 *)data);
114162306a36Sopenharmony_ci		break;
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_ci	case sdr_op:
114462306a36Sopenharmony_ci		run->mmio.phys_addr = kvm_mips_callbacks->gva_to_gpa(
114562306a36Sopenharmony_ci					vcpu->arch.host_cp0_badvaddr) & (~0x7);
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_ci		run->mmio.len = 8;
114862306a36Sopenharmony_ci		imme = vcpu->arch.host_cp0_badvaddr & 0x7;
114962306a36Sopenharmony_ci		switch (imme) {
115062306a36Sopenharmony_ci		case 0:
115162306a36Sopenharmony_ci			*(u64 *)data = vcpu->arch.gprs[rt];
115262306a36Sopenharmony_ci			break;
115362306a36Sopenharmony_ci		case 1:
115462306a36Sopenharmony_ci			*(u64 *)data = ((*(u64 *)data) & 0xff) |
115562306a36Sopenharmony_ci					(vcpu->arch.gprs[rt] << 8);
115662306a36Sopenharmony_ci			break;
115762306a36Sopenharmony_ci		case 2:
115862306a36Sopenharmony_ci			*(u64 *)data = ((*(u64 *)data) & 0xffff) |
115962306a36Sopenharmony_ci					(vcpu->arch.gprs[rt] << 16);
116062306a36Sopenharmony_ci			break;
116162306a36Sopenharmony_ci		case 3:
116262306a36Sopenharmony_ci			*(u64 *)data = ((*(u64 *)data) & 0xffffff) |
116362306a36Sopenharmony_ci					(vcpu->arch.gprs[rt] << 24);
116462306a36Sopenharmony_ci			break;
116562306a36Sopenharmony_ci		case 4:
116662306a36Sopenharmony_ci			*(u64 *)data = ((*(u64 *)data) & 0xffffffff) |
116762306a36Sopenharmony_ci					(vcpu->arch.gprs[rt] << 32);
116862306a36Sopenharmony_ci			break;
116962306a36Sopenharmony_ci		case 5:
117062306a36Sopenharmony_ci			*(u64 *)data = ((*(u64 *)data) & 0xffffffffff) |
117162306a36Sopenharmony_ci					(vcpu->arch.gprs[rt] << 40);
117262306a36Sopenharmony_ci			break;
117362306a36Sopenharmony_ci		case 6:
117462306a36Sopenharmony_ci			*(u64 *)data = ((*(u64 *)data) & 0xffffffffffff) |
117562306a36Sopenharmony_ci					(vcpu->arch.gprs[rt] << 48);
117662306a36Sopenharmony_ci			break;
117762306a36Sopenharmony_ci		case 7:
117862306a36Sopenharmony_ci			*(u64 *)data = ((*(u64 *)data) & 0xffffffffffffff) |
117962306a36Sopenharmony_ci					(vcpu->arch.gprs[rt] << 56);
118062306a36Sopenharmony_ci			break;
118162306a36Sopenharmony_ci		default:
118262306a36Sopenharmony_ci			break;
118362306a36Sopenharmony_ci		}
118462306a36Sopenharmony_ci
118562306a36Sopenharmony_ci		kvm_debug("[%#lx] OP_SDR: eaddr: %#lx, gpr: %#lx, data: %llx\n",
118662306a36Sopenharmony_ci			  vcpu->arch.pc, vcpu->arch.host_cp0_badvaddr,
118762306a36Sopenharmony_ci			  vcpu->arch.gprs[rt], *(u64 *)data);
118862306a36Sopenharmony_ci		break;
118962306a36Sopenharmony_ci#endif
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_ci#ifdef CONFIG_CPU_LOONGSON64
119262306a36Sopenharmony_ci	case sdc2_op:
119362306a36Sopenharmony_ci		rt = inst.loongson3_lsdc2_format.rt;
119462306a36Sopenharmony_ci		switch (inst.loongson3_lsdc2_format.opcode1) {
119562306a36Sopenharmony_ci		/*
119662306a36Sopenharmony_ci		 * Loongson-3 overridden sdc2 instructions.
119762306a36Sopenharmony_ci		 * opcode1              instruction
119862306a36Sopenharmony_ci		 *   0x0          gssbx: store 1 bytes from GPR
119962306a36Sopenharmony_ci		 *   0x1          gsshx: store 2 bytes from GPR
120062306a36Sopenharmony_ci		 *   0x2          gsswx: store 4 bytes from GPR
120162306a36Sopenharmony_ci		 *   0x3          gssdx: store 8 bytes from GPR
120262306a36Sopenharmony_ci		 */
120362306a36Sopenharmony_ci		case 0x0:
120462306a36Sopenharmony_ci			run->mmio.len = 1;
120562306a36Sopenharmony_ci			*(u8 *)data = vcpu->arch.gprs[rt];
120662306a36Sopenharmony_ci
120762306a36Sopenharmony_ci			kvm_debug("[%#lx] OP_GSSBX: eaddr: %#lx, gpr: %#lx, data: %#x\n",
120862306a36Sopenharmony_ci				  vcpu->arch.pc, vcpu->arch.host_cp0_badvaddr,
120962306a36Sopenharmony_ci				  vcpu->arch.gprs[rt], *(u8 *)data);
121062306a36Sopenharmony_ci			break;
121162306a36Sopenharmony_ci		case 0x1:
121262306a36Sopenharmony_ci			run->mmio.len = 2;
121362306a36Sopenharmony_ci			*(u16 *)data = vcpu->arch.gprs[rt];
121462306a36Sopenharmony_ci
121562306a36Sopenharmony_ci			kvm_debug("[%#lx] OP_GSSSHX: eaddr: %#lx, gpr: %#lx, data: %#x\n",
121662306a36Sopenharmony_ci				  vcpu->arch.pc, vcpu->arch.host_cp0_badvaddr,
121762306a36Sopenharmony_ci				  vcpu->arch.gprs[rt], *(u16 *)data);
121862306a36Sopenharmony_ci			break;
121962306a36Sopenharmony_ci		case 0x2:
122062306a36Sopenharmony_ci			run->mmio.len = 4;
122162306a36Sopenharmony_ci			*(u32 *)data = vcpu->arch.gprs[rt];
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci			kvm_debug("[%#lx] OP_GSSWX: eaddr: %#lx, gpr: %#lx, data: %#x\n",
122462306a36Sopenharmony_ci				  vcpu->arch.pc, vcpu->arch.host_cp0_badvaddr,
122562306a36Sopenharmony_ci				  vcpu->arch.gprs[rt], *(u32 *)data);
122662306a36Sopenharmony_ci			break;
122762306a36Sopenharmony_ci		case 0x3:
122862306a36Sopenharmony_ci			run->mmio.len = 8;
122962306a36Sopenharmony_ci			*(u64 *)data = vcpu->arch.gprs[rt];
123062306a36Sopenharmony_ci
123162306a36Sopenharmony_ci			kvm_debug("[%#lx] OP_GSSDX: eaddr: %#lx, gpr: %#lx, data: %#llx\n",
123262306a36Sopenharmony_ci				  vcpu->arch.pc, vcpu->arch.host_cp0_badvaddr,
123362306a36Sopenharmony_ci				  vcpu->arch.gprs[rt], *(u64 *)data);
123462306a36Sopenharmony_ci			break;
123562306a36Sopenharmony_ci		default:
123662306a36Sopenharmony_ci			kvm_err("Godson Extended GS-Store not yet supported (inst=0x%08x)\n",
123762306a36Sopenharmony_ci				inst.word);
123862306a36Sopenharmony_ci			break;
123962306a36Sopenharmony_ci		}
124062306a36Sopenharmony_ci		break;
124162306a36Sopenharmony_ci#endif
124262306a36Sopenharmony_ci	default:
124362306a36Sopenharmony_ci		kvm_err("Store not yet supported (inst=0x%08x)\n",
124462306a36Sopenharmony_ci			inst.word);
124562306a36Sopenharmony_ci		goto out_fail;
124662306a36Sopenharmony_ci	}
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_ci	vcpu->mmio_needed = 1;
124962306a36Sopenharmony_ci	run->mmio.is_write = 1;
125062306a36Sopenharmony_ci	vcpu->mmio_is_write = 1;
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_ci	r = kvm_io_bus_write(vcpu, KVM_MMIO_BUS,
125362306a36Sopenharmony_ci			run->mmio.phys_addr, run->mmio.len, data);
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_ci	if (!r) {
125662306a36Sopenharmony_ci		vcpu->mmio_needed = 0;
125762306a36Sopenharmony_ci		return EMULATE_DONE;
125862306a36Sopenharmony_ci	}
125962306a36Sopenharmony_ci
126062306a36Sopenharmony_ci	return EMULATE_DO_MMIO;
126162306a36Sopenharmony_ci
126262306a36Sopenharmony_ciout_fail:
126362306a36Sopenharmony_ci	/* Rollback PC if emulation was unsuccessful */
126462306a36Sopenharmony_ci	vcpu->arch.pc = curr_pc;
126562306a36Sopenharmony_ci	return EMULATE_FAIL;
126662306a36Sopenharmony_ci}
126762306a36Sopenharmony_ci
126862306a36Sopenharmony_cienum emulation_result kvm_mips_emulate_load(union mips_instruction inst,
126962306a36Sopenharmony_ci					    u32 cause, struct kvm_vcpu *vcpu)
127062306a36Sopenharmony_ci{
127162306a36Sopenharmony_ci	struct kvm_run *run = vcpu->run;
127262306a36Sopenharmony_ci	int r;
127362306a36Sopenharmony_ci	enum emulation_result er;
127462306a36Sopenharmony_ci	unsigned long curr_pc;
127562306a36Sopenharmony_ci	u32 op, rt;
127662306a36Sopenharmony_ci	unsigned int imme;
127762306a36Sopenharmony_ci
127862306a36Sopenharmony_ci	rt = inst.i_format.rt;
127962306a36Sopenharmony_ci	op = inst.i_format.opcode;
128062306a36Sopenharmony_ci
128162306a36Sopenharmony_ci	/*
128262306a36Sopenharmony_ci	 * Find the resume PC now while we have safe and easy access to the
128362306a36Sopenharmony_ci	 * prior branch instruction, and save it for
128462306a36Sopenharmony_ci	 * kvm_mips_complete_mmio_load() to restore later.
128562306a36Sopenharmony_ci	 */
128662306a36Sopenharmony_ci	curr_pc = vcpu->arch.pc;
128762306a36Sopenharmony_ci	er = update_pc(vcpu, cause);
128862306a36Sopenharmony_ci	if (er == EMULATE_FAIL)
128962306a36Sopenharmony_ci		return er;
129062306a36Sopenharmony_ci	vcpu->arch.io_pc = vcpu->arch.pc;
129162306a36Sopenharmony_ci	vcpu->arch.pc = curr_pc;
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_ci	vcpu->arch.io_gpr = rt;
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ci	run->mmio.phys_addr = kvm_mips_callbacks->gva_to_gpa(
129662306a36Sopenharmony_ci						vcpu->arch.host_cp0_badvaddr);
129762306a36Sopenharmony_ci	if (run->mmio.phys_addr == KVM_INVALID_ADDR)
129862306a36Sopenharmony_ci		return EMULATE_FAIL;
129962306a36Sopenharmony_ci
130062306a36Sopenharmony_ci	vcpu->mmio_needed = 2;	/* signed */
130162306a36Sopenharmony_ci	switch (op) {
130262306a36Sopenharmony_ci#if defined(CONFIG_64BIT)
130362306a36Sopenharmony_ci	case ld_op:
130462306a36Sopenharmony_ci		run->mmio.len = 8;
130562306a36Sopenharmony_ci		break;
130662306a36Sopenharmony_ci
130762306a36Sopenharmony_ci	case lwu_op:
130862306a36Sopenharmony_ci		vcpu->mmio_needed = 1;	/* unsigned */
130962306a36Sopenharmony_ci		fallthrough;
131062306a36Sopenharmony_ci#endif
131162306a36Sopenharmony_ci	case lw_op:
131262306a36Sopenharmony_ci		run->mmio.len = 4;
131362306a36Sopenharmony_ci		break;
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_ci	case lhu_op:
131662306a36Sopenharmony_ci		vcpu->mmio_needed = 1;	/* unsigned */
131762306a36Sopenharmony_ci		fallthrough;
131862306a36Sopenharmony_ci	case lh_op:
131962306a36Sopenharmony_ci		run->mmio.len = 2;
132062306a36Sopenharmony_ci		break;
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_ci	case lbu_op:
132362306a36Sopenharmony_ci		vcpu->mmio_needed = 1;	/* unsigned */
132462306a36Sopenharmony_ci		fallthrough;
132562306a36Sopenharmony_ci	case lb_op:
132662306a36Sopenharmony_ci		run->mmio.len = 1;
132762306a36Sopenharmony_ci		break;
132862306a36Sopenharmony_ci
132962306a36Sopenharmony_ci	case lwl_op:
133062306a36Sopenharmony_ci		run->mmio.phys_addr = kvm_mips_callbacks->gva_to_gpa(
133162306a36Sopenharmony_ci					vcpu->arch.host_cp0_badvaddr) & (~0x3);
133262306a36Sopenharmony_ci
133362306a36Sopenharmony_ci		run->mmio.len = 4;
133462306a36Sopenharmony_ci		imme = vcpu->arch.host_cp0_badvaddr & 0x3;
133562306a36Sopenharmony_ci		switch (imme) {
133662306a36Sopenharmony_ci		case 0:
133762306a36Sopenharmony_ci			vcpu->mmio_needed = 3;	/* 1 byte */
133862306a36Sopenharmony_ci			break;
133962306a36Sopenharmony_ci		case 1:
134062306a36Sopenharmony_ci			vcpu->mmio_needed = 4;	/* 2 bytes */
134162306a36Sopenharmony_ci			break;
134262306a36Sopenharmony_ci		case 2:
134362306a36Sopenharmony_ci			vcpu->mmio_needed = 5;	/* 3 bytes */
134462306a36Sopenharmony_ci			break;
134562306a36Sopenharmony_ci		case 3:
134662306a36Sopenharmony_ci			vcpu->mmio_needed = 6;	/* 4 bytes */
134762306a36Sopenharmony_ci			break;
134862306a36Sopenharmony_ci		default:
134962306a36Sopenharmony_ci			break;
135062306a36Sopenharmony_ci		}
135162306a36Sopenharmony_ci		break;
135262306a36Sopenharmony_ci
135362306a36Sopenharmony_ci	case lwr_op:
135462306a36Sopenharmony_ci		run->mmio.phys_addr = kvm_mips_callbacks->gva_to_gpa(
135562306a36Sopenharmony_ci					vcpu->arch.host_cp0_badvaddr) & (~0x3);
135662306a36Sopenharmony_ci
135762306a36Sopenharmony_ci		run->mmio.len = 4;
135862306a36Sopenharmony_ci		imme = vcpu->arch.host_cp0_badvaddr & 0x3;
135962306a36Sopenharmony_ci		switch (imme) {
136062306a36Sopenharmony_ci		case 0:
136162306a36Sopenharmony_ci			vcpu->mmio_needed = 7;	/* 4 bytes */
136262306a36Sopenharmony_ci			break;
136362306a36Sopenharmony_ci		case 1:
136462306a36Sopenharmony_ci			vcpu->mmio_needed = 8;	/* 3 bytes */
136562306a36Sopenharmony_ci			break;
136662306a36Sopenharmony_ci		case 2:
136762306a36Sopenharmony_ci			vcpu->mmio_needed = 9;	/* 2 bytes */
136862306a36Sopenharmony_ci			break;
136962306a36Sopenharmony_ci		case 3:
137062306a36Sopenharmony_ci			vcpu->mmio_needed = 10;	/* 1 byte */
137162306a36Sopenharmony_ci			break;
137262306a36Sopenharmony_ci		default:
137362306a36Sopenharmony_ci			break;
137462306a36Sopenharmony_ci		}
137562306a36Sopenharmony_ci		break;
137662306a36Sopenharmony_ci
137762306a36Sopenharmony_ci#if defined(CONFIG_64BIT)
137862306a36Sopenharmony_ci	case ldl_op:
137962306a36Sopenharmony_ci		run->mmio.phys_addr = kvm_mips_callbacks->gva_to_gpa(
138062306a36Sopenharmony_ci					vcpu->arch.host_cp0_badvaddr) & (~0x7);
138162306a36Sopenharmony_ci
138262306a36Sopenharmony_ci		run->mmio.len = 8;
138362306a36Sopenharmony_ci		imme = vcpu->arch.host_cp0_badvaddr & 0x7;
138462306a36Sopenharmony_ci		switch (imme) {
138562306a36Sopenharmony_ci		case 0:
138662306a36Sopenharmony_ci			vcpu->mmio_needed = 11;	/* 1 byte */
138762306a36Sopenharmony_ci			break;
138862306a36Sopenharmony_ci		case 1:
138962306a36Sopenharmony_ci			vcpu->mmio_needed = 12;	/* 2 bytes */
139062306a36Sopenharmony_ci			break;
139162306a36Sopenharmony_ci		case 2:
139262306a36Sopenharmony_ci			vcpu->mmio_needed = 13;	/* 3 bytes */
139362306a36Sopenharmony_ci			break;
139462306a36Sopenharmony_ci		case 3:
139562306a36Sopenharmony_ci			vcpu->mmio_needed = 14;	/* 4 bytes */
139662306a36Sopenharmony_ci			break;
139762306a36Sopenharmony_ci		case 4:
139862306a36Sopenharmony_ci			vcpu->mmio_needed = 15;	/* 5 bytes */
139962306a36Sopenharmony_ci			break;
140062306a36Sopenharmony_ci		case 5:
140162306a36Sopenharmony_ci			vcpu->mmio_needed = 16;	/* 6 bytes */
140262306a36Sopenharmony_ci			break;
140362306a36Sopenharmony_ci		case 6:
140462306a36Sopenharmony_ci			vcpu->mmio_needed = 17;	/* 7 bytes */
140562306a36Sopenharmony_ci			break;
140662306a36Sopenharmony_ci		case 7:
140762306a36Sopenharmony_ci			vcpu->mmio_needed = 18;	/* 8 bytes */
140862306a36Sopenharmony_ci			break;
140962306a36Sopenharmony_ci		default:
141062306a36Sopenharmony_ci			break;
141162306a36Sopenharmony_ci		}
141262306a36Sopenharmony_ci		break;
141362306a36Sopenharmony_ci
141462306a36Sopenharmony_ci	case ldr_op:
141562306a36Sopenharmony_ci		run->mmio.phys_addr = kvm_mips_callbacks->gva_to_gpa(
141662306a36Sopenharmony_ci					vcpu->arch.host_cp0_badvaddr) & (~0x7);
141762306a36Sopenharmony_ci
141862306a36Sopenharmony_ci		run->mmio.len = 8;
141962306a36Sopenharmony_ci		imme = vcpu->arch.host_cp0_badvaddr & 0x7;
142062306a36Sopenharmony_ci		switch (imme) {
142162306a36Sopenharmony_ci		case 0:
142262306a36Sopenharmony_ci			vcpu->mmio_needed = 19;	/* 8 bytes */
142362306a36Sopenharmony_ci			break;
142462306a36Sopenharmony_ci		case 1:
142562306a36Sopenharmony_ci			vcpu->mmio_needed = 20;	/* 7 bytes */
142662306a36Sopenharmony_ci			break;
142762306a36Sopenharmony_ci		case 2:
142862306a36Sopenharmony_ci			vcpu->mmio_needed = 21;	/* 6 bytes */
142962306a36Sopenharmony_ci			break;
143062306a36Sopenharmony_ci		case 3:
143162306a36Sopenharmony_ci			vcpu->mmio_needed = 22;	/* 5 bytes */
143262306a36Sopenharmony_ci			break;
143362306a36Sopenharmony_ci		case 4:
143462306a36Sopenharmony_ci			vcpu->mmio_needed = 23;	/* 4 bytes */
143562306a36Sopenharmony_ci			break;
143662306a36Sopenharmony_ci		case 5:
143762306a36Sopenharmony_ci			vcpu->mmio_needed = 24;	/* 3 bytes */
143862306a36Sopenharmony_ci			break;
143962306a36Sopenharmony_ci		case 6:
144062306a36Sopenharmony_ci			vcpu->mmio_needed = 25;	/* 2 bytes */
144162306a36Sopenharmony_ci			break;
144262306a36Sopenharmony_ci		case 7:
144362306a36Sopenharmony_ci			vcpu->mmio_needed = 26;	/* 1 byte */
144462306a36Sopenharmony_ci			break;
144562306a36Sopenharmony_ci		default:
144662306a36Sopenharmony_ci			break;
144762306a36Sopenharmony_ci		}
144862306a36Sopenharmony_ci		break;
144962306a36Sopenharmony_ci#endif
145062306a36Sopenharmony_ci
145162306a36Sopenharmony_ci#ifdef CONFIG_CPU_LOONGSON64
145262306a36Sopenharmony_ci	case ldc2_op:
145362306a36Sopenharmony_ci		rt = inst.loongson3_lsdc2_format.rt;
145462306a36Sopenharmony_ci		switch (inst.loongson3_lsdc2_format.opcode1) {
145562306a36Sopenharmony_ci		/*
145662306a36Sopenharmony_ci		 * Loongson-3 overridden ldc2 instructions.
145762306a36Sopenharmony_ci		 * opcode1              instruction
145862306a36Sopenharmony_ci		 *   0x0          gslbx: store 1 bytes from GPR
145962306a36Sopenharmony_ci		 *   0x1          gslhx: store 2 bytes from GPR
146062306a36Sopenharmony_ci		 *   0x2          gslwx: store 4 bytes from GPR
146162306a36Sopenharmony_ci		 *   0x3          gsldx: store 8 bytes from GPR
146262306a36Sopenharmony_ci		 */
146362306a36Sopenharmony_ci		case 0x0:
146462306a36Sopenharmony_ci			run->mmio.len = 1;
146562306a36Sopenharmony_ci			vcpu->mmio_needed = 27;	/* signed */
146662306a36Sopenharmony_ci			break;
146762306a36Sopenharmony_ci		case 0x1:
146862306a36Sopenharmony_ci			run->mmio.len = 2;
146962306a36Sopenharmony_ci			vcpu->mmio_needed = 28;	/* signed */
147062306a36Sopenharmony_ci			break;
147162306a36Sopenharmony_ci		case 0x2:
147262306a36Sopenharmony_ci			run->mmio.len = 4;
147362306a36Sopenharmony_ci			vcpu->mmio_needed = 29;	/* signed */
147462306a36Sopenharmony_ci			break;
147562306a36Sopenharmony_ci		case 0x3:
147662306a36Sopenharmony_ci			run->mmio.len = 8;
147762306a36Sopenharmony_ci			vcpu->mmio_needed = 30;	/* signed */
147862306a36Sopenharmony_ci			break;
147962306a36Sopenharmony_ci		default:
148062306a36Sopenharmony_ci			kvm_err("Godson Extended GS-Load for float not yet supported (inst=0x%08x)\n",
148162306a36Sopenharmony_ci				inst.word);
148262306a36Sopenharmony_ci			break;
148362306a36Sopenharmony_ci		}
148462306a36Sopenharmony_ci		break;
148562306a36Sopenharmony_ci#endif
148662306a36Sopenharmony_ci
148762306a36Sopenharmony_ci	default:
148862306a36Sopenharmony_ci		kvm_err("Load not yet supported (inst=0x%08x)\n",
148962306a36Sopenharmony_ci			inst.word);
149062306a36Sopenharmony_ci		vcpu->mmio_needed = 0;
149162306a36Sopenharmony_ci		return EMULATE_FAIL;
149262306a36Sopenharmony_ci	}
149362306a36Sopenharmony_ci
149462306a36Sopenharmony_ci	run->mmio.is_write = 0;
149562306a36Sopenharmony_ci	vcpu->mmio_is_write = 0;
149662306a36Sopenharmony_ci
149762306a36Sopenharmony_ci	r = kvm_io_bus_read(vcpu, KVM_MMIO_BUS,
149862306a36Sopenharmony_ci			run->mmio.phys_addr, run->mmio.len, run->mmio.data);
149962306a36Sopenharmony_ci
150062306a36Sopenharmony_ci	if (!r) {
150162306a36Sopenharmony_ci		kvm_mips_complete_mmio_load(vcpu);
150262306a36Sopenharmony_ci		vcpu->mmio_needed = 0;
150362306a36Sopenharmony_ci		return EMULATE_DONE;
150462306a36Sopenharmony_ci	}
150562306a36Sopenharmony_ci
150662306a36Sopenharmony_ci	return EMULATE_DO_MMIO;
150762306a36Sopenharmony_ci}
150862306a36Sopenharmony_ci
150962306a36Sopenharmony_cienum emulation_result kvm_mips_complete_mmio_load(struct kvm_vcpu *vcpu)
151062306a36Sopenharmony_ci{
151162306a36Sopenharmony_ci	struct kvm_run *run = vcpu->run;
151262306a36Sopenharmony_ci	unsigned long *gpr = &vcpu->arch.gprs[vcpu->arch.io_gpr];
151362306a36Sopenharmony_ci	enum emulation_result er = EMULATE_DONE;
151462306a36Sopenharmony_ci
151562306a36Sopenharmony_ci	if (run->mmio.len > sizeof(*gpr)) {
151662306a36Sopenharmony_ci		kvm_err("Bad MMIO length: %d", run->mmio.len);
151762306a36Sopenharmony_ci		er = EMULATE_FAIL;
151862306a36Sopenharmony_ci		goto done;
151962306a36Sopenharmony_ci	}
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_ci	/* Restore saved resume PC */
152262306a36Sopenharmony_ci	vcpu->arch.pc = vcpu->arch.io_pc;
152362306a36Sopenharmony_ci
152462306a36Sopenharmony_ci	switch (run->mmio.len) {
152562306a36Sopenharmony_ci	case 8:
152662306a36Sopenharmony_ci		switch (vcpu->mmio_needed) {
152762306a36Sopenharmony_ci		case 11:
152862306a36Sopenharmony_ci			*gpr = (vcpu->arch.gprs[vcpu->arch.io_gpr] & 0xffffffffffffff) |
152962306a36Sopenharmony_ci				(((*(s64 *)run->mmio.data) & 0xff) << 56);
153062306a36Sopenharmony_ci			break;
153162306a36Sopenharmony_ci		case 12:
153262306a36Sopenharmony_ci			*gpr = (vcpu->arch.gprs[vcpu->arch.io_gpr] & 0xffffffffffff) |
153362306a36Sopenharmony_ci				(((*(s64 *)run->mmio.data) & 0xffff) << 48);
153462306a36Sopenharmony_ci			break;
153562306a36Sopenharmony_ci		case 13:
153662306a36Sopenharmony_ci			*gpr = (vcpu->arch.gprs[vcpu->arch.io_gpr] & 0xffffffffff) |
153762306a36Sopenharmony_ci				(((*(s64 *)run->mmio.data) & 0xffffff) << 40);
153862306a36Sopenharmony_ci			break;
153962306a36Sopenharmony_ci		case 14:
154062306a36Sopenharmony_ci			*gpr = (vcpu->arch.gprs[vcpu->arch.io_gpr] & 0xffffffff) |
154162306a36Sopenharmony_ci				(((*(s64 *)run->mmio.data) & 0xffffffff) << 32);
154262306a36Sopenharmony_ci			break;
154362306a36Sopenharmony_ci		case 15:
154462306a36Sopenharmony_ci			*gpr = (vcpu->arch.gprs[vcpu->arch.io_gpr] & 0xffffff) |
154562306a36Sopenharmony_ci				(((*(s64 *)run->mmio.data) & 0xffffffffff) << 24);
154662306a36Sopenharmony_ci			break;
154762306a36Sopenharmony_ci		case 16:
154862306a36Sopenharmony_ci			*gpr = (vcpu->arch.gprs[vcpu->arch.io_gpr] & 0xffff) |
154962306a36Sopenharmony_ci				(((*(s64 *)run->mmio.data) & 0xffffffffffff) << 16);
155062306a36Sopenharmony_ci			break;
155162306a36Sopenharmony_ci		case 17:
155262306a36Sopenharmony_ci			*gpr = (vcpu->arch.gprs[vcpu->arch.io_gpr] & 0xff) |
155362306a36Sopenharmony_ci				(((*(s64 *)run->mmio.data) & 0xffffffffffffff) << 8);
155462306a36Sopenharmony_ci			break;
155562306a36Sopenharmony_ci		case 18:
155662306a36Sopenharmony_ci		case 19:
155762306a36Sopenharmony_ci			*gpr = *(s64 *)run->mmio.data;
155862306a36Sopenharmony_ci			break;
155962306a36Sopenharmony_ci		case 20:
156062306a36Sopenharmony_ci			*gpr = (vcpu->arch.gprs[vcpu->arch.io_gpr] & 0xff00000000000000) |
156162306a36Sopenharmony_ci				((((*(s64 *)run->mmio.data)) >> 8) & 0xffffffffffffff);
156262306a36Sopenharmony_ci			break;
156362306a36Sopenharmony_ci		case 21:
156462306a36Sopenharmony_ci			*gpr = (vcpu->arch.gprs[vcpu->arch.io_gpr] & 0xffff000000000000) |
156562306a36Sopenharmony_ci				((((*(s64 *)run->mmio.data)) >> 16) & 0xffffffffffff);
156662306a36Sopenharmony_ci			break;
156762306a36Sopenharmony_ci		case 22:
156862306a36Sopenharmony_ci			*gpr = (vcpu->arch.gprs[vcpu->arch.io_gpr] & 0xffffff0000000000) |
156962306a36Sopenharmony_ci				((((*(s64 *)run->mmio.data)) >> 24) & 0xffffffffff);
157062306a36Sopenharmony_ci			break;
157162306a36Sopenharmony_ci		case 23:
157262306a36Sopenharmony_ci			*gpr = (vcpu->arch.gprs[vcpu->arch.io_gpr] & 0xffffffff00000000) |
157362306a36Sopenharmony_ci				((((*(s64 *)run->mmio.data)) >> 32) & 0xffffffff);
157462306a36Sopenharmony_ci			break;
157562306a36Sopenharmony_ci		case 24:
157662306a36Sopenharmony_ci			*gpr = (vcpu->arch.gprs[vcpu->arch.io_gpr] & 0xffffffffff000000) |
157762306a36Sopenharmony_ci				((((*(s64 *)run->mmio.data)) >> 40) & 0xffffff);
157862306a36Sopenharmony_ci			break;
157962306a36Sopenharmony_ci		case 25:
158062306a36Sopenharmony_ci			*gpr = (vcpu->arch.gprs[vcpu->arch.io_gpr] & 0xffffffffffff0000) |
158162306a36Sopenharmony_ci				((((*(s64 *)run->mmio.data)) >> 48) & 0xffff);
158262306a36Sopenharmony_ci			break;
158362306a36Sopenharmony_ci		case 26:
158462306a36Sopenharmony_ci			*gpr = (vcpu->arch.gprs[vcpu->arch.io_gpr] & 0xffffffffffffff00) |
158562306a36Sopenharmony_ci				((((*(s64 *)run->mmio.data)) >> 56) & 0xff);
158662306a36Sopenharmony_ci			break;
158762306a36Sopenharmony_ci		default:
158862306a36Sopenharmony_ci			*gpr = *(s64 *)run->mmio.data;
158962306a36Sopenharmony_ci		}
159062306a36Sopenharmony_ci		break;
159162306a36Sopenharmony_ci
159262306a36Sopenharmony_ci	case 4:
159362306a36Sopenharmony_ci		switch (vcpu->mmio_needed) {
159462306a36Sopenharmony_ci		case 1:
159562306a36Sopenharmony_ci			*gpr = *(u32 *)run->mmio.data;
159662306a36Sopenharmony_ci			break;
159762306a36Sopenharmony_ci		case 2:
159862306a36Sopenharmony_ci			*gpr = *(s32 *)run->mmio.data;
159962306a36Sopenharmony_ci			break;
160062306a36Sopenharmony_ci		case 3:
160162306a36Sopenharmony_ci			*gpr = (vcpu->arch.gprs[vcpu->arch.io_gpr] & 0xffffff) |
160262306a36Sopenharmony_ci				(((*(s32 *)run->mmio.data) & 0xff) << 24);
160362306a36Sopenharmony_ci			break;
160462306a36Sopenharmony_ci		case 4:
160562306a36Sopenharmony_ci			*gpr = (vcpu->arch.gprs[vcpu->arch.io_gpr] & 0xffff) |
160662306a36Sopenharmony_ci				(((*(s32 *)run->mmio.data) & 0xffff) << 16);
160762306a36Sopenharmony_ci			break;
160862306a36Sopenharmony_ci		case 5:
160962306a36Sopenharmony_ci			*gpr = (vcpu->arch.gprs[vcpu->arch.io_gpr] & 0xff) |
161062306a36Sopenharmony_ci				(((*(s32 *)run->mmio.data) & 0xffffff) << 8);
161162306a36Sopenharmony_ci			break;
161262306a36Sopenharmony_ci		case 6:
161362306a36Sopenharmony_ci		case 7:
161462306a36Sopenharmony_ci			*gpr = *(s32 *)run->mmio.data;
161562306a36Sopenharmony_ci			break;
161662306a36Sopenharmony_ci		case 8:
161762306a36Sopenharmony_ci			*gpr = (vcpu->arch.gprs[vcpu->arch.io_gpr] & 0xff000000) |
161862306a36Sopenharmony_ci				((((*(s32 *)run->mmio.data)) >> 8) & 0xffffff);
161962306a36Sopenharmony_ci			break;
162062306a36Sopenharmony_ci		case 9:
162162306a36Sopenharmony_ci			*gpr = (vcpu->arch.gprs[vcpu->arch.io_gpr] & 0xffff0000) |
162262306a36Sopenharmony_ci				((((*(s32 *)run->mmio.data)) >> 16) & 0xffff);
162362306a36Sopenharmony_ci			break;
162462306a36Sopenharmony_ci		case 10:
162562306a36Sopenharmony_ci			*gpr = (vcpu->arch.gprs[vcpu->arch.io_gpr] & 0xffffff00) |
162662306a36Sopenharmony_ci				((((*(s32 *)run->mmio.data)) >> 24) & 0xff);
162762306a36Sopenharmony_ci			break;
162862306a36Sopenharmony_ci		default:
162962306a36Sopenharmony_ci			*gpr = *(s32 *)run->mmio.data;
163062306a36Sopenharmony_ci		}
163162306a36Sopenharmony_ci		break;
163262306a36Sopenharmony_ci
163362306a36Sopenharmony_ci	case 2:
163462306a36Sopenharmony_ci		if (vcpu->mmio_needed == 1)
163562306a36Sopenharmony_ci			*gpr = *(u16 *)run->mmio.data;
163662306a36Sopenharmony_ci		else
163762306a36Sopenharmony_ci			*gpr = *(s16 *)run->mmio.data;
163862306a36Sopenharmony_ci
163962306a36Sopenharmony_ci		break;
164062306a36Sopenharmony_ci	case 1:
164162306a36Sopenharmony_ci		if (vcpu->mmio_needed == 1)
164262306a36Sopenharmony_ci			*gpr = *(u8 *)run->mmio.data;
164362306a36Sopenharmony_ci		else
164462306a36Sopenharmony_ci			*gpr = *(s8 *)run->mmio.data;
164562306a36Sopenharmony_ci		break;
164662306a36Sopenharmony_ci	}
164762306a36Sopenharmony_ci
164862306a36Sopenharmony_cidone:
164962306a36Sopenharmony_ci	return er;
165062306a36Sopenharmony_ci}
1651