add basic exception model and context switching for aarch64
authorLunaixsky <lunaixsky@qq.com>
Tue, 1 Oct 2024 22:15:11 +0000 (23:15 +0100)
committerLunaixsky <lunaixsky@qq.com>
Tue, 1 Oct 2024 22:18:03 +0000 (23:18 +0100)
* asbract all bit field operations to generic for readability
  improvements

15 files changed:
lunaix-os/arch/aarch64/LBuild
lunaix-os/arch/aarch64/boot/init.c
lunaix-os/arch/aarch64/exception/context.S [new file with mode: 0644]
lunaix-os/arch/aarch64/exception/entries.S [new file with mode: 0644]
lunaix-os/arch/aarch64/exception/handler.c [new file with mode: 0644]
lunaix-os/arch/aarch64/exception/hart_fields.inc [new file with mode: 0644]
lunaix-os/arch/aarch64/includes/asm/aa64_asm.h
lunaix-os/arch/aarch64/includes/asm/aa64_exception.h [new file with mode: 0644]
lunaix-os/arch/aarch64/includes/asm/aa64_msrs.h
lunaix-os/arch/aarch64/includes/asm/aa64_spsr.h [new file with mode: 0644]
lunaix-os/arch/aarch64/includes/asm/abi.h
lunaix-os/arch/aarch64/includes/asm/hart.h
lunaix-os/includes/lunaix/bits.h [new file with mode: 0644]
lunaix-os/includes/lunaix/compiler.h
lunaix-os/includes/lunaix/sections.h

index 07bebb02e9ae2f2d249c1ed3a5db3386066cfc2b..7526610d39c8ef4c367fe4cb66aa58ce0ad0ab69 100644 (file)
@@ -1,4 +1,16 @@
 
