aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Hogan <james.hogan@imgtec.com>2014-03-14 09:06:09 -0400
committerPaolo Bonzini <pbonzini@redhat.com>2014-03-19 12:01:43 -0400
commit26f4f3b57862642296a2e613674e7f00d91c022f (patch)
tree34eff1982a3d9fcfd65a8f9d8a14bd6f87fd3949
parent15505679362270d02c449626385cb74af8905514 (diff)
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: James 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: Paolo Bonzini <pbonzini@redhat.com>
-rw-r--r--arch/mips/include/asm/kvm_host.h2
-rw-r--r--arch/mips/kvm/kvm_mips_emul.c30
2 files changed, 18 insertions, 14 deletions
diff --git a/arch/mips/include/asm/kvm_host.h b/arch/mips/include/asm/kvm_host.h
index 502c8da08574..060aaa6348d7 100644
--- a/arch/mips/include/asm/kvm_host.h
+++ b/arch/mips/include/asm/kvm_host.h
@@ -414,6 +414,8 @@ struct kvm_vcpu_arch {
414#define kvm_write_c0_guest_pagemask(cop0, val) (cop0->reg[MIPS_CP0_TLB_PG_MASK][0] = (val)) 414#define kvm_write_c0_guest_pagemask(cop0, val) (cop0->reg[MIPS_CP0_TLB_PG_MASK][0] = (val))
415#define kvm_read_c0_guest_wired(cop0) (cop0->reg[MIPS_CP0_TLB_WIRED][0]) 415#define kvm_read_c0_guest_wired(cop0) (cop0->reg[MIPS_CP0_TLB_WIRED][0])
416#define kvm_write_c0_guest_wired(cop0, val) (cop0->reg[MIPS_CP0_TLB_WIRED][0] = (val)) 416#define kvm_write_c0_guest_wired(cop0, val) (cop0->reg[MIPS_CP0_TLB_WIRED][0] = (val))
417#define kvm_read_c0_guest_hwrena(cop0) (cop0->reg[MIPS_CP0_HWRENA][0])
418#define kvm_write_c0_guest_hwrena(cop0, val) (cop0->reg[MIPS_CP0_HWRENA][0] = (val))
417#define kvm_read_c0_guest_badvaddr(cop0) (cop0->reg[MIPS_CP0_BAD_VADDR][0]) 419#define kvm_read_c0_guest_badvaddr(cop0) (cop0->reg[MIPS_CP0_BAD_VADDR][0])
418#define kvm_write_c0_guest_badvaddr(cop0, val) (cop0->reg[MIPS_CP0_BAD_VADDR][0] = (val)) 420#define kvm_write_c0_guest_badvaddr(cop0, val) (cop0->reg[MIPS_CP0_BAD_VADDR][0] = (val))
419#define kvm_read_c0_guest_count(cop0) (cop0->reg[MIPS_CP0_COUNT][0]) 421#define kvm_read_c0_guest_count(cop0) (cop0->reg[MIPS_CP0_COUNT][0])
diff --git a/arch/mips/kvm/kvm_mips_emul.c b/arch/mips/kvm/kvm_mips_emul.c
index e75ef8219caf..d562572c2efc 100644
--- a/arch/mips/kvm/kvm_mips_emul.c
+++ b/arch/mips/kvm/kvm_mips_emul.c
@@ -1542,8 +1542,15 @@ kvm_mips_handle_ri(unsigned long cause, uint32_t *opc,
1542 } 1542 }
1543 1543
1544 if ((inst & OPCODE) == SPEC3 && (inst & FUNC) == RDHWR) { 1544 if ((inst & OPCODE) == SPEC3 && (inst & FUNC) == RDHWR) {
1545 int usermode = !KVM_GUEST_KERNEL_MODE(vcpu);
1545 int rd = (inst & RD) >> 11; 1546 int rd = (inst & RD) >> 11;
1546 int rt = (inst & RT) >> 16; 1547 int rt = (inst & RT) >> 16;
1548 /* If usermode, check RDHWR rd is allowed by guest HWREna */
1549 if (usermode && !(kvm_read_c0_guest_hwrena(cop0) & BIT(rd))) {
1550 kvm_debug("RDHWR %#x disallowed by HWREna @ %p\n",
1551 rd, opc);
1552 goto emulate_ri;
1553 }
1547 switch (rd) { 1554 switch (rd) {
1548 case 0: /* CPU number */ 1555 case 0: /* CPU number */
1549 arch->gprs[rt] = 0; 1556 arch->gprs[rt] = 0;
@@ -1567,32 +1574,27 @@ kvm_mips_handle_ri(unsigned long cause, uint32_t *opc,
1567 } 1574 }
1568 break; 1575 break;
1569 case 29: 1576 case 29:
1570#if 1
1571 arch->gprs[rt] = kvm_read_c0_guest_userlocal(cop0); 1577 arch->gprs[rt] = kvm_read_c0_guest_userlocal(cop0);
1572#else
1573 /* UserLocal not implemented */
1574 er = EMULATE_FAIL;
1575#endif
1576 break; 1578 break;
1577 1579
1578 default: 1580 default:
1579 kvm_debug("RDHWR %#x not supported @ %p\n", rd, opc); 1581 kvm_debug("RDHWR %#x not supported @ %p\n", rd, opc);
1580 er = EMULATE_FAIL; 1582 goto emulate_ri;
1581 break;
1582 } 1583 }
1583 } else { 1584 } else {
1584 kvm_debug("Emulate RI not supported @ %p: %#x\n", opc, inst); 1585 kvm_debug("Emulate RI not supported @ %p: %#x\n", opc, inst);
1585 er = EMULATE_FAIL; 1586 goto emulate_ri;
1586 } 1587 }
1587 1588
1589 return EMULATE_DONE;
1590
1591emulate_ri:
1588 /* 1592 /*
1589 * Rollback PC only if emulation was unsuccessful 1593 * Rollback PC (if in branch delay slot then the PC already points to
1594 * branch target), and pass the RI exception to the guest OS.
1590 */ 1595 */
1591 if (er == EMULATE_FAIL) { 1596 vcpu->arch.pc = curr_pc;
1592 vcpu->arch.pc = curr_pc; 1597 return kvm_mips_emulate_ri_exc(cause, opc, run, vcpu);
1593 er = kvm_mips_emulate_ri_exc(cause, opc, run, vcpu);
1594 }
1595 return er;
1596} 1598}
1597 1599
1598enum emulation_result 1600enum emulation_result