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

[Xen-devel] [PATCH v3 27/46] xen: arm: arm64 trap handling.



Signed-off-by: Ian Campbell <ian.campbell@xxxxxxxxxx>
Acked-by: Tim Deegan <tim@xxxxxxx>
---
v3: use bitops.h provided LOG() macro
    use simple bl instead of preloading lr and b
    remove an incorrectly placed and inaccurate comment
    declare hyp_traps_vector as an array, avoiding & on uses
v2: Call leave_hypervisor_tail on exit back to guest, disable interrupts while
    restoring state.
---
 xen/arch/arm/arm64/Makefile      |    2 +
 xen/arch/arm/arm64/asm-offsets.c |   58 +++++++++
 xen/arch/arm/arm64/entry.S       |  254 ++++++++++++++++++++++++++++++++++++++
 xen/arch/arm/arm64/traps.c       |   56 +++++++++
 xen/arch/arm/smpboot.c           |    2 +-
 xen/arch/arm/traps.c             |   17 ++-
 xen/include/asm-arm/cpregs.h     |    1 +
 xen/include/asm-arm/processor.h  |    2 +-
 8 files changed, 386 insertions(+), 6 deletions(-)
 create mode 100644 xen/arch/arm/arm64/asm-offsets.c
 create mode 100644 xen/arch/arm/arm64/entry.S
 create mode 100644 xen/arch/arm/arm64/traps.c

diff --git a/xen/arch/arm/arm64/Makefile b/xen/arch/arm/arm64/Makefile
index 815f305..be41f43 100644
--- a/xen/arch/arm/arm64/Makefile
+++ b/xen/arch/arm/arm64/Makefile
@@ -1,5 +1,7 @@
 subdir-y += lib
 
+obj-y += entry.o
 obj-y += mode_switch.o
 
+obj-y += traps.o
 obj-y += domain.o
