From 6be108db01439d3463342689446e457a315d6705 Mon Sep 17 00:00:00 2001 From: Lunaixsky Date: Tue, 1 Oct 2024 23:15:11 +0100 Subject: [PATCH 1/1] add basic exception model and context switching for aarch64 * asbract all bit field operations to generic for readability improvements --- lunaix-os/arch/aarch64/LBuild | 12 +++ lunaix-os/arch/aarch64/boot/init.c | 6 +- lunaix-os/arch/aarch64/exception/context.S | 83 +++++++++++++++++++ lunaix-os/arch/aarch64/exception/entries.S | 37 +++++++++ lunaix-os/arch/aarch64/exception/handler.c | 27 ++++++ .../arch/aarch64/exception/hart_fields.inc | 32 +++++++ .../arch/aarch64/includes/asm/aa64_asm.h | 8 +- .../aarch64/includes/asm/aa64_exception.h | 59 +++++++++++++ .../arch/aarch64/includes/asm/aa64_msrs.h | 3 +- .../arch/aarch64/includes/asm/aa64_spsr.h | 16 ++++ lunaix-os/arch/aarch64/includes/asm/abi.h | 1 + lunaix-os/arch/aarch64/includes/asm/hart.h | 44 +++++----- lunaix-os/includes/lunaix/bits.h | 14 ++++ lunaix-os/includes/lunaix/compiler.h | 3 + lunaix-os/includes/lunaix/sections.h | 3 + 15 files changed, 324 insertions(+), 24 deletions(-) create mode 100644 lunaix-os/arch/aarch64/exception/context.S create mode 100644 lunaix-os/arch/aarch64/exception/entries.S create mode 100644 lunaix-os/arch/aarch64/exception/handler.c create mode 100644 lunaix-os/arch/aarch64/exception/hart_fields.inc create mode 100644 lunaix-os/arch/aarch64/includes/asm/aa64_exception.h create mode 100644 lunaix-os/arch/aarch64/includes/asm/aa64_spsr.h create mode 100644 lunaix-os/includes/lunaix/bits.h diff --git a/lunaix-os/arch/aarch64/LBuild b/lunaix-os/arch/aarch64/LBuild index 07bebb0..7526610 100644 --- a/lunaix-os/arch/aarch64/LBuild +++ b/lunaix-os/arch/aarch64/LBuild @@ -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", diff --git a/lunaix-os/arch/aarch64/boot/init.c b/lunaix-os/arch/aarch64/boot/init.c index 06b2980..b4256a7 100644 --- a/lunaix-os/arch/aarch64/boot/init.c +++ b/lunaix-os/arch/aarch64/boot/init.c @@ -1,5 +1,5 @@ #include -#include +#include #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 index 0000000..cbb7cf4 --- /dev/null +++ b/lunaix-os/arch/aarch64/exception/context.S @@ -0,0 +1,83 @@ +#define __ASM__ +#include +#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 index 0000000..ec96927 --- /dev/null +++ b/lunaix-os/arch/aarch64/exception/entries.S @@ -0,0 +1,37 @@ +#define __ASM__ +#include +#include + +.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 index 0000000..ab2b806 --- /dev/null +++ b/lunaix-os/arch/aarch64/exception/handler.c @@ -0,0 +1,27 @@ +#include +#include + +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 index 0000000..62629bc --- /dev/null +++ b/lunaix-os/arch/aarch64/exception/hart_fields.inc @@ -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: diff --git a/lunaix-os/arch/aarch64/includes/asm/aa64_asm.h b/lunaix-os/arch/aarch64/includes/asm/aa64_asm.h index 1682de7..51dcf5e 100644 --- a/lunaix-os/arch/aarch64/includes/asm/aa64_asm.h +++ b/lunaix-os/arch/aarch64/includes/asm/aa64_asm.h @@ -1,9 +1,13 @@ #ifndef __LUNAIX_AA64_ASM_H #define __LUNAIX_AA64_ASM_H -#include - #define __sr_encode(op0, op1, crn, crm, op2) \ s##op0##_##op1##_c##crn##_c##crm##_##op2 +#ifndef __ASM__ + +#include + +#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 index 0000000..5ed8104 --- /dev/null +++ b/lunaix-os/arch/aarch64/includes/asm/aa64_exception.h @@ -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 +#include + +#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 */ diff --git a/lunaix-os/arch/aarch64/includes/asm/aa64_msrs.h b/lunaix-os/arch/aarch64/includes/asm/aa64_msrs.h index d15b11e..b49d102 100644 --- a/lunaix-os/arch/aarch64/includes/asm/aa64_msrs.h +++ b/lunaix-os/arch/aarch64/includes/asm/aa64_msrs.h @@ -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 index 0000000..07a807a --- /dev/null +++ b/lunaix-os/arch/aarch64/includes/asm/aa64_spsr.h @@ -0,0 +1,16 @@ +#ifndef __LUNAIX_AA64_SPSR_H +#define __LUNAIX_AA64_SPSR_H + +#include +#include + +#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 */ diff --git a/lunaix-os/arch/aarch64/includes/asm/abi.h b/lunaix-os/arch/aarch64/includes/asm/abi.h index 099c0f7..c5dc081 100644 --- a/lunaix-os/arch/aarch64/includes/asm/abi.h +++ b/lunaix-os/arch/aarch64/includes/asm/abi.h @@ -9,6 +9,7 @@ static inline void must_inline noret switch_context() { // TODO + asm ("b _aa64_switch_task"); unreachable; } diff --git a/lunaix-os/arch/aarch64/includes/asm/hart.h b/lunaix-os/arch/aarch64/includes/asm/hart.h index f9e7d0a..89a2e9a 100644 --- a/lunaix-os/arch/aarch64/includes/asm/hart.h +++ b/lunaix-os/arch/aarch64/includes/asm/hart.h @@ -3,74 +3,80 @@ #ifndef __ASM__ #include +#include +#include + +#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 index 0000000..1029bb0 --- /dev/null +++ b/lunaix-os/includes/lunaix/bits.h @@ -0,0 +1,14 @@ +#ifndef __LUNAIX_BITS_H +#define __LUNAIX_BITS_H + +#include + +#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 */ diff --git a/lunaix-os/includes/lunaix/compiler.h b/lunaix-os/includes/lunaix/compiler.h index 178c0fe..f644112 100644 --- a/lunaix-os/includes/lunaix/compiler.h +++ b/lunaix-os/includes/lunaix/compiler.h @@ -18,13 +18,16 @@ #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) diff --git a/lunaix-os/includes/lunaix/sections.h b/lunaix-os/includes/lunaix/sections.h index 3182825..daa5ccc 100644 --- a/lunaix-os/includes/lunaix/sections.h +++ b/lunaix-os/includes/lunaix/sections.h @@ -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) -- 2.27.0