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: Hypercall handling.
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Copyright (C) 2015  Imagination Technologies Ltd.
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/kernel.h>
1262306a36Sopenharmony_ci#include <linux/kvm_host.h>
1362306a36Sopenharmony_ci#include <linux/kvm_para.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#define MAX_HYPCALL_ARGS	4
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_cienum emulation_result kvm_mips_emul_hypcall(struct kvm_vcpu *vcpu,
1862306a36Sopenharmony_ci					    union mips_instruction inst)
1962306a36Sopenharmony_ci{
2062306a36Sopenharmony_ci	unsigned int code = (inst.co_format.code >> 5) & 0x3ff;
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci	kvm_debug("[%#lx] HYPCALL %#03x\n", vcpu->arch.pc, code);
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci	switch (code) {
2562306a36Sopenharmony_ci	case 0:
2662306a36Sopenharmony_ci		return EMULATE_HYPERCALL;
2762306a36Sopenharmony_ci	default:
2862306a36Sopenharmony_ci		return EMULATE_FAIL;
2962306a36Sopenharmony_ci	};
3062306a36Sopenharmony_ci}
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_cistatic int kvm_mips_hypercall(struct kvm_vcpu *vcpu, unsigned long num,
3362306a36Sopenharmony_ci			      const unsigned long *args, unsigned long *hret)
3462306a36Sopenharmony_ci{
3562306a36Sopenharmony_ci	/* Report unimplemented hypercall to guest */
3662306a36Sopenharmony_ci	*hret = -KVM_ENOSYS;
3762306a36Sopenharmony_ci	return RESUME_GUEST;
3862306a36Sopenharmony_ci}
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ciint kvm_mips_handle_hypcall(struct kvm_vcpu *vcpu)
4162306a36Sopenharmony_ci{
4262306a36Sopenharmony_ci	unsigned long num, args[MAX_HYPCALL_ARGS];
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	/* read hypcall number and arguments */
4562306a36Sopenharmony_ci	num = vcpu->arch.gprs[2];	/* v0 */
4662306a36Sopenharmony_ci	args[0] = vcpu->arch.gprs[4];	/* a0 */
4762306a36Sopenharmony_ci	args[1] = vcpu->arch.gprs[5];	/* a1 */
4862306a36Sopenharmony_ci	args[2] = vcpu->arch.gprs[6];	/* a2 */
4962306a36Sopenharmony_ci	args[3] = vcpu->arch.gprs[7];	/* a3 */
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	return kvm_mips_hypercall(vcpu, num,
5262306a36Sopenharmony_ci				  args, &vcpu->arch.gprs[2] /* v0 */);
5362306a36Sopenharmony_ci}
54