| /* |
| * Copyright (c) 2019 Carlo Caione <ccaione@baylibre.com> |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| /* |
| * ARM64 Cortex-A ISRs wrapper |
| */ |
| |
| #include <zephyr/toolchain.h> |
| #include <zephyr/linker/sections.h> |
| #include <offsets_short.h> |
| #include <zephyr/arch/cpu.h> |
| #include <zephyr/sw_isr_table.h> |
| #include <zephyr/drivers/interrupt_controller/gic.h> |
| #include "macro_priv.inc" |
| |
| _ASM_FILE_PROLOGUE |
| |
| GDATA(_sw_isr_table) |
| |
| /* |
| * Wrapper around ISRs when inserted in software ISR table |
| * |
| * When inserted in the vector table, _isr_wrapper() demuxes the ISR table |
| * using the running interrupt number as the index, and invokes the registered |
| * ISR with its corresponding argument. When returning from the ISR, it |
| * determines if a context switch needs to happen. |
| */ |
| |
| GTEXT(_isr_wrapper) |
| SECTION_FUNC(TEXT, _isr_wrapper) |
| |
| /* ++_current_cpu->nested to be checked by arch_is_in_isr() */ |
| get_cpu x0 |
| ldr w1, [x0, #___cpu_t_nested_OFFSET] |
| add w2, w1, #1 |
| str w2, [x0, #___cpu_t_nested_OFFSET] |
| |
| /* If not nested: switch to IRQ stack and save current sp on it. */ |
| cbnz w1, 1f |
| ldr x1, [x0, #___cpu_t_irq_stack_OFFSET] |
| mov x2, sp |
| mov sp, x1 |
| str x2, [sp, #-16]! |
| #if defined(CONFIG_ARM64_SAFE_EXCEPTION_STACK) |
| sub x1, x1, #CONFIG_ISR_STACK_SIZE |
| str x1, [x0, #_cpu_offset_to_current_stack_limit] |
| #endif |
| 1: |
| #ifdef CONFIG_SCHED_THREAD_USAGE |
| bl z_sched_usage_stop |
| #endif |
| |
| #ifdef CONFIG_TRACING |
| bl sys_trace_isr_enter |
| #endif |
| |
| /* Get active IRQ number from the interrupt controller */ |
| #if !defined(CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER) |
| bl arm_gic_get_active |
| #else |
| bl z_soc_irq_get_active |
| #endif /* !CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER */ |
| |
| #if CONFIG_GIC_VER >= 3 |
| /* |
| * Ignore Special INTIDs 1020..1023 see 2.2.1 of Arm Generic Interrupt Controller |
| * Architecture Specification GIC architecture version 3 and version 4 |
| */ |
| cmp x0, 1019 |
| b.le oob |
| cmp x0, 1023 |
| b.gt oob |
| b spurious_continue |
| |
| oob: |
| #endif |
| /* IRQ out of bounds */ |
| mov x1, #(CONFIG_NUM_IRQS - 1) |
| cmp x0, x1 |
| b.hi spurious_continue |
| |
| stp x0, xzr, [sp, #-16]! |
| |
| /* Retrieve the interrupt service routine */ |
| ldr x1, =_sw_isr_table |
| add x1, x1, x0, lsl #4 /* table is 16-byte wide */ |
| ldp x0, x3, [x1] /* arg in x0, ISR in x3 */ |
| |
| /* |
| * Call the ISR. Unmask and mask again the IRQs to support nested |
| * exception handlers |
| */ |
| msr daifclr, #(DAIFCLR_IRQ_BIT) |
| blr x3 |
| msr daifset, #(DAIFSET_IRQ_BIT) |
| |
| /* Signal end-of-interrupt */ |
| ldp x0, xzr, [sp], #16 |
| |
| spurious_continue: |
| #if !defined(CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER) |
| bl arm_gic_eoi |
| #else |
| bl z_soc_irq_eoi |
| #endif /* !CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER */ |
| |
| #ifdef CONFIG_TRACING |
| bl sys_trace_isr_exit |
| #endif |
| |
| GTEXT(z_arm64_irq_done) |
| z_arm64_irq_done: |
| /* if (--_current_cpu->nested != 0) exit */ |
| get_cpu x0 |
| ldr w1, [x0, #___cpu_t_nested_OFFSET] |
| subs w1, w1, #1 |
| str w1, [x0, #___cpu_t_nested_OFFSET] |
| bne exit |
| |
| /* No more nested: retrieve the task's stack. */ |
| ldr x1, [sp] |
| mov sp, x1 |
| |
| /* retrieve pointer to the current thread */ |
| ldr x1, [x0, #___cpu_t_current_OFFSET] |
| |
| #if defined(CONFIG_ARM64_SAFE_EXCEPTION_STACK) |
| /* arch_curr_cpu()->arch.current_stack_limit = thread->arch.stack_limit */ |
| ldr x2, [x1, #_thread_offset_to_stack_limit] |
| str x2, [x0, #_cpu_offset_to_current_stack_limit] |
| #endif |
| |
| /* |
| * Get next thread to schedule with z_get_next_switch_handle(). |
| * We pass it a NULL as we didn't save the whole thread context yet. |
| * If no scheduling is necessary then NULL will be returned. |
| */ |
| str x1, [sp, #-16]! |
| mov x0, xzr |
| bl z_get_next_switch_handle |
| ldr x1, [sp], #16 |
| cbz x0, exit |
| |
| /* |
| * Switch thread |
| * x0: new thread |
| * x1: old thread |
| */ |
| bl z_arm64_context_switch |
| |
| exit: |
| #ifdef CONFIG_STACK_SENTINEL |
| bl z_check_stack_sentinel |
| #endif |
| b z_arm64_exit_exc |
| |