Commit 26f4f3b5 authored by James Hogan's avatar James Hogan Committed by Paolo Bonzini

MIPS: KVM: Consult HWREna before emulating RDHWR

The ability to read hardware registers from userland with the RDHWR
instruction should depend upon the corresponding bit of the HWREna
register being set, otherwise a reserved instruction exception should be
generated.

However KVM's current emulation ignores the guest's HWREna and always
emulates RDHWR instructions even if the guest OS has disallowed them.

Therefore rework the RDHWR emulation code to check for privilege or the
corresponding bit in the guest HWREna bit. Also remove the #if 0 case
for the UserLocal register. I presume it was there for debug purposes
but it seems unnecessary now that the guest can control whether it
causes a guest exception.
Signed-off-by: default avatarJames Hogan <james.hogan@imgtec.com>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: Gleb Natapov <gleb@kernel.org>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Sanjay Lal <sanjayl@kymasys.com>
Cc: linux-mips@linux-mips.org
Cc: kvm@vger.kernel.org
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
parent 15505679
...@@ -414,6 +414,8 @@ struct kvm_vcpu_arch { ...@@ -414,6 +414,8 @@ struct kvm_vcpu_arch {
#define kvm_write_c0_guest_pagemask(cop0, val) (cop0->reg[MIPS_CP0_TLB_PG_MASK][0] = (val)) #define kvm_write_c0_guest_pagemask(cop0, val) (cop0->reg[MIPS_CP0_TLB_PG_MASK][0] = (val))
#define kvm_read_c0_guest_wired(cop0) (cop0->reg[MIPS_CP0_TLB_WIRED][0]) #define kvm_read_c0_guest_wired(cop0) (cop0->reg[MIPS_CP0_TLB_WIRED][0])
#define kvm_write_c0_guest_wired(cop0, val) (cop0->reg[MIPS_CP0_TLB_WIRED][0] = (val)) #define kvm_write_c0_guest_wired(cop0, val) (cop0->reg[MIPS_CP0_TLB_WIRED][0] = (val))
#define kvm_read_c0_guest_hwrena(cop0) (cop0->reg[MIPS_CP0_HWRENA][0])
#define kvm_write_c0_guest_hwrena(cop0, val) (cop0->reg[MIPS_CP0_HWRENA][0] = (val))
#define kvm_read_c0_guest_badvaddr(cop0) (cop0->reg[MIPS_CP0_BAD_VADDR][0]) #define kvm_read_c0_guest_badvaddr(cop0) (cop0->reg[MIPS_CP0_BAD_VADDR][0])
#define kvm_write_c0_guest_badvaddr(cop0, val) (cop0->reg[MIPS_CP0_BAD_VADDR][0] = (val)) #define kvm_write_c0_guest_badvaddr(cop0, val) (cop0->reg[MIPS_CP0_BAD_VADDR][0] = (val))
#define kvm_read_c0_guest_count(cop0) (cop0->reg[MIPS_CP0_COUNT][0]) #define kvm_read_c0_guest_count(cop0) (cop0->reg[MIPS_CP0_COUNT][0])
......
...@@ -1542,8 +1542,15 @@ kvm_mips_handle_ri(unsigned long cause, uint32_t *opc, ...@@ -1542,8 +1542,15 @@ kvm_mips_handle_ri(unsigned long cause, uint32_t *opc,
} }
if ((inst & OPCODE) == SPEC3 && (inst & FUNC) == RDHWR) { if ((inst & OPCODE) == SPEC3 && (inst & FUNC) == RDHWR) {
int usermode = !KVM_GUEST_KERNEL_MODE(vcpu);
int rd = (inst & RD) >> 11; int rd = (inst & RD) >> 11;
int rt = (inst & RT) >> 16; int rt = (inst & RT) >> 16;
/* If usermode, check RDHWR rd is allowed by guest HWREna */
if (usermode && !(kvm_read_c0_guest_hwrena(cop0) & BIT(rd))) {
kvm_debug("RDHWR %#x disallowed by HWREna @ %p\n",
rd, opc);
goto emulate_ri;
}
switch (rd) { switch (rd) {
case 0: /* CPU number */ case 0: /* CPU number */
arch->gprs[rt] = 0; arch->gprs[rt] = 0;
...@@ -1567,32 +1574,27 @@ kvm_mips_handle_ri(unsigned long cause, uint32_t *opc, ...@@ -1567,32 +1574,27 @@ kvm_mips_handle_ri(unsigned long cause, uint32_t *opc,
} }
break; break;
case 29: case 29:
#if 1
arch->gprs[rt] = kvm_read_c0_guest_userlocal(cop0); arch->gprs[rt] = kvm_read_c0_guest_userlocal(cop0);
#else
/* UserLocal not implemented */
er = EMULATE_FAIL;
#endif
break; break;
default: default:
kvm_debug("RDHWR %#x not supported @ %p\n", rd, opc); kvm_debug("RDHWR %#x not supported @ %p\n", rd, opc);
er = EMULATE_FAIL; goto emulate_ri;
break;
} }
} else { } else {
kvm_debug("Emulate RI not supported @ %p: %#x\n", opc, inst); kvm_debug("Emulate RI not supported @ %p: %#x\n", opc, inst);
er = EMULATE_FAIL; goto emulate_ri;
} }
return EMULATE_DONE;
emulate_ri:
/* /*
* Rollback PC only if emulation was unsuccessful * Rollback PC (if in branch delay slot then the PC already points to
* branch target), and pass the RI exception to the guest OS.
*/ */
if (er == EMULATE_FAIL) {
vcpu->arch.pc = curr_pc; vcpu->arch.pc = curr_pc;
er = kvm_mips_emulate_ri_exc(cause, opc, run, vcpu); return kvm_mips_emulate_ri_exc(cause, opc, run, vcpu);
}
return er;
} }
enum emulation_result enum emulation_result
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment