Commit eadfb501 authored by James Hogan's avatar James Hogan Committed by Paolo Bonzini

MIPS: KVM: Save k0 straight into VCPU structure

Currently on a guest exception the guest's k0 register is saved to the
scratch temp register and the guest k1 saved to the exception base
address + 0x3000 using k0 to extract the Exception Base field of the
EBase register and as the base operand to the store. Both are then
copied into the VCPU structure after the other general purpose registers
have been saved there.

This bouncing to exception base + 0x3000 is not actually necessary as
the VCPU pointer can be determined and written through just as easily
with only a single spare register. The VCPU pointer is already needed in
k1 for saving the other GP registers, so lets save the guest k0 register
straight into the VCPU structure through k1, first saving k1 into the
scratch temp register instead of k0.

This could potentially pave the way for having a single exception base
area for use by all guests.

The ehb after saving the k register to the scratch temp register is also
delayed until just before it needs to be read back.
Signed-off-by: default avatarJames 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
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
parent 1f9ca62c
...@@ -347,17 +347,15 @@ void *kvm_mips_build_exception(void *addr, void *handler) ...@@ -347,17 +347,15 @@ void *kvm_mips_build_exception(void *addr, void *handler)
memset(labels, 0, sizeof(labels)); memset(labels, 0, sizeof(labels));
memset(relocs, 0, sizeof(relocs)); memset(relocs, 0, sizeof(relocs));
/* Save guest k0 */ /* Save guest k1 into scratch register */
uasm_i_mtc0(&p, K0, scratch_tmp[0], scratch_tmp[1]); uasm_i_mtc0(&p, K1, scratch_tmp[0], scratch_tmp[1]);
uasm_i_ehb(&p);
/* Get EBASE */ /* Get the VCPU pointer from the VCPU scratch register */
uasm_i_mfc0(&p, K0, C0_EBASE); uasm_i_mfc0(&p, K1, scratch_vcpu[0], scratch_vcpu[1]);
/* Get rid of CPUNum */ uasm_i_addiu(&p, K1, K1, offsetof(struct kvm_vcpu, arch));
uasm_i_srl(&p, K0, K0, 10);
uasm_i_sll(&p, K0, K0, 10); /* Save guest k0 into VCPU structure */
/* Save k1 @ offset 0x3000 */ UASM_i_SW(&p, K0, offsetof(struct kvm_vcpu_arch, gprs[K0]), K1);
UASM_i_SW(&p, K1, 0x3000, K0);
/* Branch to the common handler */ /* Branch to the common handler */
uasm_il_b(&p, &r, label_exit_common); uasm_il_b(&p, &r, label_exit_common);
...@@ -395,12 +393,13 @@ void *kvm_mips_build_exit(void *addr) ...@@ -395,12 +393,13 @@ void *kvm_mips_build_exit(void *addr)
/* /*
* Generic Guest exception handler. We end up here when the guest * Generic Guest exception handler. We end up here when the guest
* does something that causes a trap to kernel mode. * does something that causes a trap to kernel mode.
*
* Both k0/k1 registers will have already been saved (k0 into the vcpu
* structure, and k1 into the scratch_tmp register).
*
* The k1 register will already contain the kvm_vcpu_arch pointer.
*/ */
/* Get the VCPU pointer from the scratch register */
uasm_i_mfc0(&p, K1, scratch_vcpu[0], scratch_vcpu[1]);
uasm_i_addiu(&p, K1, K1, offsetof(struct kvm_vcpu, arch));
/* Start saving Guest context to VCPU */ /* Start saving Guest context to VCPU */
for (i = 0; i < 32; ++i) { for (i = 0; i < 32; ++i) {
/* Guest k0/k1 saved later */ /* Guest k0/k1 saved later */
...@@ -416,15 +415,9 @@ void *kvm_mips_build_exit(void *addr) ...@@ -416,15 +415,9 @@ void *kvm_mips_build_exit(void *addr)
uasm_i_mflo(&p, T0); uasm_i_mflo(&p, T0);
UASM_i_SW(&p, T0, offsetof(struct kvm_vcpu_arch, lo), K1); UASM_i_SW(&p, T0, offsetof(struct kvm_vcpu_arch, lo), K1);
/* Finally save guest k0/k1 to VCPU */ /* Finally save guest k1 to VCPU */
uasm_i_ehb(&p);
uasm_i_mfc0(&p, T0, scratch_tmp[0], scratch_tmp[1]); uasm_i_mfc0(&p, T0, scratch_tmp[0], scratch_tmp[1]);
UASM_i_SW(&p, T0, offsetof(struct kvm_vcpu_arch, gprs[K0]), K1);
/* Get GUEST k1 and save it in VCPU */
uasm_i_addiu(&p, T1, ZERO, ~0x2ff);
uasm_i_mfc0(&p, T0, C0_EBASE);
uasm_i_and(&p, T0, T0, T1);
UASM_i_LW(&p, T0, 0x3000, T0);
UASM_i_SW(&p, T0, offsetof(struct kvm_vcpu_arch, gprs[K1]), K1); UASM_i_SW(&p, T0, offsetof(struct kvm_vcpu_arch, gprs[K1]), K1);
/* Now that context has been saved, we can use other registers */ /* Now that context has been saved, we can use other registers */
......
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