// vectors.S — AArch64 Exception Vector Table // Each entry is 128 bytes (32 instructions), aligned to 2KB (0x800) // // Vector table layout: // 0x000 Current EL with SP0: sync, irq, fiq, serror // 0x200 Current EL with SPx: sync, irq, fiq, serror // 0x400 Lower EL AArch64: sync, irq, fiq, serror // 0x600 Lower EL AArch32: sync, irq, fiq, serror .section .text .align 11 // 2KB alignment (2^11 = 2048 = 0x800) .globl vector_table vector_table: // ================================================================ // 0x000: Current EL with SP0 (shouldn't happen in normal operation) // ================================================================ .org 0x000 b . // sync .org 0x080 b . // irq .org 0x100 b . // fiq .org 0x180 b . // serror // ================================================================ // 0x200: Current EL with SPx (kernel mode exceptions) // ================================================================ .org 0x200 b el1_sync_handler // sync (kernel faults, SVC from kernel) .org 0x280 b el1_irq_handler // irq (timer, peripherals while in kernel) .org 0x300 b . // fiq .org 0x380 b . // serror // ================================================================ // 0x400: Lower EL with AArch64 (userspace → kernel transitions) // ================================================================ .org 0x400 b el0_sync_handler // sync (SVC instruction, data abort, etc.) .org 0x480 b el0_irq_handler // irq (timer interrupt from userspace) .org 0x500 b . // fiq .org 0x580 b . // serror // ================================================================ // 0x600: Lower EL with AArch32 (unused — we're AArch64 only) // ================================================================ .org 0x600 b . .org 0x680 b . .org 0x700 b . .org 0x780 b . // ================================================================ // Helper: save all general-purpose registers // ================================================================ .macro save_all_regs stp x0, x1, [sp, #-16]! stp x2, x3, [sp, #-16]! stp x4, x5, [sp, #-16]! stp x6, x7, [sp, #-16]! stp x8, x9, [sp, #-16]! stp x10, x11, [sp, #-16]! stp x12, x13, [sp, #-16]! stp x14, x15, [sp, #-16]! stp x16, x17, [sp, #-16]! stp x18, x19, [sp, #-16]! stp x20, x21, [sp, #-16]! stp x22, x23, [sp, #-16]! stp x24, x25, [sp, #-16]! stp x26, x27, [sp, #-16]! stp x28, x29, [sp, #-16]! stp x30, xzr, [sp, #-16]! // LR + padding .endm .macro restore_all_regs ldp x30, xzr, [sp], #16 ldp x28, x29, [sp], #16 ldp x26, x27, [sp], #16 ldp x24, x25, [sp], #16 ldp x22, x23, [sp], #16 ldp x20, x21, [sp], #16 ldp x18, x19, [sp], #16 ldp x16, x17, [sp], #16 ldp x14, x15, [sp], #16 ldp x12, x13, [sp], #16 ldp x10, x11, [sp], #16 ldp x8, x9, [sp], #16 ldp x6, x7, [sp], #16 ldp x4, x5, [sp], #16 ldp x2, x3, [sp], #16 ldp x0, x1, [sp], #16 .endm // ================================================================ // EL1 Sync Handler (kernel mode synchronous exceptions) // ================================================================ el1_sync_handler: save_all_regs mrs x0, esr_el1 // Exception Syndrome Register mrs x1, elr_el1 // Exception Link Register mov x2, sp bl el1_sync_dispatch restore_all_regs eret // ================================================================ // EL1 IRQ Handler (kernel mode interrupts — timer, etc.) // ================================================================ el1_irq_handler: save_all_regs bl gic_acknowledge // returns IRQ number in x0 mov x19, x0 // save IRQ number bl el1_irq_dispatch // handle the IRQ mov x0, x19 // restore IRQ number bl gic_eoi // end of interrupt restore_all_regs eret // ================================================================ // EL0 Sync Handler (userspace synchronous — SVC instruction) // ================================================================ el0_sync_handler: save_all_regs mrs x0, esr_el1 // Exception Syndrome Register mrs x1, elr_el1 // Exception Link Register (user PC) mrs x2, sp_el0 // User stack pointer mov x3, sp // Kernel stack (for passing to C) bl el0_sync_dispatch restore_all_regs eret // ================================================================ // EL0 IRQ Handler (userspace interrupts — timer from EL0) // ================================================================ el0_irq_handler: save_all_regs bl gic_acknowledge // returns IRQ number in x0 mov x19, x0 // save IRQ number bl el0_irq_dispatch // handle the IRQ mov x0, x19 bl gic_eoi restore_all_regs eret // ================================================================ // C dispatch functions (called from assembly) // ================================================================ // el1_sync_dispatch(esr, elr, sp) — kernel sync exception .globl el1_sync_dispatch el1_sync_dispatch: // For now, just return. We'll handle faults later. ret // el1_irq_dispatch(irq_num) — kernel IRQ .globl el1_irq_dispatch el1_irq_dispatch: // Check if timer IRQ cmp x0, #30 // IRQ_TIMER_CNTP b.ne .Lnot_timer_kern b timer_irq // tail call to timer_irq() .Lnot_timer_kern: ret // el0_sync_dispatch(esr, elr, sp_el0, sp) — userspace sync .globl el0_sync_dispatch el0_sync_dispatch: // Check if SVC instruction (ESR bits [31:26] = 0x15) lsr x4, x0, #26 and x4, x4, #0x3F cmp x4, #0x15 // SVC from AArch64 b.ne .Lnot_svc // TODO: dispatch syscall based on x8 register // For now, just return ret .Lnot_svc: ret // el0_irq_dispatch(irq_num) — userspace IRQ .globl el0_irq_dispatch el0_irq_dispatch: cmp x0, #30 b.ne .Lnot_timer_user b timer_irq .Lnot_timer_user: ret