|  | /* | 
|  | * This file is subject to the terms and conditions of the GNU General Public | 
|  | * License.  See the file "COPYING" in the main directory of this archive | 
|  | * for more details. | 
|  | * | 
|  | * KVM/MIPS: Hypercall handling. | 
|  | * | 
|  | * Copyright (C) 2015  Imagination Technologies Ltd. | 
|  | */ | 
|  |  | 
|  | #include <linux/kernel.h> | 
|  | #include <linux/kvm_host.h> | 
|  | #include <linux/kvm_para.h> | 
|  |  | 
|  | #define MAX_HYPCALL_ARGS	4 | 
|  |  | 
|  | enum emulation_result kvm_mips_emul_hypcall(struct kvm_vcpu *vcpu, | 
|  | union mips_instruction inst) | 
|  | { | 
|  | unsigned int code = (inst.co_format.code >> 5) & 0x3ff; | 
|  |  | 
|  | kvm_debug("[%#lx] HYPCALL %#03x\n", vcpu->arch.pc, code); | 
|  |  | 
|  | switch (code) { | 
|  | case 0: | 
|  | return EMULATE_HYPERCALL; | 
|  | default: | 
|  | return EMULATE_FAIL; | 
|  | }; | 
|  | } | 
|  |  | 
|  | static int kvm_mips_hypercall(struct kvm_vcpu *vcpu, unsigned long num, | 
|  | const unsigned long *args, unsigned long *hret) | 
|  | { | 
|  | /* Report unimplemented hypercall to guest */ | 
|  | *hret = -KVM_ENOSYS; | 
|  | return RESUME_GUEST; | 
|  | } | 
|  |  | 
|  | int kvm_mips_handle_hypcall(struct kvm_vcpu *vcpu) | 
|  | { | 
|  | unsigned long num, args[MAX_HYPCALL_ARGS]; | 
|  |  | 
|  | /* read hypcall number and arguments */ | 
|  | num = vcpu->arch.gprs[2];	/* v0 */ | 
|  | args[0] = vcpu->arch.gprs[4];	/* a0 */ | 
|  | args[1] = vcpu->arch.gprs[5];	/* a1 */ | 
|  | args[2] = vcpu->arch.gprs[6];	/* a2 */ | 
|  | args[3] = vcpu->arch.gprs[7];	/* a3 */ | 
|  |  | 
|  | return kvm_mips_hypercall(vcpu, num, | 
|  | args, &vcpu->arch.gprs[2] /* v0 */); | 
|  | } |