]> xenbits.xensource.com Git - unikraft/unikraft.git/commitdiff
arch/arm64: Implement stack switching on IRQ/trap
authorSergiu Moga <sergiu@unikraft.io>
Thu, 23 Nov 2023 14:00:34 +0000 (16:00 +0200)
committerSergiu Moga <sergiu@unikraft.io>
Sat, 25 Nov 2023 11:06:50 +0000 (13:06 +0200)
Define a per-cpu buffer whose size is twice that of the configured
stacks and whose definition may be represented through the following
diagram:
```
      STACK_SIZE               STACK_SIZE
 <---------------------><--------------------->
 |============================================|
 |                     |                      |
 |       trap stack    |        IRQ stack     |
 |                     |                      |
 |=============================================
                       ^
                     SP_EL0
```

The middle address of this buffer shall be assigned to `SP_EL0`,
a great candidate for a register free of use as a `EL1` only Unikernel.

Now, depending on whether an exception is an IRQ or a trap, the early
assembly entry will switch to either the IRQ stack or the trap stack,
by simply making use of the `SP_EL0` system register.

Signed-off-by: Sergiu Moga <sergiu@unikraft.io>
plat/common/arm/lcpu.c
plat/kvm/arm/exceptions.S

index 342a44a8bbe2f8baff8d9e56def4648a4ca8c7d3..654a2ea47d1c26bc3ffc7a2f8c6bb0a2ad83e414 100644 (file)
@@ -30,6 +30,9 @@
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  */
+#include <uk/arch/lcpu.h>
+#include <uk/arch/ctx.h>
+#include <uk/plat/config.h>
 #include <uk/plat/common/bootinfo.h>
 #include <uk/plat/common/acpi.h>
 #include <uk/plat/lcpu.h>
 
 #define CPU_ID_MASK 0xff00ffffffUL
 