diff --git a/xen/arch/arm/arm64/asm-offsets.c b/xen/arch/arm/arm64/asm-offsets.c
new file mode 100644
index 0000000..7949e3e
--- /dev/null
+++ b/xen/arch/arm/arm64/asm-offsets.c
@@ -0,0 +1,58 @@
+/*
+ * Generate definitions needed by assembly language modules.
+ * This code generates raw asm output which is post-processed
+ * to extract and format the required data.
+ */
+#define COMPILE_OFFSETS
+
+#include <xen/config.h>
+#include <xen/types.h>
+#include <xen/sched.h>
+#include <xen/bitops.h>
+#include <public/xen.h>
+#include <asm/current.h>
+
+#define DEFINE(_sym, _val) \
+    __asm__ __volatile__ ( "\n->" #_sym " %0 " #_val : : "i" (_val) )
+#define BLANK() \
+    __asm__ __volatile__ ( "\n->" : : )
+#define OFFSET(_sym, _str, _mem) \
+    DEFINE(_sym, offsetof(_str, _mem));
+
+void __dummy__(void)
+{
+   OFFSET(UREGS_X0, struct cpu_user_regs, x0);
+   OFFSET(UREGS_LR, struct cpu_user_regs, lr);
+
+   OFFSET(UREGS_SP, struct cpu_user_regs, sp);
+   OFFSET(UREGS_PC, struct cpu_user_regs, pc);
+   OFFSET(UREGS_CPSR, struct cpu_user_regs, cpsr);
+
+   OFFSET(UREGS_SPSR_el1, struct cpu_user_regs, spsr_el1);
+
+   OFFSET(UREGS_SPSR_fiq, struct cpu_user_regs, spsr_fiq);
+   OFFSET(UREGS_SPSR_irq, struct cpu_user_regs, spsr_irq);
+   OFFSET(UREGS_SPSR_und, struct cpu_user_regs, spsr_und);
+   OFFSET(UREGS_SPSR_abt, struct cpu_user_regs, spsr_abt);
+
+   OFFSET(UREGS_SP_el0, struct cpu_user_regs, sp_el0);
+   OFFSET(UREGS_SP_el1, struct cpu_user_regs, sp_el1);
+   OFFSET(UREGS_ELR_el1, struct cpu_user_regs, elr_el1);
+
+   OFFSET(UREGS_kernel_sizeof, struct cpu_user_regs, cpsr);
+   DEFINE(UREGS_user_sizeof, sizeof(struct cpu_user_regs));
+   BLANK();
+
+   DEFINE(CPUINFO_sizeof, sizeof(struct cpu_info));
+
+   OFFSET(VCPU_arch_saved_context, struct vcpu, arch.saved_context);
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/arch/arm/arm64/entry.S b/xen/arch/arm/arm64/entry.S
new file mode 100644
index 0000000..e35b6ea
--- /dev/null
+++ b/xen/arch/arm/arm64/entry.S
@@ -0,0 +1,254 @@
+#include <xen/config.h>
+#include <asm/asm_defns.h>
+#include <public/xen.h>
+
+/*
+ * Register aliases.
+ */
+lr      .req    x30             // link register
+
+/*
+ * Stack pushing/popping (register pairs only). Equivalent to store decrement
+ * before, load increment after.
+ */
+        .macro  push, xreg1, xreg2
+        stp     \xreg1, \xreg2, [sp, #-16]!
+        .endm
+
+        .macro  pop, xreg1, xreg2
+        ldp     \xreg1, \xreg2, [sp], #16
+        .endm
+
+/*
+ * Save/restore guest mode specific state, outer stack frame
+ */
+        .macro  entry_guest, compat
+
+        add     x21, sp, #UREGS_SPSR_el1
+        mrs     x23, SPSR_EL1
+        str     x23, [x21]
+
+        .if \compat == 0 /* Aarch64 mode */
+
+        add     x21, sp, #UREGS_SP_el0
+        mrs     x22, SP_el0
+        str     x22, [x21]
+
+        add     x21, sp, #UREGS_ELR_el1
+        mrs     x22, SP_el1
+        mrs     x23, ELR_el1
+        stp     x22, x23, [x21]
+
+        .else             /* Aarch32 mode */
+
+        add     x21, sp, #UREGS_SPSR_fiq
+        mrs     x22, spsr_fiq
+        mrs     x23, spsr_irq
+        stp     w22, w23, [x21]
+
+        add     x21, sp, #UREGS_SPSR_und
+        mrs     x22, spsr_und
+        mrs     x23, spsr_abt
+        stp     w22, w23, [x21]
+
+        .endif
+
+        .endm
+
+/*
+ * Save state on entry to hypervisor
+ */
+        .macro  entry, hyp, compat
+        sub     sp, sp, #(UREGS_SPSR_el1 - UREGS_SP)
+        push    x28, x29
+        push    x26, x27
+        push    x24, x25
+        push    x22, x23
+        push    x20, x21
+        push    x18, x19
+        push    x16, x17
+        push    x14, x15
+        push    x12, x13
+        push    x10, x11
+        push    x8, x9
+        push    x6, x7
+        push    x4, x5
+        push    x2, x3
+        push    x0, x1
+
+        .if \hyp == 1        /* Hypervisor mode */
+
+        add     x21, sp, #(UREGS_X0 - UREGS_SP)
+
+        .else                /* Guest mode */
+
+        entry_guest \compat
+        mov     x21, ~0 /* sp only valid for hyp frame XXX */
+
+        .endif
+
+        stp     lr, x21, [sp, #UREGS_LR]
+
+        mrs     x22, elr_el2
+        mrs     x23, spsr_el2
+        stp     x22, x23, [sp, #UREGS_PC]
+
+        .endm
+
+/*
+ * Bad Abort numbers
+ *-----------------
+ */
+#define BAD_SYNC        0
+#define BAD_IRQ         1
+#define BAD_FIQ         2
+#define BAD_ERROR       3
+
+        .macro  invalid, reason
+        mov     x0, sp
+        mov     x1, #\reason
+        b       do_bad_mode
+        .endm
+
+hyp_sync_invalid:
+        entry   hyp=1
+        invalid BAD_SYNC
+
+hyp_irq_invalid:
+        entry   hyp=1
+        invalid BAD_IRQ
+
+hyp_fiq_invalid:
+        entry   hyp=1
+        invalid BAD_FIQ
+
+hyp_error_invalid:
+        entry   hyp=1
+        invalid BAD_ERROR
+
+/* Traps taken in Current EL with SP_ELx */
+hyp_sync:
+        entry   hyp=1
+        msr     daifclr, #2
+        mov     x0, sp
+        bl      do_trap_hypervisor
+        b       return_to_hypervisor
+
+hyp_irq:
+        entry   hyp=1
+        mov     x0, sp
+        bl      do_trap_irq
+        b       return_to_hypervisor
+
+guest_sync:
+        entry   hyp=0, compat=0
+        invalid BAD_SYNC /* No AArch64 guest support yet */
+
+guest_irq:
+        entry   hyp=0, compat=0
+        invalid BAD_IRQ /* No AArch64 guest support yet */
+
+guest_fiq_invalid:
+        entry   hyp=0, compat=0
+        invalid BAD_FIQ
+
+guest_error_invalid:
+        entry   hyp=0, compat=0
+        invalid BAD_ERROR
+
+guest_sync_compat:
+        entry   hyp=0, compat=1
+        msr     daifclr, #2
+        mov     x0, sp
+        bl      do_trap_hypervisor
+        b       return_to_guest
+
+guest_irq_compat:
+        entry   hyp=0, compat=1
+        mov     x0, sp
+        bl      do_trap_irq
+        b       return_to_guest
+
+guest_fiq_invalid_compat:
+        entry   hyp=0, compat=1
+        invalid BAD_FIQ
+
+guest_error_invalid_compat:
+        entry   hyp=0, compat=1
+        invalid BAD_ERROR
+
+ENTRY(return_to_new_vcpu)
+        ldr     x21, [sp, #UREGS_CPSR]
+        and     x21, x21, #PSR_MODE_MASK
+        /* Returning to EL2? */
+        cmp     x21, #PSR_MODE_EL2t
+        ccmp    x21, #PSR_MODE_EL2h, #0x4, ne
+        b.eq    return_to_hypervisor /* Yes */
+        /* Fall thru */
+ENTRY(return_to_guest)
+        bl      leave_hypervisor_tail /* Disables interrupts on return */
+        /* Fall thru */
+ENTRY(return_to_hypervisor)
+        msr     daifset, #2 /* Mask interrupts */
+
+        ldp     x21, x22, [sp, #UREGS_PC]       // load ELR, SPSR
+
+        pop     x0, x1
+        pop     x2, x3
+        pop     x4, x5
+        pop     x6, x7
+        pop     x8, x9
+
+        msr     elr_el2, x21                    // set up the return data
+        msr     spsr_el2, x22
+
+        pop     x10, x11
+        pop     x12, x13
+        pop     x14, x15
+        pop     x16, x17
+        pop     x18, x19
+        pop     x20, x21
+        pop     x22, x23
+        pop     x24, x25
+        pop     x26, x27
+        pop     x28, x29
+
+        ldr     lr, [sp], #(UREGS_SPSR_el1 - UREGS_SP)
+        eret
+
+/*
+ * Exception vectors.
+ */
+        .macro  ventry  label
+        .align  7
+        b       \label
+        .endm
+
+        .align  11
+ENTRY(hyp_traps_vector)
+        ventry  hyp_sync_invalid                // Synchronous EL2t
+        ventry  hyp_irq_invalid                 // IRQ EL2t
+        ventry  hyp_fiq_invalid                 // FIQ EL2t
+        ventry  hyp_error_invalid               // Error EL2t
+
+        ventry  hyp_sync                        // Synchronous EL2h
+        ventry  hyp_irq                         // IRQ EL2h
+        ventry  hyp_fiq_invalid                 // FIQ EL2h
+        ventry  hyp_error_invalid               // Error EL2h
+
+        ventry  guest_sync                      // Synchronous 64-bit EL0/EL1
+        ventry  guest_irq                       // IRQ 64-bit EL0/EL1
+        ventry  guest_fiq_invalid               // FIQ 64-bit EL0/EL1
+        ventry  guest_error_invalid             // Error 64-bit EL0/EL1
+
+        ventry  guest_sync_compat               // Synchronous 32-bit EL0/EL1
+        ventry  guest_irq_compat                // IRQ 32-bit EL0/EL1
+        ventry  guest_fiq_invalid_compat        // FIQ 32-bit EL0/EL1
+        ventry  guest_error_invalid_compat      // Error 32-bit EL0/EL1
+
+/*
+ * Local variables:
+ * mode: ASM
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/arch/arm/arm64/traps.c b/xen/arch/arm/arm64/traps.c
new file mode 100644
index 0000000..02ef992
--- /dev/null
+++ b/xen/arch/arm/arm64/traps.c
@@ -0,0 +1,56 @@
+/*
+ * xen/arch/arm/arm64/traps.c
+ *
+ * ARM AArch64 Specific Trap handlers
+ *
+ * Copyright (c) 2012 Citrix Systems.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <xen/config.h>
+#include <xen/lib.h>
+
+#include <asm/system.h>
+#include <asm/processor.h>
+
+#include <public/xen.h>
+
+asmlinkage void do_trap_serror(struct cpu_user_regs *regs)
+{
+    panic("Unhandled serror trap\n");
+}
+
+static const char *handler[]= {
+        "Synchronous Abort",
+        "IRQ",
+        "FIQ",
+        "Error"
+};
+
+asmlinkage void do_bad_mode(struct cpu_user_regs *regs, int reason)
+{
+    uint64_t esr = READ_SYSREG64(ESR_EL2);
+    printk("Bad mode in %s handler detected, code 0x%08"PRIx64"\n",
+           handler[reason], esr);
+
+    local_irq_disable();
+    panic("bad mode");
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/arch/arm/smpboot.c b/xen/arch/arm/smpboot.c
index 5f0188f..75ee8a9 100644
--- a/xen/arch/arm/smpboot.c
+++ b/xen/arch/arm/smpboot.c
@@ -142,7 +142,7 @@ void __cpuinit start_secondary(unsigned long 
boot_phys_offset,
     set_processor_id(cpuid);
 
     /* Setup Hyp vector base */
-    WRITE_CP32((register_t) hyp_traps_vector, HVBAR);
+    WRITE_SYSREG((vaddr_t)hyp_traps_vector, VBAR_EL2);
 
     mmu_init_secondary_cpu();
     enable_vfp();
diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c
index f96365b..ccd698c 100644
--- a/xen/arch/arm/traps.c
+++ b/xen/arch/arm/traps.c
@@ -628,7 +628,7 @@ static void do_cp15_64(struct cpu_user_regs *regs,
 
 }
 
-void dump_guest_s1_walk(struct domain *d, uint32_t addr)
+void dump_guest_s1_walk(struct domain *d, vaddr_t addr)
 {
     uint32_t ttbcr = READ_CP32(TTBCR);
     uint32_t ttbr0 = READ_CP32(TTBR0);
@@ -636,7 +636,7 @@ void dump_guest_s1_walk(struct domain *d, uint32_t addr)
     uint32_t offset;
     uint32_t *first = NULL, *second = NULL;
 
-    printk("dom%d VA 0x%08"PRIx32"\n", d->domain_id, addr);
+    printk("dom%d VA 0x%08"PRIvaddr"\n", d->domain_id, addr);
     printk("    TTBCR: 0x%08"PRIx32"\n", ttbcr);
     printk("    TTBR0: 0x%08"PRIx32" = 0x%"PRIpaddr"\n",
            ttbr0, p2m_lookup(d, ttbr0 & PAGE_MASK));
@@ -692,7 +692,11 @@ static void do_trap_data_abort_guest(struct cpu_user_regs 
*regs,
     mmio_info_t info;
 
     info.dabt = dabt;
+#ifdef CONFIG_ARM_32
     info.gva = READ_CP32(HDFAR);
+#else
+    info.gva = READ_SYSREG64(FAR_EL2);
+#endif
 
     if (dabt.s1ptw)
         goto bad_data_abort;
@@ -713,7 +717,7 @@ bad_data_abort:
 
     /* XXX inject a suitable fault into the guest */
     printk("Guest data abort: %s%s%s\n"
-           "    gva=%"PRIx32"\n",
+           "    gva=%"PRIvaddr"\n",
            msg, dabt.s1ptw ? " S2 during S1" : "",
            fsc_level_str(level),
            info.gva);
@@ -736,13 +740,17 @@ bad_data_abort:
 
 asmlinkage void do_trap_hypervisor(struct cpu_user_regs *regs)
 {
-    union hsr hsr = { .bits = READ_CP32(HSR) };
+    union hsr hsr = { .bits = READ_SYSREG32(ESR_EL2) };
 
     switch (hsr.ec) {
     case HSR_EC_CP15_32:
+        if ( ! is_pv32_domain(current->domain) )
+            goto bad_trap;
         do_cp15_32(regs, hsr);
         break;
     case HSR_EC_CP15_64:
+        if ( ! is_pv32_domain(current->domain) )
+            goto bad_trap;
         do_cp15_64(regs, hsr);
         break;
     case HSR_EC_HVC:
@@ -754,6 +762,7 @@ asmlinkage void do_trap_hypervisor(struct cpu_user_regs 
*regs)
         do_trap_data_abort_guest(regs, hsr.dabt);
         break;
     default:
+ bad_trap:
         printk("Hypervisor Trap. HSR=0x%x EC=0x%x IL=%x Syndrome=%"PRIx32"\n",
                hsr.bits, hsr.ec, hsr.len, hsr.iss);
         do_unexpected_trap("Hypervisor", regs);
diff --git a/xen/include/asm-arm/cpregs.h b/xen/include/asm-arm/cpregs.h
index 7a7c598..ccd8335 100644
--- a/xen/include/asm-arm/cpregs.h
+++ b/xen/include/asm-arm/cpregs.h
@@ -228,6 +228,7 @@
 #define CCSIDR_EL1              CCSIDR
 #define CLIDR_EL1               CLIDR
 #define CSSELR_EL1              CSSELR
+#define ESR_EL2                 HSR
 #define ID_AFR0_EL1             ID_AFR0
 #define ID_DFR0_EL1             ID_DFR0
 #define ID_ISAR0_EL1            ID_ISAR0
diff --git a/xen/include/asm-arm/processor.h b/xen/include/asm-arm/processor.h
index 63f03ac..c1d7d70 100644
--- a/xen/include/asm-arm/processor.h
+++ b/xen/include/asm-arm/processor.h
@@ -238,7 +238,7 @@ union hsr {
 #endif
 
 #ifndef __ASSEMBLY__
-extern uint32_t hyp_traps_vector[8];
+extern uint32_t hyp_traps_vector[];
 
 void panic_PAR(uint64_t par);
 
-- 
1.7.2.5


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.