1/*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License.  See the file "COPYING" in the main directory of this archive
4 * for more details.
5 *
6 * KVM/MIPS: Deliver/Emulate exceptions to the guest kernel
7 *
8 * Copyright (C) 2012  MIPS Technologies, Inc.  All rights reserved.
9 * Authors: Sanjay Lal <sanjayl@kymasys.com>
10 */
11
12#include <linux/errno.h>
13#include <linux/err.h>
14#include <linux/module.h>
15#include <linux/vmalloc.h>
16
17#include <linux/kvm_host.h>
18
19#include "opcode.h"
20#include "interrupt.h"
21
22static gpa_t kvm_trap_emul_gva_to_gpa_cb(gva_t gva)
23{
24	gpa_t gpa;
25	uint32_t kseg = KSEGX(gva);
26
27	if ((kseg == CKSEG0) || (kseg == CKSEG1))
28		gpa = CPHYSADDR(gva);
29	else {
30		kvm_err("%s: cannot find GPA for GVA: %#lx\n", __func__, gva);
31		kvm_mips_dump_host_tlbs();
32		gpa = KVM_INVALID_ADDR;
33	}
34
35	kvm_debug("%s: gva %#lx, gpa: %#llx\n", __func__, gva, gpa);
36
37	return gpa;
38}
39
40static int kvm_trap_emul_handle_cop_unusable(struct kvm_vcpu *vcpu)
41{
42	struct kvm_run *run = vcpu->run;
43	uint32_t __user *opc = (uint32_t __user *) vcpu->arch.pc;
44	unsigned long cause = vcpu->arch.host_cp0_cause;
45	enum emulation_result er = EMULATE_DONE;
46	int ret = RESUME_GUEST;
47
48	if (((cause & CAUSEF_CE) >> CAUSEB_CE) == 1)
49		er = kvm_mips_emulate_fpu_exc(cause, opc, run, vcpu);
50	else
51		er = kvm_mips_emulate_inst(cause, opc, run, vcpu);
52
53	switch (er) {
54	case EMULATE_DONE:
55		ret = RESUME_GUEST;
56		break;
57
58	case EMULATE_FAIL:
59		run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
60		ret = RESUME_HOST;
61		break;
62
63	case EMULATE_WAIT:
64		run->exit_reason = KVM_EXIT_INTR;
65		ret = RESUME_HOST;
66		break;
67
68	default:
69		BUG();
70	}
71	return ret;
72}
73
74static int kvm_trap_emul_handle_tlb_mod(struct kvm_vcpu *vcpu)
75{
76	struct kvm_run *run = vcpu->run;
77	uint32_t __user *opc = (uint32_t __user *) vcpu->arch.pc;
78	unsigned long badvaddr = vcpu->arch.host_cp0_badvaddr;
79	unsigned long cause = vcpu->arch.host_cp0_cause;
80	enum emulation_result er = EMULATE_DONE;
81	int ret = RESUME_GUEST;
82
83	if (KVM_GUEST_KSEGX(badvaddr) < KVM_GUEST_KSEG0
84	    || KVM_GUEST_KSEGX(badvaddr) == KVM_GUEST_KSEG23) {
85		kvm_debug("USER/KSEG23 ADDR TLB MOD fault: cause %#lx, PC: %p, BadVaddr: %#lx\n",
86			  cause, opc, badvaddr);
87		er = kvm_mips_handle_tlbmod(cause, opc, run, vcpu);
88
89		if (er == EMULATE_DONE)
90			ret = RESUME_GUEST;
91		else {
92			run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
93			ret = RESUME_HOST;
94		}
95	} else if (KVM_GUEST_KSEGX(badvaddr) == KVM_GUEST_KSEG0) {
96		/*
97		 * XXXKYMA: The guest kernel does not expect to get this fault
98		 * when we are not using HIGHMEM. Need to address this in a
99		 * HIGHMEM kernel
100		 */
101		kvm_err("TLB MOD fault not handled, cause %#lx, PC: %p, BadVaddr: %#lx\n",
102			cause, opc, badvaddr);
103		kvm_mips_dump_host_tlbs();
104		kvm_arch_vcpu_dump_regs(vcpu);
105		run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
106		ret = RESUME_HOST;
107	} else {
108		kvm_err("Illegal TLB Mod fault address , cause %#lx, PC: %p, BadVaddr: %#lx\n",
109			cause, opc, badvaddr);
110		kvm_mips_dump_host_tlbs();
111		kvm_arch_vcpu_dump_regs(vcpu);
112		run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
113		ret = RESUME_HOST;
114	}
115	return ret;
116}
117
118static int kvm_trap_emul_handle_tlb_st_miss(struct kvm_vcpu *vcpu)
119{
120	struct kvm_run *run = vcpu->run;
121	uint32_t __user *opc = (uint32_t __user *) vcpu->arch.pc;
122	unsigned long badvaddr = vcpu->arch.host_cp0_badvaddr;
123	unsigned long cause = vcpu->arch.host_cp0_cause;
124	enum emulation_result er = EMULATE_DONE;
125	int ret = RESUME_GUEST;
126
127	if (((badvaddr & PAGE_MASK) == KVM_GUEST_COMMPAGE_ADDR)
128	    && KVM_GUEST_KERNEL_MODE(vcpu)) {
129		if (kvm_mips_handle_commpage_tlb_fault(badvaddr, vcpu) < 0) {
130			run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
131			ret = RESUME_HOST;
132		}
133	} else if (KVM_GUEST_KSEGX(badvaddr) < KVM_GUEST_KSEG0
134		   || KVM_GUEST_KSEGX(badvaddr) == KVM_GUEST_KSEG23) {
135		kvm_debug("USER ADDR TLB LD fault: cause %#lx, PC: %p, BadVaddr: %#lx\n",
136			  cause, opc, badvaddr);
137		er = kvm_mips_handle_tlbmiss(cause, opc, run, vcpu);
138		if (er == EMULATE_DONE)
139			ret = RESUME_GUEST;
140		else {
141			run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
142			ret = RESUME_HOST;
143		}
144	} else if (KVM_GUEST_KSEGX(badvaddr) == KVM_GUEST_KSEG0) {
145		/*
146		 * All KSEG0 faults are handled by KVM, as the guest kernel does
147		 * not expect to ever get them
148		 */
149		if (kvm_mips_handle_kseg0_tlb_fault
150		    (vcpu->arch.host_cp0_badvaddr, vcpu) < 0) {
151			run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
152			ret = RESUME_HOST;
153		}
154	} else {
155		kvm_err("Illegal TLB LD fault address , cause %#lx, PC: %p, BadVaddr: %#lx\n",
156			cause, opc, badvaddr);
157		kvm_mips_dump_host_tlbs();
158		kvm_arch_vcpu_dump_regs(vcpu);
159		run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
160		ret = RESUME_HOST;
161	}
162	return ret;
163}
164
165static int kvm_trap_emul_handle_tlb_ld_miss(struct kvm_vcpu *vcpu)
166{
167	struct kvm_run *run = vcpu->run;
168	uint32_t __user *opc = (uint32_t __user *) vcpu->arch.pc;
169	unsigned long badvaddr = vcpu->arch.host_cp0_badvaddr;
170	unsigned long cause = vcpu->arch.host_cp0_cause;
171	enum emulation_result er = EMULATE_DONE;
172	int ret = RESUME_GUEST;
173
174	if (((badvaddr & PAGE_MASK) == KVM_GUEST_COMMPAGE_ADDR)
175	    && KVM_GUEST_KERNEL_MODE(vcpu)) {
176		if (kvm_mips_handle_commpage_tlb_fault(badvaddr, vcpu) < 0) {
177			run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
178			ret = RESUME_HOST;
179		}
180	} else if (KVM_GUEST_KSEGX(badvaddr) < KVM_GUEST_KSEG0
181		   || KVM_GUEST_KSEGX(badvaddr) == KVM_GUEST_KSEG23) {
182		kvm_debug("USER ADDR TLB ST fault: PC: %#lx, BadVaddr: %#lx\n",
183			  vcpu->arch.pc, badvaddr);
184
185		/*
186		 * User Address (UA) fault, this could happen if
187		 * (1) TLB entry not present/valid in both Guest and shadow host
188		 *     TLBs, in this case we pass on the fault to the guest
189		 *     kernel and let it handle it.
190		 * (2) TLB entry is present in the Guest TLB but not in the
191		 *     shadow, in this case we inject the TLB from the Guest TLB
192		 *     into the shadow host TLB
193		 */
194
195		er = kvm_mips_handle_tlbmiss(cause, opc, run, vcpu);
196		if (er == EMULATE_DONE)
197			ret = RESUME_GUEST;
198		else {
199			run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
200			ret = RESUME_HOST;
201		}
202	} else if (KVM_GUEST_KSEGX(badvaddr) == KVM_GUEST_KSEG0) {
203		if (kvm_mips_handle_kseg0_tlb_fault
204		    (vcpu->arch.host_cp0_badvaddr, vcpu) < 0) {
205			run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
206			ret = RESUME_HOST;
207		}
208	} else {
209		kvm_err("Illegal TLB ST fault address , cause %#lx, PC: %p, BadVaddr: %#lx\n",
210			cause, opc, badvaddr);
211		kvm_mips_dump_host_tlbs();
212		kvm_arch_vcpu_dump_regs(vcpu);
213		run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
214		ret = RESUME_HOST;
215	}
216	return ret;
217}
218
219static int kvm_trap_emul_handle_addr_err_st(struct kvm_vcpu *vcpu)
220{
221	struct kvm_run *run = vcpu->run;
222	uint32_t __user *opc = (uint32_t __user *) vcpu->arch.pc;
223	unsigned long badvaddr = vcpu->arch.host_cp0_badvaddr;
224	unsigned long cause = vcpu->arch.host_cp0_cause;
225	enum emulation_result er = EMULATE_DONE;
226	int ret = RESUME_GUEST;
227
228	if (KVM_GUEST_KERNEL_MODE(vcpu)
229	    && (KSEGX(badvaddr) == CKSEG0 || KSEGX(badvaddr) == CKSEG1)) {
230		kvm_debug("Emulate Store to MMIO space\n");
231		er = kvm_mips_emulate_inst(cause, opc, run, vcpu);
232		if (er == EMULATE_FAIL) {
233			kvm_err("Emulate Store to MMIO space failed\n");
234			run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
235			ret = RESUME_HOST;
236		} else {
237			run->exit_reason = KVM_EXIT_MMIO;
238			ret = RESUME_HOST;
239		}
240	} else {
241		kvm_err("Address Error (STORE): cause %#lx, PC: %p, BadVaddr: %#lx\n",
242			cause, opc, badvaddr);
243		run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
244		ret = RESUME_HOST;
245	}
246	return ret;
247}
248
249static int kvm_trap_emul_handle_addr_err_ld(struct kvm_vcpu *vcpu)
250{
251	struct kvm_run *run = vcpu->run;
252	uint32_t __user *opc = (uint32_t __user *) vcpu->arch.pc;
253	unsigned long badvaddr = vcpu->arch.host_cp0_badvaddr;
254	unsigned long cause = vcpu->arch.host_cp0_cause;
255	enum emulation_result er = EMULATE_DONE;
256	int ret = RESUME_GUEST;
257
258	if (KSEGX(badvaddr) == CKSEG0 || KSEGX(badvaddr) == CKSEG1) {
259		kvm_debug("Emulate Load from MMIO space @ %#lx\n", badvaddr);
260		er = kvm_mips_emulate_inst(cause, opc, run, vcpu);
261		if (er == EMULATE_FAIL) {
262			kvm_err("Emulate Load from MMIO space failed\n");
263			run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
264			ret = RESUME_HOST;
265		} else {
266			run->exit_reason = KVM_EXIT_MMIO;
267			ret = RESUME_HOST;
268		}
269	} else {
270		kvm_err("Address Error (LOAD): cause %#lx, PC: %p, BadVaddr: %#lx\n",
271			cause, opc, badvaddr);
272		run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
273		ret = RESUME_HOST;
274		er = EMULATE_FAIL;
275	}
276	return ret;
277}
278
279static int kvm_trap_emul_handle_syscall(struct kvm_vcpu *vcpu)
280{
281	struct kvm_run *run = vcpu->run;
282	uint32_t __user *opc = (uint32_t __user *) vcpu->arch.pc;
283	unsigned long cause = vcpu->arch.host_cp0_cause;
284	enum emulation_result er = EMULATE_DONE;
285	int ret = RESUME_GUEST;
286
287	er = kvm_mips_emulate_syscall(cause, opc, run, vcpu);
288	if (er == EMULATE_DONE)
289		ret = RESUME_GUEST;
290	else {
291		run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
292		ret = RESUME_HOST;
293	}
294	return ret;
295}
296
297static int kvm_trap_emul_handle_res_inst(struct kvm_vcpu *vcpu)
298{
299	struct kvm_run *run = vcpu->run;
300	uint32_t __user *opc = (uint32_t __user *) vcpu->arch.pc;
301	unsigned long cause = vcpu->arch.host_cp0_cause;
302	enum emulation_result er = EMULATE_DONE;
303	int ret = RESUME_GUEST;
304
305	er = kvm_mips_handle_ri(cause, opc, run, vcpu);
306	if (er == EMULATE_DONE)
307		ret = RESUME_GUEST;
308	else {
309		run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
310		ret = RESUME_HOST;
311	}
312	return ret;
313}
314
315static int kvm_trap_emul_handle_break(struct kvm_vcpu *vcpu)
316{
317	struct kvm_run *run = vcpu->run;
318	uint32_t __user *opc = (uint32_t __user *) vcpu->arch.pc;
319	unsigned long cause = vcpu->arch.host_cp0_cause;
320	enum emulation_result er = EMULATE_DONE;
321	int ret = RESUME_GUEST;
322
323	er = kvm_mips_emulate_bp_exc(cause, opc, run, vcpu);
324	if (er == EMULATE_DONE)
325		ret = RESUME_GUEST;
326	else {
327		run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
328		ret = RESUME_HOST;
329	}
330	return ret;
331}
332
333static int kvm_trap_emul_vm_init(struct kvm *kvm)
334{
335	return 0;
336}
337
338static int kvm_trap_emul_vcpu_init(struct kvm_vcpu *vcpu)
339{
340	return 0;
341}
342
343static int kvm_trap_emul_vcpu_setup(struct kvm_vcpu *vcpu)
344{
345	struct mips_coproc *cop0 = vcpu->arch.cop0;
346	uint32_t config1;
347	int vcpu_id = vcpu->vcpu_id;
348
349	/*
350	 * Arch specific stuff, set up config registers properly so that the
351	 * guest will come up as expected, for now we simulate a MIPS 24kc
352	 */
353	kvm_write_c0_guest_prid(cop0, 0x00019300);
354	kvm_write_c0_guest_config(cop0,
355				  MIPS_CONFIG0 | (0x1 << CP0C0_AR) |
356				  (MMU_TYPE_R4000 << CP0C0_MT));
357
358	/* Read the cache characteristics from the host Config1 Register */
359	config1 = (read_c0_config1() & ~0x7f);
360
361	/* Set up MMU size */
362	config1 &= ~(0x3f << 25);
363	config1 |= ((KVM_MIPS_GUEST_TLB_SIZE - 1) << 25);
364
365	/* We unset some bits that we aren't emulating */
366	config1 &=
367	    ~((1 << CP0C1_C2) | (1 << CP0C1_MD) | (1 << CP0C1_PC) |
368	      (1 << CP0C1_WR) | (1 << CP0C1_CA));
369	kvm_write_c0_guest_config1(cop0, config1);
370
371	kvm_write_c0_guest_config2(cop0, MIPS_CONFIG2);
372	/* MIPS_CONFIG2 | (read_c0_config2() & 0xfff) */
373	kvm_write_c0_guest_config3(cop0, MIPS_CONFIG3 | (0 << CP0C3_VInt) |
374					 (1 << CP0C3_ULRI));
375
376	/* Set Wait IE/IXMT Ignore in Config7, IAR, AR */
377	kvm_write_c0_guest_config7(cop0, (MIPS_CONF7_WII) | (1 << 10));
378
379	/*
380	 * Setup IntCtl defaults, compatibilty mode for timer interrupts (HW5)
381	 */
382	kvm_write_c0_guest_intctl(cop0, 0xFC000000);
383
384	/* Put in vcpu id as CPUNum into Ebase Reg to handle SMP Guests */
385	kvm_write_c0_guest_ebase(cop0, KVM_GUEST_KSEG0 | (vcpu_id & 0xFF));
386
387	return 0;
388}
389
390static int kvm_trap_emul_get_one_reg(struct kvm_vcpu *vcpu,
391				     const struct kvm_one_reg *reg,
392				     s64 *v)
393{
394	switch (reg->id) {
395	case KVM_REG_MIPS_CP0_COUNT:
396		*v = kvm_mips_read_count(vcpu);
397		break;
398	case KVM_REG_MIPS_COUNT_CTL:
399		*v = vcpu->arch.count_ctl;
400		break;
401	case KVM_REG_MIPS_COUNT_RESUME:
402		*v = ktime_to_ns(vcpu->arch.count_resume);
403		break;
404	case KVM_REG_MIPS_COUNT_HZ:
405		*v = vcpu->arch.count_hz;
406		break;
407	default:
408		return -EINVAL;
409	}
410	return 0;
411}
412
413static int kvm_trap_emul_set_one_reg(struct kvm_vcpu *vcpu,
414				     const struct kvm_one_reg *reg,
415				     s64 v)
416{
417	struct mips_coproc *cop0 = vcpu->arch.cop0;
418	int ret = 0;
419
420	switch (reg->id) {
421	case KVM_REG_MIPS_CP0_COUNT:
422		kvm_mips_write_count(vcpu, v);
423		break;
424	case KVM_REG_MIPS_CP0_COMPARE:
425		kvm_mips_write_compare(vcpu, v);
426		break;
427	case KVM_REG_MIPS_CP0_CAUSE:
428		/*
429		 * If the timer is stopped or started (DC bit) it must look
430		 * atomic with changes to the interrupt pending bits (TI, IRQ5).
431		 * A timer interrupt should not happen in between.
432		 */
433		if ((kvm_read_c0_guest_cause(cop0) ^ v) & CAUSEF_DC) {
434			if (v & CAUSEF_DC) {
435				/* disable timer first */
436				kvm_mips_count_disable_cause(vcpu);
437				kvm_change_c0_guest_cause(cop0, ~CAUSEF_DC, v);
438			} else {
439				/* enable timer last */
440				kvm_change_c0_guest_cause(cop0, ~CAUSEF_DC, v);
441				kvm_mips_count_enable_cause(vcpu);
442			}
443		} else {
444			kvm_write_c0_guest_cause(cop0, v);
445		}
446		break;
447	case KVM_REG_MIPS_COUNT_CTL:
448		ret = kvm_mips_set_count_ctl(vcpu, v);
449		break;
450	case KVM_REG_MIPS_COUNT_RESUME:
451		ret = kvm_mips_set_count_resume(vcpu, v);
452		break;
453	case KVM_REG_MIPS_COUNT_HZ:
454		ret = kvm_mips_set_count_hz(vcpu, v);
455		break;
456	default:
457		return -EINVAL;
458	}
459	return ret;
460}
461
462static struct kvm_mips_callbacks kvm_trap_emul_callbacks = {
463	/* exit handlers */
464	.handle_cop_unusable = kvm_trap_emul_handle_cop_unusable,
465	.handle_tlb_mod = kvm_trap_emul_handle_tlb_mod,
466	.handle_tlb_st_miss = kvm_trap_emul_handle_tlb_st_miss,
467	.handle_tlb_ld_miss = kvm_trap_emul_handle_tlb_ld_miss,
468	.handle_addr_err_st = kvm_trap_emul_handle_addr_err_st,
469	.handle_addr_err_ld = kvm_trap_emul_handle_addr_err_ld,
470	.handle_syscall = kvm_trap_emul_handle_syscall,
471	.handle_res_inst = kvm_trap_emul_handle_res_inst,
472	.handle_break = kvm_trap_emul_handle_break,
473
474	.vm_init = kvm_trap_emul_vm_init,
475	.vcpu_init = kvm_trap_emul_vcpu_init,
476	.vcpu_setup = kvm_trap_emul_vcpu_setup,
477	.gva_to_gpa = kvm_trap_emul_gva_to_gpa_cb,
478	.queue_timer_int = kvm_mips_queue_timer_int_cb,
479	.dequeue_timer_int = kvm_mips_dequeue_timer_int_cb,
480	.queue_io_int = kvm_mips_queue_io_int_cb,
481	.dequeue_io_int = kvm_mips_dequeue_io_int_cb,
482	.irq_deliver = kvm_mips_irq_deliver_cb,
483	.irq_clear = kvm_mips_irq_clear_cb,
484	.get_one_reg = kvm_trap_emul_get_one_reg,
485	.set_one_reg = kvm_trap_emul_set_one_reg,
486};
487
488int kvm_mips_emulation_init(struct kvm_mips_callbacks **install_callbacks)
489{
490	*install_callbacks = &kvm_trap_emul_callbacks;
491	return 0;
492}
493