summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/mips/include/asm/kvm_host.h2
-rw-r--r--arch/mips/kvm/entry.c23
-rw-r--r--arch/mips/kvm/mips.c12
3 files changed, 25 insertions, 12 deletions
diff --git a/arch/mips/include/asm/kvm_host.h b/arch/mips/include/asm/kvm_host.h
index a80c320..b327855 100644
--- a/arch/mips/include/asm/kvm_host.h
+++ b/arch/mips/include/asm/kvm_host.h
@@ -538,7 +538,7 @@ extern int kvm_mips_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu);
/* Building of entry/exception code */
int kvm_mips_entry_setup(void);
void *kvm_mips_build_vcpu_run(void *addr);
-void *kvm_mips_build_exception(void *addr);
+void *kvm_mips_build_exception(void *addr, void *handler);
void *kvm_mips_build_exit(void *addr);
/* FPU/MSA context management */
diff --git a/arch/mips/kvm/entry.c b/arch/mips/kvm/entry.c
index b6e7fd9..fb2cbf6 100644
--- a/arch/mips/kvm/entry.c
+++ b/arch/mips/kvm/entry.c
@@ -69,12 +69,14 @@ enum label_id {
label_msa_1,
label_return_to_host,
label_kernel_asid,
+ label_exit_common,
};
UASM_L_LA(_fpu_1)
UASM_L_LA(_msa_1)
UASM_L_LA(_return_to_host)
UASM_L_LA(_kernel_asid)
+UASM_L_LA(_exit_common)
static void *kvm_mips_build_enter_guest(void *addr);
static void *kvm_mips_build_ret_from_exit(void *addr);
@@ -327,15 +329,23 @@ static void *kvm_mips_build_enter_guest(void *addr)
/**
* kvm_mips_build_exception() - Assemble first level guest exception handler.
* @addr: Address to start writing code.
+ * @handler: Address of common handler (within range of @addr).
*
* Assemble exception vector code for guest execution. The generated vector will
- * jump to the common exception handler generated by kvm_mips_build_exit().
+ * branch to the common exception handler generated by kvm_mips_build_exit().
*
* Returns: Next address after end of written function.
*/
-void *kvm_mips_build_exception(void *addr)
+void *kvm_mips_build_exception(void *addr, void *handler)
{
u32 *p = addr;
+ struct uasm_label labels[2];
+ struct uasm_reloc relocs[2];
+ struct uasm_label *l = labels;
+ struct uasm_reloc *r = relocs;
+
+ memset(labels, 0, sizeof(labels));
+ memset(relocs, 0, sizeof(relocs));
/* Save guest k0 */
uasm_i_mtc0(&p, K0, scratch_tmp[0], scratch_tmp[1]);
@@ -349,12 +359,13 @@ void *kvm_mips_build_exception(void *addr)
/* Save k1 @ offset 0x3000 */
UASM_i_SW(&p, K1, 0x3000, K0);
- /* Exception handler is installed @ offset 0x2000 */
- uasm_i_addiu(&p, K0, K0, 0x2000);
- /* Jump to the function */
- uasm_i_jr(&p, K0);
+ /* Branch to the common handler */
+ uasm_il_b(&p, &r, label_exit_common);
uasm_i_nop(&p);
+ uasm_l_exit_common(&l, handler);
+ uasm_resolve_relocs(relocs, labels);
+
return p;
}
diff --git a/arch/mips/kvm/mips.c b/arch/mips/kvm/mips.c
index 26cc0b9..7c76768 100644
--- a/arch/mips/kvm/mips.c
+++ b/arch/mips/kvm/mips.c
@@ -265,7 +265,7 @@ static inline void dump_handler(const char *symbol, void *start, void *end)
struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id)
{
int err, size;
- void *gebase, *p;
+ void *gebase, *p, *handler;
int i;
struct kvm_vcpu *vcpu = kzalloc(sizeof(struct kvm_vcpu), GFP_KERNEL);
@@ -304,22 +304,24 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id)
vcpu->arch.guest_ebase = gebase;
/* Build guest exception vectors dynamically in unmapped memory */
+ handler = gebase + 0x2000;
/* TLB Refill, EXL = 0 */
- kvm_mips_build_exception(gebase);
+ kvm_mips_build_exception(gebase, handler);
/* General Exception Entry point */
- kvm_mips_build_exception(gebase + 0x180);
+ kvm_mips_build_exception(gebase + 0x180, handler);
/* For vectored interrupts poke the exception code @ all offsets 0-7 */
for (i = 0; i < 8; i++) {
kvm_debug("L1 Vectored handler @ %p\n",
gebase + 0x200 + (i * VECTORSPACING));
- kvm_mips_build_exception(gebase + 0x200 + i * VECTORSPACING);
+ kvm_mips_build_exception(gebase + 0x200 + i * VECTORSPACING,
+ handler);
}
/* General exit handler */
- p = gebase + 0x2000;
+ p = handler;
p = kvm_mips_build_exit(p);
/* Guest entry routine */