Re: [PATCH 06/14] MIPS; KVM: Convert exception entry to uasm

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Paolo,

On Thu, Jun 23, 2016 at 05:34:39PM +0100, James Hogan wrote:
> Convert the whole of locore.S (assembly to enter guest and handle
> exception entry) to be generated dynamically with uasm. This is done
> with minimal changes to the resulting code.

Before I forget, please feel free to s/;/:/ in the subject line if/when
you apply (but I know I need some acks yet).

Thanks
James

> 
> The main changes are:
> - Some constants are generated by uasm using LUI+ADDIU instead of
>   LUI+ORI.
> - Loading of lo and hi are swapped around in vcpu_run but not when
>   resuming the guest after an exit. Both bits of logic are now generated
>   by the same code.
> - Register MOVEs in uasm use different ADDU operand ordering to GNU as,
>   putting zero register into rs instead of rt.
> - The JALR.HB to call the C exit handler is switched to JALR, since the
>   hazard barrier would appear to be unnecessary.
> 
> This will allow further optimisation in the future to dynamically handle
> the capabilities of the CPU.
> 
> Signed-off-by: James Hogan <james.hogan@xxxxxxxxxx>
> Cc: Paolo Bonzini <pbonzini@xxxxxxxxxx>
> Cc: Radim Krčmář <rkrcmar@xxxxxxxxxx>
> Cc: Ralf Baechle <ralf@xxxxxxxxxxxxxx>
> Cc: linux-mips@xxxxxxxxxxxxxx
> Cc: kvm@xxxxxxxxxxxxxxx
> ---
>  arch/mips/include/asm/kvm_host.h    |   8 +-
>  arch/mips/kvm/Kconfig               |   1 +
>  arch/mips/kvm/Makefile              |   2 +-
>  arch/mips/kvm/{locore.S => entry.c} | 884 ++++++++++++++++++------------------
>  arch/mips/kvm/interrupt.h           |   4 -
>  arch/mips/kvm/mips.c                |  37 +-
>  6 files changed, 472 insertions(+), 464 deletions(-)
>  rename arch/mips/kvm/{locore.S => entry.c} (20%)
> 
> diff --git a/arch/mips/include/asm/kvm_host.h b/arch/mips/include/asm/kvm_host.h
> index b0773c6d622f..2e76e899079c 100644
> --- a/arch/mips/include/asm/kvm_host.h
> +++ b/arch/mips/include/asm/kvm_host.h
> @@ -533,8 +533,12 @@ int kvm_mips_emulation_init(struct kvm_mips_callbacks **install_callbacks);
>  /* Debug: dump vcpu state */
>  int kvm_arch_vcpu_dump_regs(struct kvm_vcpu *vcpu);
>  
> -/* Trampoline ASM routine to start running in "Guest" context */
> -extern int __kvm_mips_vcpu_run(struct kvm_run *run, struct kvm_vcpu *vcpu);
> +extern int kvm_mips_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu);
> +
> +/* Building of entry/exception code */
> +void *kvm_mips_build_vcpu_run(void *addr);
> +void *kvm_mips_build_exception(void *addr);
> +void *kvm_mips_build_exit(void *addr);
>  
>  /* FPU/MSA context management */
>  void __kvm_save_fpu(struct kvm_vcpu_arch *vcpu);
> diff --git a/arch/mips/kvm/Kconfig b/arch/mips/kvm/Kconfig
> index 2ae12825529f..7c56d6b124d1 100644
> --- a/arch/mips/kvm/Kconfig
> +++ b/arch/mips/kvm/Kconfig
> @@ -17,6 +17,7 @@ if VIRTUALIZATION
>  config KVM
>  	tristate "Kernel-based Virtual Machine (KVM) support"
>  	depends on HAVE_KVM
> +	select EXPORT_UASM
>  	select PREEMPT_NOTIFIERS
>  	select ANON_INODES
>  	select KVM_MMIO
> diff --git a/arch/mips/kvm/Makefile b/arch/mips/kvm/Makefile
> index 0aabe40fcac9..847429de780d 100644
> --- a/arch/mips/kvm/Makefile
> +++ b/arch/mips/kvm/Makefile
> @@ -7,7 +7,7 @@ EXTRA_CFLAGS += -Ivirt/kvm -Iarch/mips/kvm
>  
>  common-objs-$(CONFIG_CPU_HAS_MSA) += msa.o
>  
> -kvm-objs := $(common-objs-y) mips.o emulate.o locore.o \
> +kvm-objs := $(common-objs-y) mips.o emulate.o entry.o \
>  	    interrupt.o stats.o commpage.o \
>  	    dyntrans.o trap_emul.o fpu.o
>  kvm-objs += mmu.o
> diff --git a/arch/mips/kvm/locore.S b/arch/mips/kvm/entry.c
> similarity index 20%
> rename from arch/mips/kvm/locore.S
> rename to arch/mips/kvm/entry.c
> index 698286c0f732..9a18b4939b35 100644
> --- a/arch/mips/kvm/locore.S
> +++ b/arch/mips/kvm/entry.c
> @@ -3,373 +3,445 @@
>   * License.  See the file "COPYING" in the main directory of this archive
>   * for more details.
>   *
> - * Main entry point for the guest, exception handling.
> + * Generation of main entry point for the guest, exception handling.
>   *
> - * Copyright (C) 2012  MIPS Technologies, Inc.  All rights reserved.
> + * Copyright (C) 2012  MIPS Technologies, Inc.
>   * Authors: Sanjay Lal <sanjayl@xxxxxxxxxxx>
> + *
> + * Copyright (C) 2016 Imagination Technologies Ltd.
>   */
>  
> -#include <asm/asm.h>
> -#include <asm/asmmacro.h>
> -#include <asm/regdef.h>
> -#include <asm/mipsregs.h>
> -#include <asm/stackframe.h>
> -#include <asm/asm-offsets.h>
> -
> -#define _C_LABEL(x)     x
> -#define MIPSX(name)     mips32_ ## name
> +#include <linux/kvm_host.h>
> +#include <asm/msa.h>
> +#include <asm/setup.h>
> +#include <asm/uasm.h>
> +
> +/* Register names */
> +#define ZERO		0
> +#define AT		1
> +#define V0		2
> +#define V1		3
> +#define A0		4
> +#define A1		5
> +
> +#if _MIPS_SIM == _MIPS_SIM_ABI32
> +#define T0		8
> +#define T1		9
> +#define T2		10
> +#define T3		11
> +#endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */
> +
> +#if _MIPS_SIM == _MIPS_SIM_ABI64 || _MIPS_SIM == _MIPS_SIM_NABI32
> +#define T0		12
> +#define T1		13
> +#define T2		14
> +#define T3		15
> +#endif /* _MIPS_SIM == _MIPS_SIM_ABI64 || _MIPS_SIM == _MIPS_SIM_NABI32 */
> +
> +#define S0		16
> +#define S1		17
> +#define T9		25
> +#define K0		26
> +#define K1		27
> +#define GP		28
> +#define SP		29
> +#define RA		31
> +
> +/* Some CP0 registers */
> +#define C0_HWRENA	7, 0
> +#define C0_BADVADDR	8, 0
> +#define C0_ENTRYHI	10, 0
> +#define C0_STATUS	12, 0
> +#define C0_CAUSE	13, 0
> +#define C0_EPC		14, 0
> +#define C0_EBASE	15, 1
> +#define C0_CONFIG3	16, 3
> +#define C0_CONFIG5	16, 5
> +#define C0_DDATA_LO	28, 3
> +#define C0_ERROREPC	30, 0
> +
>  #define CALLFRAME_SIZ   32
>  
> -/*
> - * VECTOR
> - *  exception vector entrypoint
> - */
> -#define VECTOR(x, regmask)      \
> -    .ent    _C_LABEL(x),0;      \
> -    EXPORT(x);
> -
> -#define VECTOR_END(x)      \
> -    EXPORT(x);
> -
> -/* Overload, Danger Will Robinson!! */
> -#define PT_HOST_USERLOCAL   PT_EPC
> +enum label_id {
> +	label_fpu_1 = 1,
> +	label_msa_1,
> +	label_return_to_host,
> +	label_kernel_asid,
> +};
>  
> -#define CP0_DDATA_LO        $28,3
> +UASM_L_LA(_fpu_1)
> +UASM_L_LA(_msa_1)
> +UASM_L_LA(_return_to_host)
> +UASM_L_LA(_kernel_asid)
>  
> -/* Resume Flags */
> -#define RESUME_FLAG_HOST        (1<<1)  /* Resume host? */
> +static void *kvm_mips_build_enter_guest(void *addr);
> +static void *kvm_mips_build_ret_from_exit(void *addr);
> +static void *kvm_mips_build_ret_to_guest(void *addr);
> +static void *kvm_mips_build_ret_to_host(void *addr);
>  
> -#define RESUME_GUEST            0
> -#define RESUME_HOST             RESUME_FLAG_HOST
> -
> -/*
> - * __kvm_mips_vcpu_run: entry point to the guest
> - * a0: run
> - * a1: vcpu
> +/**
> + * kvm_mips_build_vcpu_run() - Assemble function to start running a guest VCPU.
> + * @addr:	Address to start writing code.
> + *
> + * Assemble the start of the vcpu_run function to run a guest VCPU. The function
> + * conforms to the following prototype:
> + *
> + * int vcpu_run(struct kvm_run *run, struct kvm_vcpu *vcpu);
> + *
> + * The exit from the guest and return to the caller is handled by the code
> + * generated by kvm_mips_build_ret_to_host().
> + *
> + * Returns:	Next address after end of written function.
>   */
> -	.set	noreorder
> +void *kvm_mips_build_vcpu_run(void *addr)
> +{
> +	u32 *p = addr;
> +	unsigned int i;
> +
> +	/*
> +	 * A0: run
> +	 * A1: vcpu
> +	 */
>  
> -FEXPORT(__kvm_mips_vcpu_run)
>  	/* k0/k1 not being used in host kernel context */
> -	INT_ADDIU k1, sp, -PT_SIZE
> -	LONG_S	$16, PT_R16(k1)
> -	LONG_S	$17, PT_R17(k1)
> -	LONG_S	$18, PT_R18(k1)
> -	LONG_S	$19, PT_R19(k1)
> -	LONG_S	$20, PT_R20(k1)
> -	LONG_S	$21, PT_R21(k1)
> -	LONG_S	$22, PT_R22(k1)
> -	LONG_S	$23, PT_R23(k1)
> -
> -	LONG_S	$28, PT_R28(k1)
> -	LONG_S	$29, PT_R29(k1)
> -	LONG_S	$30, PT_R30(k1)
> -	LONG_S	$31, PT_R31(k1)
> +	uasm_i_addiu(&p, K1, SP, -(int)sizeof(struct pt_regs));
> +	for (i = 16; i < 32; ++i) {
> +		if (i == 24)
> +			i = 28;
> +		UASM_i_SW(&p, i, offsetof(struct pt_regs, regs[i]), K1);
> +	}
>  
>  	/* Save hi/lo */
> -	mflo	v0
> -	LONG_S	v0, PT_LO(k1)
> -	mfhi	v1
> -	LONG_S	v1, PT_HI(k1)
> +	uasm_i_mflo(&p, V0);
> +	UASM_i_SW(&p, V0, offsetof(struct pt_regs, lo), K1);
> +	uasm_i_mfhi(&p, V1);
> +	UASM_i_SW(&p, V1, offsetof(struct pt_regs, hi), K1);
>  
>  	/* Save host status */
> -	mfc0	v0, CP0_STATUS
> -	LONG_S	v0, PT_STATUS(k1)
> +	uasm_i_mfc0(&p, V0, C0_STATUS);
> +	UASM_i_SW(&p, V0, offsetof(struct pt_regs, cp0_status), K1);
>  
>  	/* Save DDATA_LO, will be used to store pointer to vcpu */
> -	mfc0	v1, CP0_DDATA_LO
> -	LONG_S	v1, PT_HOST_USERLOCAL(k1)
> +	uasm_i_mfc0(&p, V1, C0_DDATA_LO);
> +	UASM_i_SW(&p, V1, offsetof(struct pt_regs, cp0_epc), K1);
>  
>  	/* DDATA_LO has pointer to vcpu */
> -	mtc0	a1, CP0_DDATA_LO
> +	uasm_i_mtc0(&p, A1, C0_DDATA_LO);
>  
>  	/* Offset into vcpu->arch */
> -	INT_ADDIU k1, a1, VCPU_HOST_ARCH
> +	uasm_i_addiu(&p, K1, A1, offsetof(struct kvm_vcpu, arch));
>  
>  	/*
>  	 * Save the host stack to VCPU, used for exception processing
>  	 * when we exit from the Guest
>  	 */
> -	LONG_S	sp, VCPU_HOST_STACK(k1)
> +	UASM_i_SW(&p, SP, offsetof(struct kvm_vcpu_arch, host_stack), K1);
>  
>  	/* Save the kernel gp as well */
> -	LONG_S	gp, VCPU_HOST_GP(k1)
> +	UASM_i_SW(&p, GP, offsetof(struct kvm_vcpu_arch, host_gp), K1);
>  
>  	/*
>  	 * Setup status register for running the guest in UM, interrupts
>  	 * are disabled
>  	 */
> -	li	k0, (ST0_EXL | KSU_USER | ST0_BEV)
> -	mtc0	k0, CP0_STATUS
> -	ehb
> +	UASM_i_LA(&p, K0, ST0_EXL | KSU_USER | ST0_BEV);
> +	uasm_i_mtc0(&p, K0, C0_STATUS);
> +	uasm_i_ehb(&p);
>  
>  	/* load up the new EBASE */
> -	LONG_L	k0, VCPU_GUEST_EBASE(k1)
> -	mtc0	k0, CP0_EBASE
> +	UASM_i_LW(&p, K0, offsetof(struct kvm_vcpu_arch, guest_ebase), K1);
> +	uasm_i_mtc0(&p, K0, C0_EBASE);
>  
>  	/*
>  	 * Now that the new EBASE has been loaded, unset BEV, set
>  	 * interrupt mask as it was but make sure that timer interrupts
>  	 * are enabled
>  	 */
> -	li	k0, (ST0_EXL | KSU_USER | ST0_IE)
> -	andi	v0, v0, ST0_IM
> -	or	k0, k0, v0
> -	mtc0	k0, CP0_STATUS
> -	ehb
> +	uasm_i_addiu(&p, K0, ZERO, ST0_EXL | KSU_USER | ST0_IE);
> +	uasm_i_andi(&p, V0, V0, ST0_IM);
> +	uasm_i_or(&p, K0, K0, V0);
> +	uasm_i_mtc0(&p, K0, C0_STATUS);
> +	uasm_i_ehb(&p);
> +
> +	p = kvm_mips_build_enter_guest(p);
> +
> +	return p;
> +}
> +
> +/**
> + * kvm_mips_build_enter_guest() - Assemble code to resume guest execution.
> + * @addr:	Address to start writing code.
> + *
> + * Assemble the code to resume guest execution. This code is common between the
> + * initial entry into the guest from the host, and returning from the exit
> + * handler back to the guest.
> + *
> + * Returns:	Next address after end of written function.
> + */
> +static void *kvm_mips_build_enter_guest(void *addr)
> +{
> +	u32 *p = addr;
> +	unsigned int i;
> +	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));
>  
>  	/* Set Guest EPC */
> -	LONG_L	t0, VCPU_PC(k1)
> -	mtc0	t0, CP0_EPC
> +	UASM_i_LW(&p, T0, offsetof(struct kvm_vcpu_arch, pc), K1);
> +	uasm_i_mtc0(&p, T0, C0_EPC);
>  
> -FEXPORT(__kvm_mips_load_asid)
>  	/* Set the ASID for the Guest Kernel */
> -	PTR_L	t0, VCPU_COP0(k1)
> -	LONG_L	t0, COP0_STATUS(t0)
> -	andi	t0, KSU_USER | ST0_ERL | ST0_EXL
> -	xori	t0, KSU_USER
> -	bnez	t0, 1f		/* If kernel */
> -	 INT_ADDIU t1, k1, VCPU_GUEST_KERNEL_ASID  /* (BD)  */
> -	INT_ADDIU t1, k1, VCPU_GUEST_USER_ASID    /* else user */
> -1:
> -	/* t1: contains the base of the ASID array, need to get the cpu id */
> -	LONG_L	t2, TI_CPU($28)             /* smp_processor_id */
> -	INT_SLL	t2, t2, 2                   /* x4 */
> -	REG_ADDU t3, t1, t2
> -	LONG_L	k0, (t3)
> +	UASM_i_LW(&p, T0, offsetof(struct kvm_vcpu_arch, cop0), K1);
> +	UASM_i_LW(&p, T0, offsetof(struct mips_coproc, reg[MIPS_CP0_STATUS][0]),
> +		  T0);
> +	uasm_i_andi(&p, T0, T0, KSU_USER | ST0_ERL | ST0_EXL);
> +	uasm_i_xori(&p, T0, T0, KSU_USER);
> +	uasm_il_bnez(&p, &r, T0, label_kernel_asid);
> +	 uasm_i_addiu(&p, T1, K1,
> +		      offsetof(struct kvm_vcpu_arch, guest_kernel_asid));
> +	/* else user */
> +	uasm_i_addiu(&p, T1, K1,
> +		     offsetof(struct kvm_vcpu_arch, guest_user_asid));
> +	uasm_l_kernel_asid(&l, p);
> +
> +	/* t1: contains the base of the ASID array, need to get the cpu id  */
> +	/* smp_processor_id */
> +	UASM_i_LW(&p, T2, offsetof(struct thread_info, cpu), GP);
> +	/* x4 */
> +	uasm_i_sll(&p, T2, T2, 2);
> +	UASM_i_ADDU(&p, T3, T1, T2);
> +	UASM_i_LW(&p, K0, 0, T3);
>  #ifdef CONFIG_MIPS_ASID_BITS_VARIABLE
> -	li	t3, CPUINFO_SIZE/4
> -	mul	t2, t2, t3		/* x sizeof(struct cpuinfo_mips)/4 */
> -	LONG_L	t2, (cpu_data + CPUINFO_ASID_MASK)(t2)
> -	and	k0, k0, t2
> +	/* x sizeof(struct cpuinfo_mips)/4 */
> +	uasm_i_addiu(&p, T3, ZERO, sizeof(struct cpuinfo_mips)/4);
> +	uasm_i_mul(&p, T2, T2, T3);
> +
> +	UASM_i_LA_mostly(&p, AT, (long)&cpu_data[0].asid_mask);
> +	UASM_i_ADDU(&p, AT, AT, T2);
> +	UASM_i_LW(&p, T2, uasm_rel_lo((long)&cpu_data[0].asid_mask), AT);
> +	uasm_i_and(&p, K0, K0, T2);
>  #else
> -	andi	k0, k0, MIPS_ENTRYHI_ASID
> +	uasm_i_andi(&p, K0, K0, MIPS_ENTRYHI_ASID);
>  #endif
> -	mtc0	k0, CP0_ENTRYHI
> -	ehb
> +	uasm_i_mtc0(&p, K0, C0_ENTRYHI);
> +	uasm_i_ehb(&p);
>  
>  	/* Disable RDHWR access */
> -	mtc0	zero, CP0_HWRENA
> -
> -	.set	noat
> -	/* Now load up the Guest Context from VCPU */
> -	LONG_L	$1, VCPU_R1(k1)
> -	LONG_L	$2, VCPU_R2(k1)
> -	LONG_L	$3, VCPU_R3(k1)
> -
> -	LONG_L	$4, VCPU_R4(k1)
> -	LONG_L	$5, VCPU_R5(k1)
> -	LONG_L	$6, VCPU_R6(k1)
> -	LONG_L	$7, VCPU_R7(k1)
> -
> -	LONG_L	$8, VCPU_R8(k1)
> -	LONG_L	$9, VCPU_R9(k1)
> -	LONG_L	$10, VCPU_R10(k1)
> -	LONG_L	$11, VCPU_R11(k1)
> -	LONG_L	$12, VCPU_R12(k1)
> -	LONG_L	$13, VCPU_R13(k1)
> -	LONG_L	$14, VCPU_R14(k1)
> -	LONG_L	$15, VCPU_R15(k1)
> -	LONG_L	$16, VCPU_R16(k1)
> -	LONG_L	$17, VCPU_R17(k1)
> -	LONG_L	$18, VCPU_R18(k1)
> -	LONG_L	$19, VCPU_R19(k1)
> -	LONG_L	$20, VCPU_R20(k1)
> -	LONG_L	$21, VCPU_R21(k1)
> -	LONG_L	$22, VCPU_R22(k1)
> -	LONG_L	$23, VCPU_R23(k1)
> -	LONG_L	$24, VCPU_R24(k1)
> -	LONG_L	$25, VCPU_R25(k1)
> -
> -	/* k0/k1 loaded up later */
> -
> -	LONG_L	$28, VCPU_R28(k1)
> -	LONG_L	$29, VCPU_R29(k1)
> -	LONG_L	$30, VCPU_R30(k1)
> -	LONG_L	$31, VCPU_R31(k1)
> +	uasm_i_mtc0(&p, ZERO, C0_HWRENA);
> +
> +	/* load the guest context from VCPU and return */
> +	for (i = 1; i < 32; ++i) {
> +		/* Guest k0/k1 loaded later */
> +		if (i == K0 || i == K1)
> +			continue;
> +		UASM_i_LW(&p, i, offsetof(struct kvm_vcpu_arch, gprs[i]), K1);
> +	}
>  
>  	/* Restore hi/lo */
> -	LONG_L	k0, VCPU_LO(k1)
> -	mtlo	k0
> +	UASM_i_LW(&p, K0, offsetof(struct kvm_vcpu_arch, hi), K1);
> +	uasm_i_mthi(&p, K0);
>  
> -	LONG_L	k0, VCPU_HI(k1)
> -	mthi	k0
> +	UASM_i_LW(&p, K0, offsetof(struct kvm_vcpu_arch, lo), K1);
> +	uasm_i_mtlo(&p, K0);
>  
> -FEXPORT(__kvm_mips_load_k0k1)
>  	/* Restore the guest's k0/k1 registers */
> -	LONG_L	k0, VCPU_R26(k1)
> -	LONG_L	k1, VCPU_R27(k1)
> +	UASM_i_LW(&p, K0, offsetof(struct kvm_vcpu_arch, gprs[K0]), K1);
> +	UASM_i_LW(&p, K1, offsetof(struct kvm_vcpu_arch, gprs[K1]), K1);
>  
>  	/* Jump to guest */
> -	eret
> -EXPORT(__kvm_mips_vcpu_run_end)
> -
> -VECTOR(MIPSX(exception), unknown)
> -/* Find out what mode we came from and jump to the proper handler. */
> -	mtc0	k0, CP0_ERROREPC	#01: Save guest k0
> -	ehb				#02:
> -
> -	mfc0	k0, CP0_EBASE		#02: Get EBASE
> -	INT_SRL	k0, k0, 10		#03: Get rid of CPUNum
> -	INT_SLL	k0, k0, 10		#04
> -	LONG_S	k1, 0x3000(k0)		#05: Save k1 @ offset 0x3000
> -	INT_ADDIU k0, k0, 0x2000	#06: Exception handler is
> -					#    installed @ offset 0x2000
> -	j	k0			#07: jump to the function
> -	 nop				#08: branch delay slot
> -VECTOR_END(MIPSX(exceptionEnd))
> -.end MIPSX(exception)
> -
> -/*
> - * Generic Guest exception handler. We end up here when the guest
> - * does something that causes a trap to kernel mode.
> +	uasm_i_eret(&p);
> +
> +	uasm_resolve_relocs(relocs, labels);
> +
> +	return p;
> +}
> +
> +/**
> + * kvm_mips_build_exception() - Assemble first level guest exception handler.
> + * @addr:	Address to start writing code.
> + *
> + * Assemble exception vector code for guest execution. The generated vector will
> + * jump 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)
> +{
> +	u32 *p = addr;
> +
> +	/* Save guest k0 */
> +	uasm_i_mtc0(&p, K0, C0_ERROREPC);
> +	uasm_i_ehb(&p);
> +
> +	/* Get EBASE */
> +	uasm_i_mfc0(&p, K0, C0_EBASE);
> +	/* Get rid of CPUNum */
> +	uasm_i_srl(&p, K0, K0, 10);
> +	uasm_i_sll(&p, K0, K0, 10);
> +	/* 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);
> +	 uasm_i_nop(&p);
> +
> +	return p;
> +}
> +
> +/**
> + * kvm_mips_build_exit() - Assemble common guest exit handler.
> + * @addr:	Address to start writing code.
> + *
> + * Assemble the generic guest exit handling code. This is called by the
> + * exception vectors (generated by kvm_mips_build_exception()), and calls
> + * kvm_mips_handle_exit(), then either resumes the guest or returns to the host
> + * depending on the return value.
> + *
> + * Returns:	Next address after end of written function.
>   */
> -NESTED (MIPSX(GuestException), CALLFRAME_SIZ, ra)
> -	/* Get the VCPU pointer from DDTATA_LO */
> -	mfc0	k1, CP0_DDATA_LO
> -	INT_ADDIU k1, k1, VCPU_HOST_ARCH
> +void *kvm_mips_build_exit(void *addr)
> +{
> +	u32 *p = addr;
> +	unsigned int i;
> +	struct uasm_label labels[3];
> +	struct uasm_reloc relocs[3];
> +	struct uasm_label *l = labels;
> +	struct uasm_reloc *r = relocs;
> +
> +	memset(labels, 0, sizeof(labels));
> +	memset(relocs, 0, sizeof(relocs));
> +
> +	/*
> +	 * Generic Guest exception handler. We end up here when the guest
> +	 * does something that causes a trap to kernel mode.
> +	 */
> +
> +	/* Get the VCPU pointer from DDATA_LO */
> +	uasm_i_mfc0(&p, K1, C0_DDATA_LO);
> +	uasm_i_addiu(&p, K1, K1, offsetof(struct kvm_vcpu, arch));
>  
>  	/* Start saving Guest context to VCPU */
> -	LONG_S	$0, VCPU_R0(k1)
> -	LONG_S	$1, VCPU_R1(k1)
> -	LONG_S	$2, VCPU_R2(k1)
> -	LONG_S	$3, VCPU_R3(k1)
> -	LONG_S	$4, VCPU_R4(k1)
> -	LONG_S	$5, VCPU_R5(k1)
> -	LONG_S	$6, VCPU_R6(k1)
> -	LONG_S	$7, VCPU_R7(k1)
> -	LONG_S	$8, VCPU_R8(k1)
> -	LONG_S	$9, VCPU_R9(k1)
> -	LONG_S	$10, VCPU_R10(k1)
> -	LONG_S	$11, VCPU_R11(k1)
> -	LONG_S	$12, VCPU_R12(k1)
> -	LONG_S	$13, VCPU_R13(k1)
> -	LONG_S	$14, VCPU_R14(k1)
> -	LONG_S	$15, VCPU_R15(k1)
> -	LONG_S	$16, VCPU_R16(k1)
> -	LONG_S	$17, VCPU_R17(k1)
> -	LONG_S	$18, VCPU_R18(k1)
> -	LONG_S	$19, VCPU_R19(k1)
> -	LONG_S	$20, VCPU_R20(k1)
> -	LONG_S	$21, VCPU_R21(k1)
> -	LONG_S	$22, VCPU_R22(k1)
> -	LONG_S	$23, VCPU_R23(k1)
> -	LONG_S	$24, VCPU_R24(k1)
> -	LONG_S	$25, VCPU_R25(k1)
> -
> -	/* Guest k0/k1 saved later */
> -
> -	LONG_S	$28, VCPU_R28(k1)
> -	LONG_S	$29, VCPU_R29(k1)
> -	LONG_S	$30, VCPU_R30(k1)
> -	LONG_S	$31, VCPU_R31(k1)
> -
> -	.set at
> +	for (i = 0; i < 32; ++i) {
> +		/* Guest k0/k1 saved later */
> +		if (i == K0 || i == K1)
> +			continue;
> +		UASM_i_SW(&p, i, offsetof(struct kvm_vcpu_arch, gprs[i]), K1);
> +	}
>  
>  	/* We need to save hi/lo and restore them on the way out */
> -	mfhi	t0
> -	LONG_S	t0, VCPU_HI(k1)
> +	uasm_i_mfhi(&p, T0);
> +	UASM_i_SW(&p, T0, offsetof(struct kvm_vcpu_arch, hi), K1);
>  
> -	mflo	t0
> -	LONG_S	t0, VCPU_LO(k1)
> +	uasm_i_mflo(&p, T0);
> +	UASM_i_SW(&p, T0, offsetof(struct kvm_vcpu_arch, lo), K1);
>  
>  	/* Finally save guest k0/k1 to VCPU */
> -	mfc0	t0, CP0_ERROREPC
> -	LONG_S	t0, VCPU_R26(k1)
> +	uasm_i_mfc0(&p, T0, C0_ERROREPC);
> +	UASM_i_SW(&p, T0, offsetof(struct kvm_vcpu_arch, gprs[K0]), K1);
>  
>  	/* Get GUEST k1 and save it in VCPU */
> -	PTR_LI	t1, ~0x2ff
> -	mfc0	t0, CP0_EBASE
> -	and	t0, t0, t1
> -	LONG_L	t0, 0x3000(t0)
> -	LONG_S	t0, VCPU_R27(k1)
> +	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);
>  
>  	/* Now that context has been saved, we can use other registers */
>  
>  	/* Restore vcpu */
> -	mfc0	a1, CP0_DDATA_LO
> -	move	s1, a1
> +	uasm_i_mfc0(&p, A1, C0_DDATA_LO);
> +	uasm_i_move(&p, S1, A1);
>  
>  	/* Restore run (vcpu->run) */
> -	LONG_L	a0, VCPU_RUN(a1)
> +	UASM_i_LW(&p, A0, offsetof(struct kvm_vcpu, run), A1);
>  	/* Save pointer to run in s0, will be saved by the compiler */
> -	move	s0, a0
> +	uasm_i_move(&p, S0, A0);
>  
>  	/*
> -	 * Save Host level EPC, BadVaddr and Cause to VCPU, useful to
> -	 * process the exception
> +	 * Save Host level EPC, BadVaddr and Cause to VCPU, useful to process
> +	 * the exception
>  	 */
> -	mfc0	k0,CP0_EPC
> -	LONG_S	k0, VCPU_PC(k1)
> +	uasm_i_mfc0(&p, K0, C0_EPC);
> +	UASM_i_SW(&p, K0, offsetof(struct kvm_vcpu_arch, pc), K1);
>  
> -	mfc0	k0, CP0_BADVADDR
> -	LONG_S	k0, VCPU_HOST_CP0_BADVADDR(k1)
> +	uasm_i_mfc0(&p, K0, C0_BADVADDR);
> +	UASM_i_SW(&p, K0, offsetof(struct kvm_vcpu_arch, host_cp0_badvaddr),
> +		  K1);
>  
> -	mfc0	k0, CP0_CAUSE
> -	sw	k0, VCPU_HOST_CP0_CAUSE(k1)
> +	uasm_i_mfc0(&p, K0, C0_CAUSE);
> +	uasm_i_sw(&p, K0, offsetof(struct kvm_vcpu_arch, host_cp0_cause), K1);
>  
>  	/* Now restore the host state just enough to run the handlers */
>  
>  	/* Switch EBASE to the one used by Linux */
>  	/* load up the host EBASE */
> -	mfc0	v0, CP0_STATUS
> +	uasm_i_mfc0(&p, V0, C0_STATUS);
>  
> -	or	k0, v0, ST0_BEV
> +	uasm_i_lui(&p, AT, ST0_BEV >> 16);
> +	uasm_i_or(&p, K0, V0, AT);
>  
> -	mtc0	k0, CP0_STATUS
> -	ehb
> +	uasm_i_mtc0(&p, K0, C0_STATUS);
> +	uasm_i_ehb(&p);
>  
> -	LONG_L	k0, ebase
> -	mtc0	k0,CP0_EBASE
> +	UASM_i_LA_mostly(&p, K0, (long)&ebase);
> +	UASM_i_LW(&p, K0, uasm_rel_lo((long)&ebase), K0);
> +	uasm_i_mtc0(&p, K0, C0_EBASE);
>  
>  	/*
>  	 * If FPU is enabled, save FCR31 and clear it so that later ctc1's don't
>  	 * trigger FPE for pending exceptions.
>  	 */
> -	and	v1, v0, ST0_CU1
> -	beqz	v1, 1f
> -	 nop
> -	.set	push
> -	SET_HARDFLOAT
> -	cfc1	t0, fcr31
> -	sw	t0, VCPU_FCR31(k1)
> -	ctc1	zero,fcr31
> -	.set	pop
> -1:
> +	uasm_i_lui(&p, AT, ST0_CU1 >> 16);
> +	uasm_i_and(&p, V1, V0, AT);
> +	uasm_il_beqz(&p, &r, V1, label_fpu_1);
> +	 uasm_i_nop(&p);
> +	uasm_i_cfc1(&p, T0, 31);
> +	uasm_i_sw(&p, T0, offsetof(struct kvm_vcpu_arch, fpu.fcr31), K1);
> +	uasm_i_ctc1(&p, ZERO, 31);
> +	uasm_l_fpu_1(&l, p);
>  
>  #ifdef CONFIG_CPU_HAS_MSA
>  	/*
>  	 * If MSA is enabled, save MSACSR and clear it so that later
>  	 * instructions don't trigger MSAFPE for pending exceptions.
>  	 */
> -	mfc0	t0, CP0_CONFIG3
> -	ext	t0, t0, 28, 1 /* MIPS_CONF3_MSAP */
> -	beqz	t0, 1f
> -	 nop
> -	mfc0	t0, CP0_CONFIG5
> -	ext	t0, t0, 27, 1 /* MIPS_CONF5_MSAEN */
> -	beqz	t0, 1f
> -	 nop
> -	_cfcmsa	t0, MSA_CSR
> -	sw	t0, VCPU_MSA_CSR(k1)
> -	_ctcmsa	MSA_CSR, zero
> -1:
> +	uasm_i_mfc0(&p, T0, C0_CONFIG3);
> +	uasm_i_ext(&p, T0, T0, 28, 1); /* MIPS_CONF3_MSAP */
> +	uasm_il_beqz(&p, &r, T0, label_msa_1);
> +	 uasm_i_nop(&p);
> +	uasm_i_mfc0(&p, T0, C0_CONFIG5);
> +	uasm_i_ext(&p, T0, T0, 27, 1); /* MIPS_CONF5_MSAEN */
> +	uasm_il_beqz(&p, &r, T0, label_msa_1);
> +	 uasm_i_nop(&p);
> +	uasm_i_cfcmsa(&p, T0, MSA_CSR);
> +	uasm_i_sw(&p, T0, offsetof(struct kvm_vcpu_arch, fpu.msacsr),
> +		  K1);
> +	uasm_i_ctcmsa(&p, MSA_CSR, ZERO);
> +	uasm_l_msa_1(&l, p);
>  #endif
>  
>  	/* Now that the new EBASE has been loaded, unset BEV and KSU_USER */
> -	and	v0, v0, ~(ST0_EXL | KSU_USER | ST0_IE)
> -	or	v0, v0, ST0_CU0
> -	mtc0	v0, CP0_STATUS
> -	ehb
> +	uasm_i_addiu(&p, AT, ZERO, ~(ST0_EXL | KSU_USER | ST0_IE));
> +	uasm_i_and(&p, V0, V0, AT);
> +	uasm_i_lui(&p, AT, ST0_CU0 >> 16);
> +	uasm_i_or(&p, V0, V0, AT);
> +	uasm_i_mtc0(&p, V0, C0_STATUS);
> +	uasm_i_ehb(&p);
>  
>  	/* Load up host GP */
> -	LONG_L	gp, VCPU_HOST_GP(k1)
> +	UASM_i_LW(&p, GP, offsetof(struct kvm_vcpu_arch, host_gp), K1);
>  
>  	/* Need a stack before we can jump to "C" */
> -	LONG_L	sp, VCPU_HOST_STACK(k1)
> +	UASM_i_LW(&p, SP, offsetof(struct kvm_vcpu_arch, host_stack), K1);
>  
>  	/* Saved host state */
> -	INT_ADDIU sp, sp, -PT_SIZE
> +	uasm_i_addiu(&p, SP, SP, -(int)sizeof(struct pt_regs));
>  
>  	/*
>  	 * XXXKYMA do we need to load the host ASID, maybe not because the
> @@ -377,27 +449,54 @@ NESTED (MIPSX(GuestException), CALLFRAME_SIZ, ra)
>  	 */
>  
>  	/* Restore host DDATA_LO */
> -	LONG_L	k0, PT_HOST_USERLOCAL(sp)
> -	mtc0	k0, CP0_DDATA_LO
> +	UASM_i_LW(&p, K0, offsetof(struct pt_regs, cp0_epc), SP);
> +	uasm_i_mtc0(&p, K0, C0_DDATA_LO);
>  
>  	/* Restore RDHWR access */
> -	INT_L	k0, hwrena
> -	mtc0	k0, CP0_HWRENA
> +	UASM_i_LA_mostly(&p, K0, (long)&hwrena);
> +	uasm_i_lw(&p, K0, uasm_rel_lo((long)&hwrena), K0);
> +	uasm_i_mtc0(&p, K0, C0_HWRENA);
>  
>  	/* Jump to handler */
> -FEXPORT(__kvm_mips_jump_to_handler)
>  	/*
>  	 * XXXKYMA: not sure if this is safe, how large is the stack??
>  	 * Now jump to the kvm_mips_handle_exit() to see if we can deal
>  	 * with this in the kernel
>  	 */
> -	PTR_LA	t9, kvm_mips_handle_exit
> -	jalr.hb	t9
> -	 INT_ADDIU sp, sp, -CALLFRAME_SIZ           /* BD Slot */
> +	UASM_i_LA(&p, T9, (unsigned long)kvm_mips_handle_exit);
> +	uasm_i_jalr(&p, RA, T9);
> +	 uasm_i_addiu(&p, SP, SP, -CALLFRAME_SIZ);
> +
> +	uasm_resolve_relocs(relocs, labels);
> +
> +	p = kvm_mips_build_ret_from_exit(p);
> +
> +	return p;
> +}
> +
> +/**
> + * kvm_mips_build_ret_from_exit() - Assemble guest exit return handler.
> + * @addr:	Address to start writing code.
> + *
> + * Assemble the code to handle the return from kvm_mips_handle_exit(), either
> + * resuming the guest or returning to the host depending on the return value.
> + *
> + * Returns:	Next address after end of written function.
> + */
> +static void *kvm_mips_build_ret_from_exit(void *addr)
> +{
> +	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));
>  
>  	/* Return from handler Make sure interrupts are disabled */
> -	di
> -	ehb
> +	uasm_i_di(&p, ZERO);
> +	uasm_i_ehb(&p);
>  
>  	/*
>  	 * XXXKYMA: k0/k1 could have been blown away if we processed
> @@ -405,198 +504,119 @@ FEXPORT(__kvm_mips_jump_to_handler)
>  	 * guest, reload k1
>  	 */
>  
> -	move	k1, s1
> -	INT_ADDIU k1, k1, VCPU_HOST_ARCH
> +	uasm_i_move(&p, K1, S1);
> +	uasm_i_addiu(&p, K1, K1, offsetof(struct kvm_vcpu, arch));
>  
>  	/*
>  	 * Check return value, should tell us if we are returning to the
>  	 * host (handle I/O etc)or resuming the guest
>  	 */
> -	andi	t0, v0, RESUME_HOST
> -	bnez	t0, __kvm_mips_return_to_host
> -	 nop
> +	uasm_i_andi(&p, T0, V0, RESUME_HOST);
> +	uasm_il_bnez(&p, &r, T0, label_return_to_host);
> +	 uasm_i_nop(&p);
> +
> +	p = kvm_mips_build_ret_to_guest(p);
> +
> +	uasm_l_return_to_host(&l, p);
> +	p = kvm_mips_build_ret_to_host(p);
> +
> +	uasm_resolve_relocs(relocs, labels);
> +
> +	return p;
> +}
> +
> +/**
> + * kvm_mips_build_ret_to_guest() - Assemble code to return to the guest.
> + * @addr:	Address to start writing code.
> + *
> + * Assemble the code to handle return from the guest exit handler
> + * (kvm_mips_handle_exit()) back to the guest.
> + *
> + * Returns:	Next address after end of written function.
> + */
> +static void *kvm_mips_build_ret_to_guest(void *addr)
> +{
> +	u32 *p = addr;
>  
> -__kvm_mips_return_to_guest:
>  	/* Put the saved pointer to vcpu (s1) back into the DDATA_LO Register */
> -	mtc0	s1, CP0_DDATA_LO
> +	uasm_i_mtc0(&p, S1, C0_DDATA_LO);
>  
>  	/* Load up the Guest EBASE to minimize the window where BEV is set */
> -	LONG_L	t0, VCPU_GUEST_EBASE(k1)
> +	UASM_i_LW(&p, T0, offsetof(struct kvm_vcpu_arch, guest_ebase), K1);
>  
>  	/* Switch EBASE back to the one used by KVM */
> -	mfc0	v1, CP0_STATUS
> -	or	k0, v1, ST0_BEV
> -	mtc0	k0, CP0_STATUS
> -	ehb
> -	mtc0	t0, CP0_EBASE
> +	uasm_i_mfc0(&p, V1, C0_STATUS);
> +	uasm_i_lui(&p, AT, ST0_BEV >> 16);
> +	uasm_i_or(&p, K0, V1, AT);
> +	uasm_i_mtc0(&p, K0, C0_STATUS);
> +	uasm_i_ehb(&p);
> +	uasm_i_mtc0(&p, T0, C0_EBASE);
>  
>  	/* Setup status register for running guest in UM */
> -	or	v1, v1, (ST0_EXL | KSU_USER | ST0_IE)
> -	and	v1, v1, ~(ST0_CU0 | ST0_MX)
> -	mtc0	v1, CP0_STATUS
> -	ehb
> +	uasm_i_ori(&p, V1, V1, ST0_EXL | KSU_USER | ST0_IE);
> +	UASM_i_LA(&p, AT, ~(ST0_CU0 | ST0_MX));
> +	uasm_i_and(&p, V1, V1, AT);
> +	uasm_i_mtc0(&p, V1, C0_STATUS);
> +	uasm_i_ehb(&p);
> +
> +	p = kvm_mips_build_enter_guest(p);
> +
> +	return p;
> +}
> +
> +/**
> + * kvm_mips_build_ret_to_host() - Assemble code to return to the host.
> + * @addr:	Address to start writing code.
> + *
> + * Assemble the code to handle return from the guest exit handler
> + * (kvm_mips_handle_exit()) back to the host, i.e. to the caller of the vcpu_run
> + * function generated by kvm_mips_build_vcpu_run().
> + *
> + * Returns:	Next address after end of written function.
> + */
> +static void *kvm_mips_build_ret_to_host(void *addr)
> +{
> +	u32 *p = addr;
> +	unsigned int i;
>  
> -	/* Set Guest EPC */
> -	LONG_L	t0, VCPU_PC(k1)
> -	mtc0	t0, CP0_EPC
> -
> -	/* Set the ASID for the Guest Kernel */
> -	PTR_L	t0, VCPU_COP0(k1)
> -	LONG_L	t0, COP0_STATUS(t0)
> -	andi	t0, KSU_USER | ST0_ERL | ST0_EXL
> -	xori	t0, KSU_USER
> -	bnez	t0, 1f		/* If kernel */
> -	 INT_ADDIU t1, k1, VCPU_GUEST_KERNEL_ASID  /* (BD)  */
> -	INT_ADDIU t1, k1, VCPU_GUEST_USER_ASID    /* else user */
> -1:
> -	/* t1: contains the base of the ASID array, need to get the cpu id  */
> -	LONG_L	t2, TI_CPU($28)		/* smp_processor_id */
> -	INT_SLL	t2, t2, 2		/* x4 */
> -	REG_ADDU t3, t1, t2
> -	LONG_L	k0, (t3)
> -#ifdef CONFIG_MIPS_ASID_BITS_VARIABLE
> -	li	t3, CPUINFO_SIZE/4
> -	mul	t2, t2, t3		/* x sizeof(struct cpuinfo_mips)/4 */
> -	LONG_L	t2, (cpu_data + CPUINFO_ASID_MASK)(t2)
> -	and	k0, k0, t2
> -#else
> -	andi	k0, k0, MIPS_ENTRYHI_ASID
> -#endif
> -	mtc0	k0, CP0_ENTRYHI
> -	ehb
> -
> -	/* Disable RDHWR access */
> -	mtc0	zero, CP0_HWRENA
> -
> -	.set	noat
> -	/* load the guest context from VCPU and return */
> -	LONG_L	$0, VCPU_R0(k1)
> -	LONG_L	$1, VCPU_R1(k1)
> -	LONG_L	$2, VCPU_R2(k1)
> -	LONG_L	$3, VCPU_R3(k1)
> -	LONG_L	$4, VCPU_R4(k1)
> -	LONG_L	$5, VCPU_R5(k1)
> -	LONG_L	$6, VCPU_R6(k1)
> -	LONG_L	$7, VCPU_R7(k1)
> -	LONG_L	$8, VCPU_R8(k1)
> -	LONG_L	$9, VCPU_R9(k1)
> -	LONG_L	$10, VCPU_R10(k1)
> -	LONG_L	$11, VCPU_R11(k1)
> -	LONG_L	$12, VCPU_R12(k1)
> -	LONG_L	$13, VCPU_R13(k1)
> -	LONG_L	$14, VCPU_R14(k1)
> -	LONG_L	$15, VCPU_R15(k1)
> -	LONG_L	$16, VCPU_R16(k1)
> -	LONG_L	$17, VCPU_R17(k1)
> -	LONG_L	$18, VCPU_R18(k1)
> -	LONG_L	$19, VCPU_R19(k1)
> -	LONG_L	$20, VCPU_R20(k1)
> -	LONG_L	$21, VCPU_R21(k1)
> -	LONG_L	$22, VCPU_R22(k1)
> -	LONG_L	$23, VCPU_R23(k1)
> -	LONG_L	$24, VCPU_R24(k1)
> -	LONG_L	$25, VCPU_R25(k1)
> -
> -	/* $/k1 loaded later */
> -	LONG_L	$28, VCPU_R28(k1)
> -	LONG_L	$29, VCPU_R29(k1)
> -	LONG_L	$30, VCPU_R30(k1)
> -	LONG_L	$31, VCPU_R31(k1)
> -
> -FEXPORT(__kvm_mips_skip_guest_restore)
> -	LONG_L	k0, VCPU_HI(k1)
> -	mthi	k0
> -
> -	LONG_L	k0, VCPU_LO(k1)
> -	mtlo	k0
> -
> -	LONG_L	k0, VCPU_R26(k1)
> -	LONG_L	k1, VCPU_R27(k1)
> -
> -	eret
> -	.set	at
> -
> -__kvm_mips_return_to_host:
>  	/* EBASE is already pointing to Linux */
> -	LONG_L	k1, VCPU_HOST_STACK(k1)
> -	INT_ADDIU k1,k1, -PT_SIZE
> +	UASM_i_LW(&p, K1, offsetof(struct kvm_vcpu_arch, host_stack), K1);
> +	uasm_i_addiu(&p, K1, K1, -(int)sizeof(struct pt_regs));
>  
>  	/* Restore host DDATA_LO */
> -	LONG_L	k0, PT_HOST_USERLOCAL(k1)
> -	mtc0	k0, CP0_DDATA_LO
> +	UASM_i_LW(&p, K0, offsetof(struct pt_regs, cp0_epc), K1);
> +	uasm_i_mtc0(&p, K0, C0_DDATA_LO);
>  
>  	/*
>  	 * r2/v0 is the return code, shift it down by 2 (arithmetic)
>  	 * to recover the err code
>  	 */
> -	INT_SRA	k0, v0, 2
> -	move	$2, k0
> +	uasm_i_sra(&p, K0, V0, 2);
> +	uasm_i_move(&p, V0, K0);
>  
>  	/* Load context saved on the host stack */
> -	LONG_L	$16, PT_R16(k1)
> -	LONG_L	$17, PT_R17(k1)
> -	LONG_L	$18, PT_R18(k1)
> -	LONG_L	$19, PT_R19(k1)
> -	LONG_L	$20, PT_R20(k1)
> -	LONG_L	$21, PT_R21(k1)
> -	LONG_L	$22, PT_R22(k1)
> -	LONG_L	$23, PT_R23(k1)
> +	for (i = 16; i < 31; ++i) {
> +		if (i == 24)
> +			i = 28;
> +		UASM_i_LW(&p, i, offsetof(struct pt_regs, regs[i]), K1);
> +	}
>  
> -	LONG_L	$28, PT_R28(k1)
> -	LONG_L	$29, PT_R29(k1)
> -	LONG_L	$30, PT_R30(k1)
> +	UASM_i_LW(&p, K0, offsetof(struct pt_regs, hi), K1);
> +	uasm_i_mthi(&p, K0);
>  
> -	LONG_L	k0, PT_HI(k1)
> -	mthi	k0
> -
> -	LONG_L	k0, PT_LO(k1)
> -	mtlo	k0
> +	UASM_i_LW(&p, K0, offsetof(struct pt_regs, lo), K1);
> +	uasm_i_mtlo(&p, K0);
>  
>  	/* Restore RDHWR access */
> -	INT_L	k0, hwrena
> -	mtc0	k0, CP0_HWRENA
> +	UASM_i_LA_mostly(&p, K0, (long)&hwrena);
> +	uasm_i_lw(&p, K0, uasm_rel_lo((long)&hwrena), K0);
> +	uasm_i_mtc0(&p, K0, C0_HWRENA);
>  
>  	/* Restore RA, which is the address we will return to */
> -	LONG_L	ra, PT_R31(k1)
> -	j	ra
> -	 nop
> +	UASM_i_LW(&p, RA, offsetof(struct pt_regs, regs[RA]), K1);
> +	uasm_i_jr(&p, RA);
> +	 uasm_i_nop(&p);
>  
> -VECTOR_END(MIPSX(GuestExceptionEnd))
> -.end MIPSX(GuestException)
> +	return p;
> +}
>  
> -MIPSX(exceptions):
> -	####
> -	##### The exception handlers.
> -	#####
> -	.word _C_LABEL(MIPSX(GuestException))	#  0
> -	.word _C_LABEL(MIPSX(GuestException))	#  1
> -	.word _C_LABEL(MIPSX(GuestException))	#  2
> -	.word _C_LABEL(MIPSX(GuestException))	#  3
> -	.word _C_LABEL(MIPSX(GuestException))	#  4
> -	.word _C_LABEL(MIPSX(GuestException))	#  5
> -	.word _C_LABEL(MIPSX(GuestException))	#  6
> -	.word _C_LABEL(MIPSX(GuestException))	#  7
> -	.word _C_LABEL(MIPSX(GuestException))	#  8
> -	.word _C_LABEL(MIPSX(GuestException))	#  9
> -	.word _C_LABEL(MIPSX(GuestException))	# 10
> -	.word _C_LABEL(MIPSX(GuestException))	# 11
> -	.word _C_LABEL(MIPSX(GuestException))	# 12
> -	.word _C_LABEL(MIPSX(GuestException))	# 13
> -	.word _C_LABEL(MIPSX(GuestException))	# 14
> -	.word _C_LABEL(MIPSX(GuestException))	# 15
> -	.word _C_LABEL(MIPSX(GuestException))	# 16
> -	.word _C_LABEL(MIPSX(GuestException))	# 17
> -	.word _C_LABEL(MIPSX(GuestException))	# 18
> -	.word _C_LABEL(MIPSX(GuestException))	# 19
> -	.word _C_LABEL(MIPSX(GuestException))	# 20
> -	.word _C_LABEL(MIPSX(GuestException))	# 21
> -	.word _C_LABEL(MIPSX(GuestException))	# 22
> -	.word _C_LABEL(MIPSX(GuestException))	# 23
> -	.word _C_LABEL(MIPSX(GuestException))	# 24
> -	.word _C_LABEL(MIPSX(GuestException))	# 25
> -	.word _C_LABEL(MIPSX(GuestException))	# 26
> -	.word _C_LABEL(MIPSX(GuestException))	# 27
> -	.word _C_LABEL(MIPSX(GuestException))	# 28
> -	.word _C_LABEL(MIPSX(GuestException))	# 29
> -	.word _C_LABEL(MIPSX(GuestException))	# 30
> -	.word _C_LABEL(MIPSX(GuestException))	# 31
> diff --git a/arch/mips/kvm/interrupt.h b/arch/mips/kvm/interrupt.h
> index d661c100b219..fb118a2c8379 100644
> --- a/arch/mips/kvm/interrupt.h
> +++ b/arch/mips/kvm/interrupt.h
> @@ -28,10 +28,6 @@
>  #define MIPS_EXC_MAX                12
>  /* XXXSL More to follow */
>  
> -extern char __kvm_mips_vcpu_run_end[];
> -extern char mips32_exception[], mips32_exceptionEnd[];
> -extern char mips32_GuestException[], mips32_GuestExceptionEnd[];
> -
>  #define C_TI        (_ULCAST_(1) << 30)
>  
>  #define KVM_MIPS_IRQ_DELIVER_ALL_AT_ONCE (0)
> diff --git a/arch/mips/kvm/mips.c b/arch/mips/kvm/mips.c
> index 5a2b9034a05c..f00cf5f9ac52 100644
> --- a/arch/mips/kvm/mips.c
> +++ b/arch/mips/kvm/mips.c
> @@ -247,8 +247,8 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
>  
>  struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id)
>  {
> -	int err, size, offset;
> -	void *gebase;
> +	int err, size;
> +	void *gebase, *p;
>  	int i;
>  
>  	struct kvm_vcpu *vcpu = kzalloc(sizeof(struct kvm_vcpu), GFP_KERNEL);
> @@ -286,41 +286,28 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id)
>  	/* Save new ebase */
>  	vcpu->arch.guest_ebase = gebase;
>  
> -	/* Copy L1 Guest Exception handler to correct offset */
> +	/* Build guest exception vectors dynamically in unmapped memory */
>  
>  	/* TLB Refill, EXL = 0 */
> -	memcpy(gebase, mips32_exception,
> -	       mips32_exceptionEnd - mips32_exception);
> +	kvm_mips_build_exception(gebase);
>  
>  	/* General Exception Entry point */
> -	memcpy(gebase + 0x180, mips32_exception,
> -	       mips32_exceptionEnd - mips32_exception);
> +	kvm_mips_build_exception(gebase + 0x180);
>  
>  	/* 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));
> -		memcpy(gebase + 0x200 + (i * VECTORSPACING), mips32_exception,
> -		       mips32_exceptionEnd - mips32_exception);
> +		kvm_mips_build_exception(gebase + 0x200 + i * VECTORSPACING);
>  	}
>  
> -	/* General handler, relocate to unmapped space for sanity's sake */
> -	offset = 0x2000;
> -	kvm_debug("Installing KVM Exception handlers @ %p, %#x bytes\n",
> -		  gebase + offset,
> -		  mips32_GuestExceptionEnd - mips32_GuestException);
> +	/* General exit handler */
> +	p = gebase + 0x2000;
> +	p = kvm_mips_build_exit(p);
>  
> -	memcpy(gebase + offset, mips32_GuestException,
> -	       mips32_GuestExceptionEnd - mips32_GuestException);
> -
> -#ifdef MODULE
> -	offset += mips32_GuestExceptionEnd - mips32_GuestException;
> -	memcpy(gebase + offset, (char *)__kvm_mips_vcpu_run,
> -	       __kvm_mips_vcpu_run_end - (char *)__kvm_mips_vcpu_run);
> -	vcpu->arch.vcpu_run = gebase + offset;
> -#else
> -	vcpu->arch.vcpu_run = __kvm_mips_vcpu_run;
> -#endif
> +	/* Guest entry routine */
> +	vcpu->arch.vcpu_run = p;
> +	p = kvm_mips_build_vcpu_run(p);
>  
>  	/* Invalidate the icache for these ranges */
>  	local_flush_icache_range((unsigned long)gebase,
> -- 
> 2.4.10
> 

Attachment: signature.asc
Description: Digital signature


[Index of Archives]     [Linux MIPS Home]     [LKML Archive]     [Linux ARM Kernel]     [Linux ARM]     [Linux]     [Git]     [Yosemite News]     [Linux SCSI]     [Linux Hams]

  Powered by Linux