Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

James Hogan and committed by
Paolo Bonzini
26f4f3b5 15505679

+18 -14
+2
arch/mips/include/asm/kvm_host.h
··· 414 414 #define kvm_write_c0_guest_pagemask(cop0, val) (cop0->reg[MIPS_CP0_TLB_PG_MASK][0] = (val)) 415 415 #define kvm_read_c0_guest_wired(cop0) (cop0->reg[MIPS_CP0_TLB_WIRED][0]) 416 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 419 #define kvm_read_c0_guest_badvaddr(cop0) (cop0->reg[MIPS_CP0_BAD_VADDR][0]) 418 420 #define kvm_write_c0_guest_badvaddr(cop0, val) (cop0->reg[MIPS_CP0_BAD_VADDR][0] = (val)) 419 421 #define kvm_read_c0_guest_count(cop0) (cop0->reg[MIPS_CP0_COUNT][0])
+16 -14
arch/mips/kvm/kvm_mips_emul.c
··· 1542 1542 } 1543 1543 1544 1544 if ((inst & OPCODE) == SPEC3 && (inst & FUNC) == RDHWR) { 1545 + int usermode = !KVM_GUEST_KERNEL_MODE(vcpu); 1545 1546 int rd = (inst & RD) >> 11; 1546 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 1554 switch (rd) { 1548 1555 case 0: /* CPU number */ 1549 1556 arch->gprs[rt] = 0; ··· 1574 1567 } 1575 1568 break; 1576 1569 case 29: 1577 - #if 1 1578 1570 arch->gprs[rt] = kvm_read_c0_guest_userlocal(cop0); 1579 - #else 1580 - /* UserLocal not implemented */ 1581 - er = EMULATE_FAIL; 1582 - #endif 1583 1571 break; 1584 1572 1585 1573 default: 1586 1574 kvm_debug("RDHWR %#x not supported @ %p\n", rd, opc); 1587 - er = EMULATE_FAIL; 1588 - break; 1575 + goto emulate_ri; 1589 1576 } 1590 1577 } else { 1591 1578 kvm_debug("Emulate RI not supported @ %p: %#x\n", opc, inst); 1592 - er = EMULATE_FAIL; 1579 + goto emulate_ri; 1593 1580 } 1594 1581 1582 + return EMULATE_DONE; 1583 + 1584 + emulate_ri: 1595 1585 /* 1596 - * Rollback PC only if emulation was unsuccessful 1586 + * Rollback PC (if in branch delay slot then the PC already points to 1587 + * branch target), and pass the RI exception to the guest OS. 1597 1588 */ 1598 - if (er == EMULATE_FAIL) { 1599 - vcpu->arch.pc = curr_pc; 1600 - er = kvm_mips_emulate_ri_exc(cause, opc, run, vcpu); 1601 - } 1602 - return er; 1589 + vcpu->arch.pc = curr_pc; 1590 + return kvm_mips_emulate_ri_exc(cause, opc, run, vcpu); 1603 1591 } 1604 1592 1605 1593 enum emulation_result