+/*
+ *       STACK_SIZE               STACK_SIZE
+ * <---------------------><--------------------->
+ * |============================================|
+ * |                     |                      |
+ * |       trap stack    |        IRQ stack     |
+ * |                     |                      |
+ * |=============================================
+ *                       ^
+ *                     SP_EL0
+ */
+static __align(UKARCH_SP_ALIGN)
+UKPLAT_PER_LCPU_ARRAY_DEFINE(__u8, lcpu_irqntrap_sp, STACK_SIZE * 2);
+
 __lcpuid lcpu_arch_id(void)
 {
        __u64 mpidr_reg;
@@ -80,6 +97,7 @@ extern struct _gic_dev *gic;
 
 int lcpu_arch_init(struct lcpu *this_lcpu)
 {
+       __uptr irqntrap_sp;
        int ret = 0;
 
        /* Initialize the interrupt controller for non-bsp cores */
@@ -91,6 +109,10 @@ int lcpu_arch_init(struct lcpu *this_lcpu)
 
        SYSREG_WRITE64(tpidr_el1, (__uptr)this_lcpu);
 
+       irqntrap_sp = (__uptr)&ukplat_per_lcpu_array_current(lcpu_irqntrap_sp,
+                                                            STACK_SIZE / 2);
+       SYSREG_WRITE64(sp_el0, irqntrap_sp);
+
        return ret;
 }
 
index 98501c13b417853411ef0e94f0d4f1bd3c36a487..865859849f260b154ab41e2e61b5712fb6bab999 100644 (file)
@@ -28,6 +28,8 @@
  */
 #include <uk/arch/lcpu.h>
 #include <uk/asm.h>
+#include <uk/plat/common/lcpu.h>
+#include <uk/plat/config.h>
 
 .macro EXCHANGE_SP_WITH_X0
        add sp, sp, x0  // new_sp = sp + x0
        EXCHANGE_SP_WITH_X0
 .endm
 
-.macro SAVE_REGS
-       sub sp, sp, #__TRAP_STACK_SIZE
+.macro SAVE_REGS, is_irq
+       /* Use TPIDRRO_EL0 as scratch register. It is fine to do so because
+        * it will always hold a value the application can't modify and we will
+        * always be able to restore it to its desired known value anytime we
+        * want. Thus, temporarily store x0.
+        */
+       msr     tpidrro_el0, x0
+
+       /* Fetch middle of `lcpu_irqntrap_sp`:
+        *       STACK_SIZE               STACK_SIZE
+        * <---------------------><--------------------->
+        * |============================================|
+        * |                     |                      |
+        * |       trap stack    |        IRQ stack     |
+        * |                     |                      |
+        * |=============================================
+        *                       ^
+        *                     SP_EL0
+        */
+       mrs     x0, sp_el0
+
+       /* Make it so that SP contains SP_EL0 and x0 contains old SP */
+       EXCHANGE_SP_WITH_X0
+
+.if \is_irq != 0
+       /* If we are an IRQ, use the IRQ stack instead. */
+       add     sp, sp, #STACK_SIZE
+.endif
+
+       /* Store old SP previously saved into x0 */
+       str     x0, [sp, #-16]
+
+       /* Restore x0 */
+       mrs     x0, tpidrro_el0
+
+       /* Begin saving registers */
+       sub     sp, sp, #__TRAP_STACK_SIZE
 
        /* Save general purpose registers */
-       stp x0, x1, [sp, #16 * 0]
-       stp x2, x3, [sp, #16 * 1]
-       stp x4, x5, [sp, #16 * 2]
-       stp x6, x7, [sp, #16 * 3]
-       stp x8, x9, [sp, #16 * 4]
-       stp x10, x11, [sp, #16 * 5]
-       stp x12, x13, [sp, #16 * 6]
-       stp x14, x15, [sp, #16 * 7]
-       stp x16, x17, [sp, #16 * 8]
-       stp x18, x19, [sp, #16 * 9]
-       stp x20, x21, [sp, #16 * 10]
-       stp x22, x23, [sp, #16 * 11]
-       stp x24, x25, [sp, #16 * 12]
-       stp x26, x27, [sp, #16 * 13]
-       stp x28, x29, [sp, #16 * 14]
+       stp     x0, x1, [sp, #16 * 0]
+       stp     x2, x3, [sp, #16 * 1]
+       stp     x4, x5, [sp, #16 * 2]
+       stp     x6, x7, [sp, #16 * 3]
+       stp     x8, x9, [sp, #16 * 4]
+       stp     x10, x11, [sp, #16 * 5]
+       stp     x12, x13, [sp, #16 * 6]
+       stp     x14, x15, [sp, #16 * 7]
+       stp     x16, x17, [sp, #16 * 8]
+       stp     x18, x19, [sp, #16 * 9]
+       stp     x20, x21, [sp, #16 * 10]
+       stp     x22, x23, [sp, #16 * 11]
+       stp     x24, x25, [sp, #16 * 12]
+       stp     x26, x27, [sp, #16 * 13]
+       stp     x28, x29, [sp, #16 * 14]
 
        /* Save LR and exception PC */
-       mrs x21, elr_el1
-       stp x30, x21, [sp, #16 * 15]
+       mrs     x21, elr_el1
+       stp     x30, x21, [sp, #16 * 15]
 
        /* Save pstate and exception status register */
-       mrs x22, spsr_el1
-       mrs x23, esr_el1
-       stp x22, x23, [sp, #16 * 16]
+       mrs     x22, spsr_el1
+       mrs     x23, esr_el1
+       stp     x22, x23, [sp, #16 * 16]
 .endm
 
 .macro RESTORE_REGS
        /* Restore x18, x19 */
        ldp x18, x19, [x19, #16 * 9]
 
-       add sp, sp, #__TRAP_STACK_SIZE
-
        eret
 .endm
 
  */
 .align 6
 el1_sync:
-       SAVE_REGS
+       SAVE_REGS 0
        mov x0, sp
        mrs x1, far_el1
        bl trap_el1_sync
@@ -154,7 +189,7 @@ el1_sync:
 
 .align 6
 el1_irq:
-       SAVE_REGS
+       SAVE_REGS 1
        msr daifclr, #(8 | 4 | 1)
        mov x0, sp
        bl trap_el1_irq
@@ -169,7 +204,7 @@ el1_irq:
 #define el_invalid(name, reason, el)   \
 .align 6;                              \
 name##_invalid:                                \
-       SAVE_REGS;                      \
+       SAVE_REGS 0;                    \
        mov x0, sp;                     \
        mov x1, el;                     \
        mov x2, #(reason);              \