[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [RFC 08/10] xen/arm64: Implement the hypercall handing fully in assembly
Currently when the guest is issuing an hypercall, all the registers are saved in the stack and then later reload from the stack before calling the hypercall dispatcher. To avoid spending time loading from the stack the arguments, the hypercall handler can be implemented in assembly. This patch implements the assembly version of do_trap_hypercall for AArch64. Note that the C version of do_trap_hypercall will be dropped in a follow-up patch. Signed-off-by: Julien Grall <julien.grall@xxxxxxxxxx> --- xen/arch/arm/arm64/asm-offsets.c | 11 +++ xen/arch/arm/arm64/entry.S | 147 ++++++++++++++++++++++++++++++++++++++- xen/include/asm-arm/processor.h | 3 + 3 files changed, 159 insertions(+), 2 deletions(-) diff --git a/xen/arch/arm/arm64/asm-offsets.c b/xen/arch/arm/arm64/asm-offsets.c index a3ce816..6f0e8f1 100644 --- a/xen/arch/arm/arm64/asm-offsets.c +++ b/xen/arch/arm/arm64/asm-offsets.c @@ -23,6 +23,12 @@ void __dummy__(void) { OFFSET(UREGS_X0, struct cpu_user_regs, x0); + OFFSET(UREGS_X1, struct cpu_user_regs, x1); + OFFSET(UREGS_X2, struct cpu_user_regs, x2); + OFFSET(UREGS_X3, struct cpu_user_regs, x3); + OFFSET(UREGS_X4, struct cpu_user_regs, x4); + OFFSET(UREGS_X12, struct cpu_user_regs, x12); + OFFSET(UREGS_X16, struct cpu_user_regs, x16); OFFSET(UREGS_LR, struct cpu_user_regs, lr); OFFSET(UREGS_SP, struct cpu_user_regs, sp); @@ -50,6 +56,11 @@ void __dummy__(void) BLANK(); OFFSET(INITINFO_stack, struct init_info, stack); + +#ifdef PERF_COUNTERS + BLANK(); + DEFINE(ASM_PERFC_hypercalls, PERFC_hypercalls); +#endif } /* diff --git a/xen/arch/arm/arm64/entry.S b/xen/arch/arm/arm64/entry.S index 93c80ff..5092533 100644 --- a/xen/arch/arm/arm64/entry.S +++ b/xen/arch/arm/arm64/entry.S @@ -1,4 +1,5 @@ #include <xen/config.h> +#include <xen/errno.h> #include <asm/asm_defns.h> #include <asm/bug.h> #include <asm/regs.h> @@ -174,8 +175,9 @@ hyp_irq: guest_sync: entry hyp=0, compat=0 msr daifclr, #2 + mov x7, x0 mov x0, sp - bl do_trap_hypervisor + bl do_trap_guest_sync exit hyp=0, compat=0 guest_irq: @@ -195,8 +197,9 @@ guest_error_invalid: guest_sync_compat: entry hyp=0, compat=1 msr daifclr, #2 + mov x7, x0 mov x0, sp - bl do_trap_hypervisor + bl do_trap_guest_sync exit hyp=0, compat=1 guest_irq_compat: @@ -277,6 +280,146 @@ ENTRY(hyp_traps_vector) ventry guest_fiq_invalid_compat // FIQ 32-bit EL0/EL1 ventry guest_error_invalid_compat // Error 32-bit EL0/EL1 + +/* + * x0/sp - cpu_user_regs + * x7 - x0 of the guest (possible arg1 of an hypercall) + * x12 - hypercall number for HVC32 + * x16 - hypercall number for HVC64 + * + * Callee-saved register used within the function for specific purpose: + * + * x19 - save x30 (lr) + * x20 - save the guest pc (only for debug build) + * x21 - save the hypercall number + * x22 - ESR_EL2.EC + * + * Note that x1 - x4 shouldn't be clobbered as they contain the + * arguments of the hypercall if the guest issued an hypercall. + */ +do_trap_guest_sync: + mrs x5, ESR_EL2 + lsr x22, x5, #HSR_EC_SHIFT /* x22 <- ESR.EL2.EC */ + /* The trap may be an hypercall if EC == HVC32 || HVC64 */ + cmp x22, #HSR_EC_HVC32 + beq do_trap_hvc32 /* EC == HVC32 -> HVC call */ + cmp x22, #HSR_EC_HVC64 + beq do_trap_hvc /* EC == HVC64 -> HVC call */ + + b do_trap_hypervisor /* Not an HVC call -> generic dispatch */ + +do_trap_hvc32: + /* + * For HVC32, the hypercall number is in x12, load it in x16 + * to have the HVC dispatcher common. + */ + mov x16, x12 + +do_trap_hvc: + /* + * Only HVC call with ISS == XEN_HYPERCALL_TAG is handled in + * assembly, the rest is handled in C by the generic dispatch. + */ + and x6, x5, #HSR_ISS_MASK /* x6 <- ESR_EL2.ISS */ + cmp x6, #XEN_HYPERCALL_TAG + bne do_trap_hypervisor /* Not an hypercall -> generic dispatch */ + +do_trap_hypercall: + /* The guest issued an hypercall */ + + /* Check if the hypercall number is valid */ + cmp x16, #(NR_hypercalls-1) + bhi invalid_hypercall /* Hypercall number invalid -> bail out */ + + PERFC_INCR(hypercalls, x16) + +#ifndef NDEBUG + /* Save guest PC to detect hypercall continuation */ + ldr x20, [sp, #UREGS_PC] /* x20 <- regs->pc */ +#endif + + /* + * Call the hypercall dispatcher + * The arguments arg2 - arg5 are already in the correct + * registers (i.e x1 - x4). + */ + mov x19, lr /* save LR in x19 */ + mov x21, x16 /* save the hypercall number in x21 */ + mov x0, x7 /* x0 <- arg1 */ + mov x5, x16 /* x5 <- Hypercall number */ + bl do_dispatch_hypercall + mov lr, x19 /* Restore LR from x19 */ + + str x0, [sp, #UREGS_X0] /* regs->x0 <- do_dispatch_hypercall(...) */ + +#ifndef NDEBUG + /* + * Clobber arguments register only if pc is unchanged, otherwise + * this is a hypercall continuation. + */ + ldr x0, [sp, #UREGS_PC] /* x0 <- regs->pc */ + cmp x0, x20 /* Compare regs->pc (x0) with orig_pc (x20) */ + bne clobber_done /* different => no need to clobber */ + + ldr x6, =0xdeadbeefdeadbeef /* x6 <- poison for registers */ + + ldr x5, =hypercall_args_table + ldr x5, [x5, x21] /* x5 <- number of args */ + cmp x5, #5; b .Largs5 + cmp x5, #4; b .Largs4 + cmp x5, #3; b .Largs3 + cmp x5, #2; b .Largs2 + cmp x5, #1; b .Largs1 + cmp x5, #0; b .Largs0 /* Only for hypercall not implemented */ + BUG /* Number of arguments invalid */ +.Largs5: + ldr x6, [sp, #UREGS_X4] +.Largs4: + ldr x6, [sp, #UREGS_X3] +.Largs3: + ldr x6, [sp, #UREGS_X2] +.Largs2: + ldr x6, [sp, #UREGS_X1] +.Largs1: + /* Don't clobber x0 -- it's the return value */ + b .Lclobber_nr +.Largs0: + /* + * Can only happen when the hypercall is not implemented. + * i.e hypercall_table[*nr] == do_ni_hypercall + */ + ldr x6, =hypercall_table + ldr x6, [x6, x21, lsl #3] /* x10 := pointer to hypercall function */ + ldr x5, do_ni_hypercall + cmp x5, x6 + beq .Lclobber_nr /* Hypercall function == do_ni_hypercall => Good */ + ASSERT_FAILED("hypercall_table[*nr] == do_ni_hypercall") + +.Lclobber_nr: + /* + * Clobber the hypercall number register. The register depends + * on HSR.EL2 (stored in x22): + * HSR_EC_HVC32 -> x12 + * HSR_EC_HVC64 -> x16 + */ + cmp x22, #HSR_EC_HVC32 + beq .Lclobber_hvc32 +.Lclobber_hvc64: + str x6, [sp, #UREGS_X16] + b clobber_done +.Lclobber_hvc32: + str x6, [sp, #UREGS_X12] + +clobber_done: +#endif + + ret + +invalid_hypercall: + mov x0, #-ENOSYS + str x0, [sp, #UREGS_X0] /* regs->x0 <- -ENOSYS */ + ret + /* * struct vcpu *__context_switch(struct vcpu *prev, struct vcpu *next) * diff --git a/xen/include/asm-arm/processor.h b/xen/include/asm-arm/processor.h index 7e6eb66..da02599 100644 --- a/xen/include/asm-arm/processor.h +++ b/xen/include/asm-arm/processor.h @@ -483,6 +483,9 @@ union hsr { }; #endif +#define HSR_EC_SHIFT 26 +#define HSR_ISS_MASK 0x00ffffff + /* HSR.EC == HSR_CP{15,14,10}_32 */ #define HSR_CP32_OP2_MASK (0x000e0000) #define HSR_CP32_OP2_SHIFT (17) -- 2.1.4 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |