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
6 * KVM/MIPS: Deliver/Emulate exceptions to the guest kernel
8 * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved.
9 * Authors: Sanjay Lal <sanjayl@kymasys.com>
12 #include <linux/errno.h>
13 #include <linux/err.h>
14 #include <linux/module.h>
15 #include <linux/vmalloc.h>
17 #include <linux/kvm_host.h>
20 #include "interrupt.h"
22 static gpa_t kvm_trap_emul_gva_to_gpa_cb(gva_t gva)
25 uint32_t kseg = KSEGX(gva);
27 if ((kseg == CKSEG0) || (kseg == CKSEG1))
30 kvm_err("%s: cannot find GPA for GVA: %#lx\n", __func__, gva);
31 kvm_mips_dump_host_tlbs();
32 gpa = KVM_INVALID_ADDR;
35 kvm_debug("%s: gva %#lx, gpa: %#llx\n", __func__, gva, gpa);
40 static int kvm_trap_emul_handle_cop_unusable(struct kvm_vcpu *vcpu)
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;
48 if (((cause & CAUSEF_CE) >> CAUSEB_CE) == 1)
49 er = kvm_mips_emulate_fpu_exc(cause, opc, run, vcpu);
51 er = kvm_mips_emulate_inst(cause, opc, run, vcpu);
59 run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
64 run->exit_reason = KVM_EXIT_INTR;
74 static int kvm_trap_emul_handle_tlb_mod(struct kvm_vcpu *vcpu)
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;
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);
89 if (er == EMULATE_DONE)
92 run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
95 } else if (KVM_GUEST_KSEGX(badvaddr) == KVM_GUEST_KSEG0) {
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
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;
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;
118 static int kvm_trap_emul_handle_tlb_st_miss(struct kvm_vcpu *vcpu)
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;
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;
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)
141 run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
144 } else if (KVM_GUEST_KSEGX(badvaddr) == KVM_GUEST_KSEG0) {
146 * All KSEG0 faults are handled by KVM, as the guest kernel does
147 * not expect to ever get them
149 if (kvm_mips_handle_kseg0_tlb_fault
150 (vcpu->arch.host_cp0_badvaddr, vcpu) < 0) {
151 run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
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;
165 static int kvm_trap_emul_handle_tlb_ld_miss(struct kvm_vcpu *vcpu)
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;
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;
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);
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
195 er = kvm_mips_handle_tlbmiss(cause, opc, run, vcpu);
196 if (er == EMULATE_DONE)
199 run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
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;
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;
219 static int kvm_trap_emul_handle_addr_err_st(struct kvm_vcpu *vcpu)
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;
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;
237 run->exit_reason = KVM_EXIT_MMIO;
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;
249 static int kvm_trap_emul_handle_addr_err_ld(struct kvm_vcpu *vcpu)
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;
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;
266 run->exit_reason = KVM_EXIT_MMIO;
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;
279 static int kvm_trap_emul_handle_syscall(struct kvm_vcpu *vcpu)
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;
287 er = kvm_mips_emulate_syscall(cause, opc, run, vcpu);
288 if (er == EMULATE_DONE)
291 run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
297 static int kvm_trap_emul_handle_res_inst(struct kvm_vcpu *vcpu)
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;
305 er = kvm_mips_handle_ri(cause, opc, run, vcpu);
306 if (er == EMULATE_DONE)
309 run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
315 static int kvm_trap_emul_handle_break(struct kvm_vcpu *vcpu)
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;
323 er = kvm_mips_emulate_bp_exc(cause, opc, run, vcpu);
324 if (er == EMULATE_DONE)
327 run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
333 static int kvm_trap_emul_vm_init(struct kvm *kvm)
338 static int kvm_trap_emul_vcpu_init(struct kvm_vcpu *vcpu)
343 static int kvm_trap_emul_vcpu_setup(struct kvm_vcpu *vcpu)
345 struct mips_coproc *cop0 = vcpu->arch.cop0;
347 int vcpu_id = vcpu->vcpu_id;
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
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));
358 /* Read the cache characteristics from the host Config1 Register */
359 config1 = (read_c0_config1() & ~0x7f);
361 /* Set up MMU size */
362 config1 &= ~(0x3f << 25);
363 config1 |= ((KVM_MIPS_GUEST_TLB_SIZE - 1) << 25);
365 /* We unset some bits that we aren't emulating */
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);
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) |
376 /* Set Wait IE/IXMT Ignore in Config7, IAR, AR */
377 kvm_write_c0_guest_config7(cop0, (MIPS_CONF7_WII) | (1 << 10));
380 * Setup IntCtl defaults, compatibilty mode for timer interrupts (HW5)
382 kvm_write_c0_guest_intctl(cop0, 0xFC000000);
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));
390 static int kvm_trap_emul_get_one_reg(struct kvm_vcpu *vcpu,
391 const struct kvm_one_reg *reg,
395 case KVM_REG_MIPS_CP0_COUNT:
396 *v = kvm_mips_read_count(vcpu);
398 case KVM_REG_MIPS_COUNT_CTL:
399 *v = vcpu->arch.count_ctl;
401 case KVM_REG_MIPS_COUNT_RESUME:
402 *v = ktime_to_ns(vcpu->arch.count_resume);
404 case KVM_REG_MIPS_COUNT_HZ:
405 *v = vcpu->arch.count_hz;
413 static int kvm_trap_emul_set_one_reg(struct kvm_vcpu *vcpu,
414 const struct kvm_one_reg *reg,
417 struct mips_coproc *cop0 = vcpu->arch.cop0;
421 case KVM_REG_MIPS_CP0_COUNT:
422 kvm_mips_write_count(vcpu, v);
424 case KVM_REG_MIPS_CP0_COMPARE:
425 kvm_mips_write_compare(vcpu, v);
427 case KVM_REG_MIPS_CP0_CAUSE:
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.
433 if ((kvm_read_c0_guest_cause(cop0) ^ v) & CAUSEF_DC) {
435 /* disable timer first */
436 kvm_mips_count_disable_cause(vcpu);
437 kvm_change_c0_guest_cause(cop0, ~CAUSEF_DC, v);
439 /* enable timer last */
440 kvm_change_c0_guest_cause(cop0, ~CAUSEF_DC, v);
441 kvm_mips_count_enable_cause(vcpu);
444 kvm_write_c0_guest_cause(cop0, v);
447 case KVM_REG_MIPS_COUNT_CTL:
448 ret = kvm_mips_set_count_ctl(vcpu, v);
450 case KVM_REG_MIPS_COUNT_RESUME:
451 ret = kvm_mips_set_count_resume(vcpu, v);
453 case KVM_REG_MIPS_COUNT_HZ:
454 ret = kvm_mips_set_count_hz(vcpu, v);
462 static struct kvm_mips_callbacks kvm_trap_emul_callbacks = {
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,
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,
488 int kvm_mips_emulation_init(struct kvm_mips_callbacks **install_callbacks)
490 *install_callbacks = &kvm_trap_emul_callbacks;