^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * This file is subject to the terms and conditions of the GNU General Public
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * License. See the file "COPYING" in the main directory of this archive
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * for more details.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * KVM/MIPS: Binary Patching for privileged instructions, reduces traps.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Authors: Sanjay Lal <sanjayl@kymasys.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/highmem.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/kvm_host.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/vmalloc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/fs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/memblock.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <asm/cacheflush.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include "commpage.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) * kvm_mips_trans_replace() - Replace trapping instruction in guest memory.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) * @vcpu: Virtual CPU.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) * @opc: PC of instruction to replace.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) * @replace: Instruction to write
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) static int kvm_mips_trans_replace(struct kvm_vcpu *vcpu, u32 *opc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) union mips_instruction replace)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) unsigned long vaddr = (unsigned long)opc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) retry:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) /* The GVA page table is still active so use the Linux TLB handlers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) kvm_trap_emul_gva_lockless_begin(vcpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) err = put_user(replace.word, opc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) kvm_trap_emul_gva_lockless_end(vcpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) if (unlikely(err)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) * We write protect clean pages in GVA page table so normal
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) * Linux TLB mod handler doesn't silently dirty the page.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) * Its also possible we raced with a GVA invalidation.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) * Try to force the page to become dirty.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) err = kvm_trap_emul_gva_fault(vcpu, vaddr, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) if (unlikely(err)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) kvm_info("%s: Address unwriteable: %p\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) __func__, opc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) * Try again. This will likely trigger a TLB refill, which will
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) * fetch the new dirty entry from the GVA page table, which
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) * should then succeed.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) goto retry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) __local_flush_icache_user_range(vaddr, vaddr + 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) int kvm_mips_trans_cache_index(union mips_instruction inst, u32 *opc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) struct kvm_vcpu *vcpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) union mips_instruction nop_inst = { 0 };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) /* Replace the CACHE instruction, with a NOP */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) return kvm_mips_trans_replace(vcpu, opc, nop_inst);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) * Address based CACHE instructions are transformed into synci(s). A little
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) * heavy for just D-cache invalidates, but avoids an expensive trap
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) int kvm_mips_trans_cache_va(union mips_instruction inst, u32 *opc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) struct kvm_vcpu *vcpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) union mips_instruction synci_inst = { 0 };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) synci_inst.i_format.opcode = bcond_op;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) synci_inst.i_format.rs = inst.i_format.rs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) synci_inst.i_format.rt = synci_op;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) if (cpu_has_mips_r6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) synci_inst.i_format.simmediate = inst.spec3_format.simmediate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) synci_inst.i_format.simmediate = inst.i_format.simmediate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) return kvm_mips_trans_replace(vcpu, opc, synci_inst);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) int kvm_mips_trans_mfc0(union mips_instruction inst, u32 *opc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) struct kvm_vcpu *vcpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) union mips_instruction mfc0_inst = { 0 };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) u32 rd, sel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) rd = inst.c0r_format.rd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) sel = inst.c0r_format.sel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) if (rd == MIPS_CP0_ERRCTL && sel == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) mfc0_inst.r_format.opcode = spec_op;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) mfc0_inst.r_format.rd = inst.c0r_format.rt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) mfc0_inst.r_format.func = add_op;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) mfc0_inst.i_format.opcode = lw_op;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) mfc0_inst.i_format.rt = inst.c0r_format.rt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) mfc0_inst.i_format.simmediate = KVM_GUEST_COMMPAGE_ADDR |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) offsetof(struct kvm_mips_commpage, cop0.reg[rd][sel]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) #ifdef CONFIG_CPU_BIG_ENDIAN
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) if (sizeof(vcpu->arch.cop0->reg[0][0]) == 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) mfc0_inst.i_format.simmediate |= 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) return kvm_mips_trans_replace(vcpu, opc, mfc0_inst);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) int kvm_mips_trans_mtc0(union mips_instruction inst, u32 *opc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) struct kvm_vcpu *vcpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) union mips_instruction mtc0_inst = { 0 };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) u32 rd, sel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) rd = inst.c0r_format.rd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) sel = inst.c0r_format.sel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) mtc0_inst.i_format.opcode = sw_op;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) mtc0_inst.i_format.rt = inst.c0r_format.rt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) mtc0_inst.i_format.simmediate = KVM_GUEST_COMMPAGE_ADDR |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) offsetof(struct kvm_mips_commpage, cop0.reg[rd][sel]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) #ifdef CONFIG_CPU_BIG_ENDIAN
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) if (sizeof(vcpu->arch.cop0->reg[0][0]) == 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) mtc0_inst.i_format.simmediate |= 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) return kvm_mips_trans_replace(vcpu, opc, mtc0_inst);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) }