+sources([
+    "boot/init.c",
+    "boot/kremap.c",
+    "boot/start.S"
+])
+
+sources([
+    "exception/entries.S",
+    "exception/context.S",
+    "exception/handler.c"
+])
+
 compile_opts([
     "-mlittle-endian",
     "-mgeneral-regs-only",
index 06b29802bcf45dd018fce6ff46deccc41bfa7034..b4256a76323aad1a2b64d45958cd7005997e90d1 100644 (file)
@@ -1,5 +1,5 @@
 #include <lunaix/boot_generic.h>
-#include <asm/aa64_msrs.h>
+#include <asm/aa64.h>
 
 #include "init.h"
 
@@ -27,10 +27,12 @@ setup_pstate()
    set_sysreg(SPSel, 1);
 }
 
+extern void aa64_vbase();
+
 static inline void
 setup_evbar()
 {
-    // TODO install exception vectors, setup VBAR
+    set_sysreg(VBAR_EL1, aa64_vbase);
 }
 
 static inline void
diff --git a/lunaix-os/arch/aarch64/exception/context.S b/lunaix-os/arch/aarch64/exception/context.S
new file mode 100644 (file)
index 0000000..cbb7cf4
--- /dev/null
@@ -0,0 +1,83 @@
+#define __ASM__
+#include <asm/aa64_msrs.h>
+#include "hart_field.inc"
+
+.section .text
+    
+    .globl _aa64_evec_prehandle
+    .globl _aa64_switch_task
+
+    _aa64_evec_prehandle:
+        stp  xzr, elr, [sp, #-16]!  # push {xzr , elr}
+        stp spsr, xzr, [sp, #-16]!  # push {spsr, xzr}
+
+        stp   lr,  fp, [sp, #-16]!  # push {x31-x1}
+        stp  x28, x27, [sp, #-16]!
+        stp  x26, x25, [sp, #-16]!
+        stp  x24, x23, [sp, #-16]!
+        stp  x22, x21, [sp, #-16]!
+        stp  x20, x19, [sp, #-16]!
+        stp  x18, x17, [sp, #-16]!
+        stp  x16, x15, [sp, #-16]!
+        stp  x14, x13, [sp, #-16]!
+        stp  x12, x11, [sp, #-16]!
+        stp  x10,  x9, [sp, #-16]!
+        stp   x8,  x7, [sp, #-16]!
+        stp   x6,  x5, [sp, #-16]!
+        stp   x4,  x3, [sp, #-16]!
+        stp   x2,  x1, [sp, #-16]!
+        stp   x0, xzr, [sp, #-16]!  # push {x0, xzr}
+
+        add   x1, sp,  #hart_execp
+
+        mrs   x0, SP_EL0
+        str   x0, [x1, #execp_spel0_saved]
+        
+        sub   x0, sp,  #hart_end
+        str   x0, [x1, #execp_spel1_saved]
+        
+        mov   x0, sp
+        bl    handle_exception
+        
+    do_eret:
+        mov   sp,   x0
+
+        add   x1,   x0, #hart_execp
+
+        ldr   x0,  [x1, #execp_spsr]
+        msr   SPSR_EL1, x0
+
+        ldr   x0,  [x1, #execp_link]
+        msr   ELR_E1,   x0
+
+        ldr   x0,  [x1, #execp_spel0_saved]
+        msr   SP_EL0,   x0
+
+        add   sp,  sp, #hart_regs
+
+        ldr   x0,      [sp, #8 ]!
+        ldp   x1,  x2, [sp, #16]!
+        ldp   x3,  x4, [sp, #16]!
+        ldp   x5,  x6, [sp, #16]!
+        ldp   x7,  x8, [sp, #16]!
+        ldp   x9, x10, [sp, #16]!
+        ldp  x11, x12, [sp, #16]!
+        ldp  x13, x14, [sp, #16]!
+        ldp  x15, x16, [sp, #16]!
+        ldp  x17, x18, [sp, #16]!
+        ldp  x19, x20, [sp, #16]!
+        ldp  x21, x22, [sp, #16]!
+        ldp  x23, x24, [sp, #16]!
+        ldp  x25, x26, [sp, #16]!
+        ldp  x27, x28, [sp, #16]!
+        ldp   fp,  lr, [sp, #16]!
+        
+        # sp now point to the start of exec_param
+
+        ldr   sp,  [sp, #execp_spel1_saved]
+
+        eret
+
+    _aa64_switch_task:
+        # TODO
+        b     do_eret
\ No newline at end of file
diff --git a/lunaix-os/arch/aarch64/exception/entries.S b/lunaix-os/arch/aarch64/exception/entries.S
new file mode 100644 (file)
index 0000000..ec96927
--- /dev/null
@@ -0,0 +1,37 @@
+#define __ASM__
+#include <asm/aa64_exception.h>
+#include <asm/aa64_msrs.h>
+
+.macro aa64_exception_entry type
+    .align 128
+    .type  _exception_entry_t\type, @function
+
+    # each handler has at most 128 bytes (32 insts)
+    _exception_entry_t\type:
+        stp x1,  x0,  [sp, #-16]
+
+        # re-purpose the [63, 56] of ESR to exception
+        #  type identifier
+
+        mov x0,  =\type
+        lsl x0,  x0, #56
+        mrs x1,  ESR_EL1
+        orr x0,  x0, x1
+
+        ldr x1,  [sp, #-8]
+        str x0,  [sp, #-8]!
+        ldr x0,  [sp, #-8]
+
+        b _aa64_evec_prehandle
+.endm
+
+.section .text
+
+    .globl aa64_vbase
+    .align 128
+
+    aa64_vbase:
+    aa64_exception_entry EXCEPTION_SYNC
+    aa64_exception_entry EXCEPTION_IRQ
+    aa64_exception_entry EXCEPTION_FIQ
+    aa64_exception_entry EXCEPTION_SERR
diff --git a/lunaix-os/arch/aarch64/exception/handler.c b/lunaix-os/arch/aarch64/exception/handler.c
new file mode 100644 (file)
index 0000000..ab2b806
--- /dev/null
@@ -0,0 +1,27 @@
+#include <lunaix/process.h>
+#include <asm/hart.h>
+
+static inline void
+update_thread_context(struct hart_state* state)
+{
+    if (!current_thread) {
+        return;
+    }
+
+    struct hart_state* parent = current_thread->hstate;
+    hart_push_state(parent, state);
+    current_thread->hstate = state;
+
+    if (parent) {
+        state->depth = parent->depth + 1;
+    }
+}
+
+
+struct hart_state*
+handle_exception(struct hart_state* hstate)
+{
+    update_thread_context(hstate);
+
+    return hstate;
+}
\ No newline at end of file
diff --git a/lunaix-os/arch/aarch64/exception/hart_fields.inc b/lunaix-os/arch/aarch64/exception/hart_fields.inc
new file mode 100644 (file)
index 0000000..62629bc
--- /dev/null
@@ -0,0 +1,32 @@
+    .struct 0
+reg_xn:
+    .struct reg_xn + 8 * 29
+reg_fp:
+    .struct reg_fp + 8
+reg_lr:
+    .struct reg_lr + 8
+reg_end:
+
+    .struct 0
+execp_parent:
+    .struct execp_parent + 8
+execp_spsr:
+    .struct execp_spsr + 8
+execp_link:
+    .struct execp_link + 8
+execp_spel0_saved:
+    .struct execp_spel0_saved + 8
+execp_spel1_saved:
+    .struct execp_spel1_saved + 8
+execp_syndrome:
+    .struct execp_syndrome + 8
+execp_end:
+
+    .struct 0
+hart_depth:
+    .struct hart_depth + 8
+hart_regs:
+    .struct hart_regs + reg_end
+hart_execp:
+    .struct hart_execp + execp_end
+hart_end:
index 1682de7868d0e2630debeb4c6daca206a3fa7508..51dcf5e4f7712de423573e4a74d95d62806de3b5 100644 (file)
@@ -1,9 +1,13 @@
 #ifndef __LUNAIX_AA64_ASM_H
 #define __LUNAIX_AA64_ASM_H
 
-#include <lunaix/compiler.h>
-
 #define __sr_encode(op0, op1, crn, crm, op2)    \
             s##op0##_##op1##_c##crn##_c##crm##_##op2
 
+#ifndef __ASM__
+
+#include <lunaix/compiler.h>
+
+#else
+#endif
 #endif /* __LUNAIX_AA64_ASM_H */
diff --git a/lunaix-os/arch/aarch64/includes/asm/aa64_exception.h b/lunaix-os/arch/aarch64/includes/asm/aa64_exception.h
new file mode 100644 (file)
index 0000000..5ed8104
--- /dev/null
@@ -0,0 +1,59 @@
+#ifndef __LUNAIX_AA64_ESR_H
+#define __LUNAIX_AA64_ESR_H
+
+#ifdef __ASM__
+
+#define EXCEPTION_SYNC      0
+#define EXCEPTION_IFQ       1
+#define EXCEPTION_IRQ       2
+#define EXCEPTION_SERR      3
+
+#else
+
+#include <lunaix/bits.h>
+#include <lunaix/types.h>
+
+#define ESR_ISS2            BITS(55, 32)
+#define ESR_EC              BITS(31, 26)
+#define ESR_IL              BIT(25)
+#define ESR_ISS             BITS(24,  0)
+
+#define EC_UNKNOWN          0b000000
+#define EC_WF               0b000001
+#define EC_SIMD             0b000111
+#define EC_LS64             0b001010
+#define EC_BTI              0b001101
+#define EC_EXEC_STATE       0b001110
+#define EC_SYS_INST         0b011000
+
+#define EC_I_ABORT          0b100000
+#define EC_I_ABORT_EL       0b100001
+
+#define EC_D_ABORT          0b100100
+#define EC_D_ABORT_EL       0b100101
+
+#define EC_PC_ALIGN         0b100010
+#define EC_SP_ALIGN         0b100110
+
+#define EC_SERROR           0b101111
+
+static inline bool
+esr_inst32(reg_t esr)
+{
+    return !!BITS_GET(esr, ESR_IL);
+}
+
+static inline unsigned int
+esr_ec(reg_t esr)
+{
+    return (unsigned int)BITS_GET(esr, ESR_EC);
+}
+
+static inline reg_t
+esr_iss(reg_t esr)
+{
+    return (reg_t)BITS_GET(esr, ESR_ISS);
+}
+
+#endif /* !__ASM__ */
+#endif /* __LUNAIX_AA64_ESR_H */
index d15b11ebf4ccd776252b65e3a8d1bd7348664001..b49d1022cde9a2ebd0c62df3c156a4afbf0eaea6 100644 (file)
@@ -17,6 +17,7 @@
 #define SP_EL0          __sr_encode(3, 0,  4,  1, 0)
 #define SP_EL1          __sr_encode(3, 4,  4,  1, 0)
 
+#ifndef __ASM__
 #define read_sysreg(reg)                                    \
         ({  unsigned long _x;                               \
             asm ("mrs %0, " stringify(reg):"=r"(_x));       \
@@ -40,5 +41,5 @@
 #define SCTRL_A             (1UL << 1)
 #define SCTRL_M             (1UL << 0)
 
-
+#endif
 #endif /* __LUNAIX_AA64_MSRS_H */
diff --git a/lunaix-os/arch/aarch64/includes/asm/aa64_spsr.h b/lunaix-os/arch/aarch64/includes/asm/aa64_spsr.h
new file mode 100644 (file)
index 0000000..07a807a
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef __LUNAIX_AA64_SPSR_H
+#define __LUNAIX_AA64_SPSR_H
+
+#include <lunaix/types.h>
+#include <lunaix/bits.h>
+
+#define SPSR_EL          BITS(3, 2)
+#define SPSR_SP          BIT(0)
+
+static inline bool
+spsr_from_el0(reg_t spsr)
+{
+    return BITS_GET(spsr, SPSR_EL) == 0;
+}
+
+#endif /* __LUNAIX_AA64_SPSR_H */
index 099c0f739a37fbc6f9709c9bd1610c39bc9313fb..c5dc081b4973a9633c218a00a4d6c351e1d7c591 100644 (file)
@@ -9,6 +9,7 @@
 static inline void must_inline noret
 switch_context() {
     // TODO
+    asm ("b _aa64_switch_task");
     unreachable;
 }
 
index f9e7d0ac1c1113f480ab0014de6b71bb7ca8f1c7..89a2e9ae881574564f2d36e4fa09f44107676f72 100644 (file)
@@ -3,74 +3,80 @@
 
 #ifndef __ASM__
 #include <lunaix/types.h>
+#include <lunaix/bits.h>
+#include <asm/aa64_spsr.h>
+
+#define SYNDROME_ETYPE  BITS(63, 56)
 
 struct hart_state;
 
 struct regcontext
 {
     union {
-        reg_t x[32];
+        reg_t x[31];
         struct {
             reg_t x[29];
             reg_t fp;
             reg_t lr;
-            reg_t sp;
         };
     };
-} compact;
+} compact align(8);
 
 struct exec_param
 {
     struct hart_state* parent_state;
-    reg_t vector;
+    reg_t spsr;
+    reg_t link;
+    struct {
+        reg_t sp_el0;
+        reg_t sp_el1;
+    };
+    
     reg_t syndrome;
-    reg_t elink;
-    reg_t sp;
-} compact;
+} compact align(8);
 
 struct hart_state
 {
     reg_t depth;
     struct regcontext registers;
-    union
-    {
-        reg_t sp;
-        volatile struct exec_param* execp;
-    };
-} compact;
+    struct exec_param execp;
+} compact align(16);
 
 static inline int
 hart_vector_stamp(struct hart_state* hstate) {
-    return hstate->execp->vector;
+    return BITS_GET(hstate->execp.syndrome, SYNDROME_ETYPE);
 }
 
 static inline unsigned int
 hart_ecause(struct hart_state* hstate) {
-    return hstate->execp->syndrome;
+    return hstate->execp.syndrome;
 }
 
 static inline struct hart_state*
 hart_parent_state(struct hart_state* hstate)
 {
-    return hstate->execp->parent_state;
+    return hstate->execp.parent_state;
 }
 
 static inline void
 hart_push_state(struct hart_state* p_hstate, struct hart_state* hstate)
 {
-    hstate->execp->parent_state = p_hstate;
+    hstate->execp.parent_state = p_hstate;
 }
 
 static inline ptr_t
 hart_pc(struct hart_state* hstate)
 {
-    return hstate->execp->elink;
+    return hstate->execp.link;
 }
 
 static inline ptr_t
 hart_sp(struct hart_state* hstate)
 {
-    return hstate->execp->sp;
+    if (spsr_from_el0(hstate->execp.spsr)) {
+        return hstate->execp.sp_el0;
+    }
+    return hstate->execp.sp_el1;
 }
 
 static inline bool
diff --git a/lunaix-os/includes/lunaix/bits.h b/lunaix-os/includes/lunaix/bits.h
new file mode 100644 (file)
index 0000000..1029bb0
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef __LUNAIX_BITS_H
+#define __LUNAIX_BITS_H
+
+#include <lunaix/compiler.h>
+
+#define BITS(h, l)               (((1UL << ((h) + 1)) - 1) ^ ((1UL << (l)) - 1))
+#define BIT(p)                   BITS(p, p)
+
+#define BITS_GET(from, bits)     (((from) & (bits)) >> ctzl(bits))
+
+#define BITS_SET(to, bits, val)  \
+            (((to) & ~(bits)) | (((val) << ctzl(bits)) & (bits)))
+
+#endif /* __LUNAIX_BITS_H */
index 178c0fedd598a91544d8cbaac81133942ba0430b..f644112c4300cc594e9e448d1a6a8da6971e36d1 100644 (file)
 
 #define msbiti                  (sizeof(int) * 8 - 1)
 #define clz(bits)               __builtin_clz(bits)
+#define ctz(bits)               __builtin_ctz(bits)
 
 #ifdef CONFIG_ARCH_BITS_64
 #define msbitl                  (sizeof(long) * 8 - 1)
 #define clzl(bits)              __builtin_clzl(bits)
+#define ctzl(bits)              __builtin_ctzl(bits)
 #else
 #define msbitl                  msbiti
 #define clzl(bits)              clz(bits)
+#define ctzl(bits)              ctz(bits)
 #endif
 
 #define sadd_of(a, b, of)       __builtin_sadd_overflow(a, b, of)
index 31828259f3edc667fe650f7e4d3f7eefcb3edd78..daa5ccc5fbffe5ea3713d04b9ee09def21f58d9c 100644 (file)
@@ -27,6 +27,9 @@
 #define reclaimable_start   __section_mark(bssreclaim, start)
 #define reclaimable_end     __section_mark(bssreclaim, end)
 
+#define boot_start          __section_mark(kboot, start)
+#define boot_end            __section_mark(kboot, end)
+
 #define kernel_start        __section_mark(kexec, start)
 #define kernel_load_end     __section_mark(kexec, end)
 #define kernel_end          __section_mark(kimg, end)