KVM: MIPS: Use CP0_BadInstr[P] for emulation
When exiting from the guest, store the values of the CP0_BadInstr and CP0_BadInstrP registers if they exist, which contain the encodings of the instructions which caused the last synchronous exception. When the instruction is needed for emulation, kvm_get_badinstr() and kvm_get_badinstrp() are used instead of calling kvm_get_inst() directly, to decide whether to read the saved CP0_BadInstr/CP0_BadInstrP registers (if they exist), or read the instruction from memory (if not). The use of these registers should be more robust than using kvm_get_inst(), as it actually gives the instruction encoding seen by the hardware rather than relying on user accessors after the fact, which can be fooled by incoherent icache or a racing code modification. It will also work with VZ, where the guest virtual memory isn't directly accessible by the host with user accessors. Signed-off-by: James Hogan <james.hogan@imgtec.com> Cc: Paolo Bonzini <pbonzini@redhat.com> Cc: "Radim Krčmář" <rkrcmar@redhat.com> Cc: Ralf Baechle <ralf@linux-mips.org> Cc: linux-mips@linux-mips.org Cc: kvm@vger.kernel.org
This commit is contained in:
@@ -53,6 +53,8 @@
|
||||
/* Some CP0 registers */
|
||||
#define C0_HWRENA 7, 0
|
||||
#define C0_BADVADDR 8, 0
|
||||
#define C0_BADINSTR 8, 1
|
||||
#define C0_BADINSTRP 8, 2
|
||||
#define C0_ENTRYHI 10, 0
|
||||
#define C0_STATUS 12, 0
|
||||
#define C0_CAUSE 13, 0
|
||||
@@ -579,6 +581,18 @@ void *kvm_mips_build_exit(void *addr)
|
||||
uasm_i_mfc0(&p, K0, C0_CAUSE);
|
||||
uasm_i_sw(&p, K0, offsetof(struct kvm_vcpu_arch, host_cp0_cause), K1);
|
||||
|
||||
if (cpu_has_badinstr) {
|
||||
uasm_i_mfc0(&p, K0, C0_BADINSTR);
|
||||
uasm_i_sw(&p, K0, offsetof(struct kvm_vcpu_arch,
|
||||
host_cp0_badinstr), K1);
|
||||
}
|
||||
|
||||
if (cpu_has_badinstrp) {
|
||||
uasm_i_mfc0(&p, K0, C0_BADINSTRP);
|
||||
uasm_i_sw(&p, K0, offsetof(struct kvm_vcpu_arch,
|
||||
host_cp0_badinstrp), K1);
|
||||
}
|
||||
|
||||
/* Now restore the host state just enough to run the handlers */
|
||||
|
||||
/* Switch EBASE to the one used by Linux */
|
||||
|
Reference in New Issue
Block a user