arch: arm: cortex_a_r: introduce USE_SWITCH
This commit introduce 'USE_SWITCH' feature into cortex-A/R(aarch32) architecture For introducing USE_SWITCH, the exception entry and exit are unified via `z_arm_cortex_ar_enter_exc` and `z_arm_cortex_ar_exit_exc`. All exceptions including ISR are using this way to enter and exit exception handler. Differentiate exception depth and interrupt depth. Allow doing context switch when exception depth greater than 1 but not allow doing this when interrupt depth greater than 1. Currently, USE_SWITCH doesn't support FPU_SHARING and USERSPACE. Signed-off-by: Huifeng Zhang <Huifeng.Zhang@arm.com>
This commit is contained in:
parent
87dd43766d
commit
abde709b5e
17 changed files with 504 additions and 9 deletions
|
@ -34,11 +34,12 @@ config CPU_AARCH32_CORTEX_R
|
||||||
select HAS_CMSIS_CORE
|
select HAS_CMSIS_CORE
|
||||||
select ARCH_HAS_NESTED_EXCEPTION_DETECTION
|
select ARCH_HAS_NESTED_EXCEPTION_DETECTION
|
||||||
select HAS_FLASH_LOAD_OFFSET
|
select HAS_FLASH_LOAD_OFFSET
|
||||||
select ARCH_HAS_USERSPACE if ARM_MPU
|
select ARCH_HAS_USERSPACE if ARM_MPU && !USE_SWITCH
|
||||||
select ARCH_HAS_EXTRA_EXCEPTION_INFO
|
select ARCH_HAS_EXTRA_EXCEPTION_INFO if !USE_SWITCH
|
||||||
select ARCH_HAS_CODE_DATA_RELOCATION
|
select ARCH_HAS_CODE_DATA_RELOCATION
|
||||||
select ARCH_HAS_NOCACHE_MEMORY_SUPPORT if ARM_MPU && CPU_HAS_ARM_MPU && CPU_HAS_DCACHE
|
select ARCH_HAS_NOCACHE_MEMORY_SUPPORT if ARM_MPU && CPU_HAS_ARM_MPU && CPU_HAS_DCACHE
|
||||||
select ARCH_SUPPORTS_ROM_START
|
select ARCH_SUPPORTS_ROM_START
|
||||||
|
select USE_SWITCH_SUPPORTED
|
||||||
help
|
help
|
||||||
This option signifies the use of a CPU of the Cortex-R family.
|
This option signifies the use of a CPU of the Cortex-R family.
|
||||||
|
|
||||||
|
@ -54,8 +55,9 @@ config CPU_AARCH32_CORTEX_A
|
||||||
select CPU_HAS_MMU
|
select CPU_HAS_MMU
|
||||||
select HAS_CMSIS_CORE
|
select HAS_CMSIS_CORE
|
||||||
select HAS_FLASH_LOAD_OFFSET
|
select HAS_FLASH_LOAD_OFFSET
|
||||||
select ARCH_HAS_EXTRA_EXCEPTION_INFO
|
select ARCH_HAS_EXTRA_EXCEPTION_INFO if !USE_SWITCH
|
||||||
select ARCH_HAS_NOCACHE_MEMORY_SUPPORT
|
select ARCH_HAS_NOCACHE_MEMORY_SUPPORT
|
||||||
|
select USE_SWITCH_SUPPORTED
|
||||||
help
|
help
|
||||||
This option signifies the use of a CPU of the Cortex-A family.
|
This option signifies the use of a CPU of the Cortex-A family.
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,6 @@ zephyr_library()
|
||||||
|
|
||||||
zephyr_library_sources(
|
zephyr_library_sources(
|
||||||
exc.S
|
exc.S
|
||||||
exc_exit.S
|
|
||||||
fault.c
|
fault.c
|
||||||
irq_init.c
|
irq_init.c
|
||||||
reboot.c
|
reboot.c
|
||||||
|
@ -12,8 +11,6 @@ zephyr_library_sources(
|
||||||
stacks.c
|
stacks.c
|
||||||
tcm.c
|
tcm.c
|
||||||
vector_table.S
|
vector_table.S
|
||||||
swap.c
|
|
||||||
swap_helper.S
|
|
||||||
irq_manage.c
|
irq_manage.c
|
||||||
prep_c.c
|
prep_c.c
|
||||||
thread.c
|
thread.c
|
||||||
|
@ -25,3 +22,5 @@ zephyr_library_sources_ifdef(CONFIG_USERSPACE thread.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_SEMIHOST semihost.c)
|
zephyr_library_sources_ifdef(CONFIG_SEMIHOST semihost.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_THREAD_LOCAL_STORAGE __aeabi_read_tp.S)
|
zephyr_library_sources_ifdef(CONFIG_THREAD_LOCAL_STORAGE __aeabi_read_tp.S)
|
||||||
zephyr_library_sources_ifdef(CONFIG_ARCH_CACHE cache.c)
|
zephyr_library_sources_ifdef(CONFIG_ARCH_CACHE cache.c)
|
||||||
|
zephyr_library_sources_ifdef(CONFIG_USE_SWITCH switch.S)
|
||||||
|
zephyr_library_sources_ifndef(CONFIG_USE_SWITCH swap.c swap_helper.S exc_exit.S)
|
||||||
|
|
|
@ -99,7 +99,7 @@ config CPU_CORTEX_R52
|
||||||
select AARCH32_ARMV8_R
|
select AARCH32_ARMV8_R
|
||||||
select CPU_HAS_ICACHE
|
select CPU_HAS_ICACHE
|
||||||
select CPU_HAS_DCACHE
|
select CPU_HAS_DCACHE
|
||||||
select VFP_SP_D16
|
select VFP_SP_D16 if !USE_SWITCH
|
||||||
help
|
help
|
||||||
This option signifies the use of a Cortex-R52 CPU
|
This option signifies the use of a Cortex-R52 CPU
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,8 @@ GTEXT(z_arm_undef_instruction)
|
||||||
GTEXT(z_arm_prefetch_abort)
|
GTEXT(z_arm_prefetch_abort)
|
||||||
GTEXT(z_arm_data_abort)
|
GTEXT(z_arm_data_abort)
|
||||||
|
|
||||||
|
#ifndef CONFIG_USE_SWITCH
|
||||||
|
|
||||||
.macro exception_entry mode
|
.macro exception_entry mode
|
||||||
/*
|
/*
|
||||||
* Store r0-r3, r12, lr, lr_und and spsr_und into the stack to
|
* Store r0-r3, r12, lr, lr_und and spsr_und into the stack to
|
||||||
|
@ -233,3 +235,59 @@ SECTION_SUBSEC_FUNC(TEXT, __exc, z_arm_data_abort)
|
||||||
streq r1, [sp, #24 + FPU_SF_SIZE]
|
streq r1, [sp, #24 + FPU_SF_SIZE]
|
||||||
|
|
||||||
b z_arm_exc_exit
|
b z_arm_exc_exit
|
||||||
|
|
||||||
|
#else
|
||||||
|
/**
|
||||||
|
* @brief Undefined instruction exception handler
|
||||||
|
*
|
||||||
|
* An undefined instruction (UNDEF) exception is generated when an undefined
|
||||||
|
* instruction, or a VFP instruction when the VFP is not enabled, is
|
||||||
|
* encountered.
|
||||||
|
*/
|
||||||
|
SECTION_SUBSEC_FUNC(TEXT, __exc, z_arm_undef_instruction)
|
||||||
|
/*
|
||||||
|
* The undefined instruction address is offset by 2 if the previous
|
||||||
|
* mode is Thumb; otherwise, it is offset by 4.
|
||||||
|
*/
|
||||||
|
push {r0}
|
||||||
|
mrs r0, spsr
|
||||||
|
tst r0, #T_BIT
|
||||||
|
subeq lr, #4 /* ARM (!T_BIT) */
|
||||||
|
subne lr, #2 /* Thumb (T_BIT) */
|
||||||
|
pop {r0}
|
||||||
|
|
||||||
|
z_arm_cortex_ar_enter_exc
|
||||||
|
bl z_arm_fault_undef_instruction
|
||||||
|
b z_arm_cortex_ar_exit_exc
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Prefetch abort exception handler
|
||||||
|
*
|
||||||
|
* A prefetch abort (PABT) exception is generated when the processor marks the
|
||||||
|
* prefetched instruction as invalid and the instruction is executed.
|
||||||
|
*/
|
||||||
|
SECTION_SUBSEC_FUNC(TEXT, __exc, z_arm_prefetch_abort)
|
||||||
|
/*
|
||||||
|
* The faulting instruction address is always offset by 4 for the
|
||||||
|
* prefetch abort exceptions.
|
||||||
|
*/
|
||||||
|
sub lr, #4
|
||||||
|
z_arm_cortex_ar_enter_exc
|
||||||
|
bl z_arm_fault_prefetch
|
||||||
|
b z_arm_cortex_ar_exit_exc
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Data abort exception handler
|
||||||
|
*
|
||||||
|
* A data abort (DABT) exception is generated when an error occurs on a data
|
||||||
|
* memory access. This exception can be either synchronous or asynchronous,
|
||||||
|
* depending on the type of fault that caused it.
|
||||||
|
*/
|
||||||
|
SECTION_SUBSEC_FUNC(TEXT, __exc, z_arm_data_abort)
|
||||||
|
sub lr, #8
|
||||||
|
|
||||||
|
z_arm_cortex_ar_enter_exc
|
||||||
|
bl z_arm_fault_data
|
||||||
|
b z_arm_cortex_ar_exit_exc
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -32,6 +32,7 @@ GDATA(_sw_isr_table)
|
||||||
GTEXT(_isr_wrapper)
|
GTEXT(_isr_wrapper)
|
||||||
GTEXT(z_arm_int_exit)
|
GTEXT(z_arm_int_exit)
|
||||||
|
|
||||||
|
#ifndef CONFIG_USE_SWITCH
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @brief Wrapper around ISRs when inserted in software ISR table
|
* @brief Wrapper around ISRs when inserted in software ISR table
|
||||||
|
@ -228,3 +229,145 @@ spurious_continue:
|
||||||
* z_arm_int_exit() */
|
* z_arm_int_exit() */
|
||||||
ldr r1, =z_arm_int_exit
|
ldr r1, =z_arm_int_exit
|
||||||
bx r1
|
bx r1
|
||||||
|
|
||||||
|
#else
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @brief 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 and invoke the arch_switch
|
||||||
|
* function if so.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
SECTION_FUNC(TEXT, _isr_wrapper)
|
||||||
|
sub lr, #4
|
||||||
|
z_arm_cortex_ar_enter_exc
|
||||||
|
|
||||||
|
/* Increment interrupt nesting count */
|
||||||
|
get_cpu r2
|
||||||
|
ldr r0, [r2, #___cpu_t_nested_OFFSET]
|
||||||
|
add r0, #1
|
||||||
|
str r0, [r2, #___cpu_t_nested_OFFSET]
|
||||||
|
|
||||||
|
/* If not nested: switch to IRQ stack and save current sp on it. */
|
||||||
|
cmp r0, #1
|
||||||
|
bhi 1f
|
||||||
|
mov r0, sp
|
||||||
|
cps #MODE_IRQ
|
||||||
|
push {r0}
|
||||||
|
1:
|
||||||
|
#ifdef CONFIG_TRACING_ISR
|
||||||
|
bl sys_trace_isr_enter
|
||||||
|
#endif /* CONFIG_TRACING_ISR */
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM
|
||||||
|
/*
|
||||||
|
* All interrupts are disabled when handling idle wakeup. For tickless
|
||||||
|
* idle, this ensures that the calculation and programming of the
|
||||||
|
* device for the next timer deadline is not interrupted. For
|
||||||
|
* non-tickless idle, this ensures that the clearing of the kernel idle
|
||||||
|
* state is not interrupted. In each case, z_pm_save_idle_exit
|
||||||
|
* is called with interrupts disabled.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* is this a wakeup from idle ? */
|
||||||
|
ldr r2, =_kernel
|
||||||
|
/* requested idle duration, in ticks */
|
||||||
|
ldr r0, [r2, #_kernel_offset_to_idle]
|
||||||
|
cmp r0, #0
|
||||||
|
|
||||||
|
beq _idle_state_cleared
|
||||||
|
movs r1, #0
|
||||||
|
/* clear kernel idle state */
|
||||||
|
str r1, [r2, #_kernel_offset_to_idle]
|
||||||
|
bl z_pm_save_idle_exit
|
||||||
|
_idle_state_cleared:
|
||||||
|
#endif /* CONFIG_PM */
|
||||||
|
|
||||||
|
/* 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 */
|
||||||
|
|
||||||
|
push {r0, r1}
|
||||||
|
lsl r0, r0, #3 /* table is 8-byte wide */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Skip calling the isr if it is a spurious interrupt.
|
||||||
|
*/
|
||||||
|
mov r1, #CONFIG_NUM_IRQS
|
||||||
|
lsl r1, r1, #3
|
||||||
|
cmp r0, r1
|
||||||
|
bge spurious_continue
|
||||||
|
|
||||||
|
ldr r1, =_sw_isr_table
|
||||||
|
add r1, r1, r0 /* table entry: ISRs must have their MSB set to stay
|
||||||
|
* in thumb mode */
|
||||||
|
ldm r1!,{r0,r3} /* arg in r0, ISR in r3 */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enable and disable interrupts again to allow nested in exception handlers.
|
||||||
|
*/
|
||||||
|
cpsie i
|
||||||
|
blx r3 /* call ISR */
|
||||||
|
cpsid i
|
||||||
|
|
||||||
|
spurious_continue:
|
||||||
|
/* Signal end-of-interrupt */
|
||||||
|
pop {r0, r1}
|
||||||
|
#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_ISR
|
||||||
|
bl sys_trace_isr_exit
|
||||||
|
#endif
|
||||||
|
|
||||||
|
GTEXT(z_arm_cortex_ar_irq_done)
|
||||||
|
z_arm_cortex_ar_irq_done:
|
||||||
|
/* Decrement interrupt nesting count */
|
||||||
|
get_cpu r2
|
||||||
|
ldr r0, [r2, #___cpu_t_nested_OFFSET]
|
||||||
|
sub r0, r0, #1
|
||||||
|
str r0, [r2, #___cpu_t_nested_OFFSET]
|
||||||
|
/* Do not context switch if exiting a nested interrupt */
|
||||||
|
cmp r0, #0
|
||||||
|
bhi __EXIT_INT
|
||||||
|
|
||||||
|
/* retrieve pointer to the current thread */
|
||||||
|
pop {r0}
|
||||||
|
cps #MODE_SYS
|
||||||
|
mov sp, r0
|
||||||
|
|
||||||
|
ldr r1, [r2, #___cpu_t_current_OFFSET]
|
||||||
|
push {r1}
|
||||||
|
mov r0, #0
|
||||||
|
bl z_get_next_switch_handle
|
||||||
|
|
||||||
|
pop {r1}
|
||||||
|
cmp r0, #0
|
||||||
|
beq __EXIT_INT
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Switch thread
|
||||||
|
* r0: new thread
|
||||||
|
* r1: old thread
|
||||||
|
*/
|
||||||
|
bl z_arm_context_switch
|
||||||
|
|
||||||
|
__EXIT_INT:
|
||||||
|
|
||||||
|
#ifdef CONFIG_STACK_SENTINEL
|
||||||
|
bl z_check_stack_sentinel
|
||||||
|
#endif /* CONFIG_STACK_SENTINEL */
|
||||||
|
|
||||||
|
b z_arm_cortex_ar_exit_exc
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -16,4 +16,24 @@
|
||||||
and \rreg0, #TPIDRURO_CURR_CPU
|
and \rreg0, #TPIDRURO_CURR_CPU
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
|
.macro z_arm_cortex_ar_enter_exc
|
||||||
|
/*
|
||||||
|
* Store r0-r3, r12, lr into the stack to construct an exception
|
||||||
|
* stack frame.
|
||||||
|
*/
|
||||||
|
srsdb sp!, #MODE_SYS
|
||||||
|
cps #MODE_SYS
|
||||||
|
stmdb sp, {r0-r3, r12, lr}^
|
||||||
|
sub sp, #24
|
||||||
|
|
||||||
|
/* TODO: EXTRA_EXCEPTION_INFO */
|
||||||
|
mov r0, sp
|
||||||
|
|
||||||
|
/* increment exception depth */
|
||||||
|
get_cpu r2
|
||||||
|
ldrb r1, [r2, #_cpu_offset_to_exc_depth]
|
||||||
|
add r1, r1, #1
|
||||||
|
strb r1, [r2, #_cpu_offset_to_exc_depth]
|
||||||
|
.endm
|
||||||
|
|
||||||
#endif /* _MACRO_PRIV_INC_ */
|
#endif /* _MACRO_PRIV_INC_ */
|
||||||
|
|
165
arch/arm/core/cortex_a_r/switch.S
Normal file
165
arch/arm/core/cortex_a_r/switch.S
Normal file
|
@ -0,0 +1,165 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 Arm Limited (or its affiliates). All rights reserved.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* @brief Thread context switching for ARM Cortex-A and Cortex-R (AArch32)
|
||||||
|
*
|
||||||
|
* This module implements the routines necessary for thread context switching
|
||||||
|
* on ARM Cortex-A and Cortex-R CPUs.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <zephyr/toolchain.h>
|
||||||
|
#include <zephyr/linker/sections.h>
|
||||||
|
#include <zephyr/arch/cpu.h>
|
||||||
|
#include <offsets_short.h>
|
||||||
|
#include <zephyr/kernel.h>
|
||||||
|
#include "macro_priv.inc"
|
||||||
|
|
||||||
|
_ASM_FILE_PROLOGUE
|
||||||
|
|
||||||
|
GTEXT(z_arm_svc)
|
||||||
|
GTEXT(z_arm_context_switch)
|
||||||
|
GTEXT(z_do_kernel_oops)
|
||||||
|
GTEXT(z_arm_do_syscall)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Routine to handle context switches
|
||||||
|
*
|
||||||
|
* This function is directly called either by _isr_wrapper() in case of
|
||||||
|
* preemption, or arch_switch() in case of cooperative switching.
|
||||||
|
*
|
||||||
|
* void z_arm_context_switch(struct k_thread *new, struct k_thread *old);
|
||||||
|
*/
|
||||||
|
SECTION_FUNC(TEXT, z_arm_context_switch)
|
||||||
|
|
||||||
|
ldr r2, =_thread_offset_to_callee_saved
|
||||||
|
add r2, r1, r2
|
||||||
|
|
||||||
|
stm r2, {r4-r11, sp, lr}
|
||||||
|
|
||||||
|
/* save current thread's exception depth */
|
||||||
|
get_cpu r2
|
||||||
|
ldrb r3, [r2, #_cpu_offset_to_exc_depth]
|
||||||
|
strb r3, [r1, #_thread_offset_to_exception_depth]
|
||||||
|
|
||||||
|
/* retrieve next thread's exception depth */
|
||||||
|
ldrb r3, [r0, #_thread_offset_to_exception_depth]
|
||||||
|
strb r3, [r2, #_cpu_offset_to_exc_depth]
|
||||||
|
|
||||||
|
/* save old thread into switch handle which is required by
|
||||||
|
* z_sched_switch_spin().
|
||||||
|
*
|
||||||
|
* Note that this step must be done after all relevant state is
|
||||||
|
* saved.
|
||||||
|
*/
|
||||||
|
dsb
|
||||||
|
str r1, [r1, #___thread_t_switch_handle_OFFSET]
|
||||||
|
|
||||||
|
#if defined(CONFIG_THREAD_LOCAL_STORAGE)
|
||||||
|
/* Grab the TLS pointer */
|
||||||
|
ldr r3, [r0, #_thread_offset_to_tls]
|
||||||
|
|
||||||
|
/* Store TLS pointer in the "Process ID" register.
|
||||||
|
* This register is used as a base pointer to all
|
||||||
|
* thread variables with offsets added by toolchain.
|
||||||
|
*/
|
||||||
|
mcr 15, 0, r3, c13, c0, 2
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ldr r2, =_thread_offset_to_callee_saved
|
||||||
|
add r2, r0, r2
|
||||||
|
ldm r2, {r4-r11, sp, lr}
|
||||||
|
|
||||||
|
#if defined (CONFIG_ARM_MPU)
|
||||||
|
/* Re-program dynamic memory map */
|
||||||
|
push {r0, lr}
|
||||||
|
bl z_arm_configure_dynamic_mpu_regions
|
||||||
|
pop {r0, lr}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_INSTRUMENT_THREAD_SWITCHING
|
||||||
|
push {lr}
|
||||||
|
bl z_thread_mark_switched_in
|
||||||
|
pop {lr}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bx lr
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @brief Service call handler
|
||||||
|
*
|
||||||
|
* The service call (svc) is used in the following occasions:
|
||||||
|
* - Cooperative context switching
|
||||||
|
* - IRQ offloading
|
||||||
|
* - Kernel run-time exceptions
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
SECTION_FUNC(TEXT, z_arm_svc)
|
||||||
|
z_arm_cortex_ar_enter_exc
|
||||||
|
|
||||||
|
/* Get SVC number */
|
||||||
|
cps #MODE_SVC
|
||||||
|
mrs r0, spsr
|
||||||
|
tst r0, #0x20
|
||||||
|
ldreq r1, [lr, #-4]
|
||||||
|
biceq r1, #0xff000000
|
||||||
|
beq demux
|
||||||
|
|
||||||
|
ldr r1, [lr, #-2]
|
||||||
|
and r1, #0xff
|
||||||
|
|
||||||
|
/*
|
||||||
|
* grab service call number:
|
||||||
|
* TODO 0: context switch
|
||||||
|
* 1: irq_offload (if configured)
|
||||||
|
* 2: kernel panic or oops (software generated fatal exception)
|
||||||
|
* TODO 3: system calls for memory protection
|
||||||
|
*/
|
||||||
|
demux:
|
||||||
|
cps #MODE_SYS
|
||||||
|
|
||||||
|
cmp r1, #_SVC_CALL_RUNTIME_EXCEPT
|
||||||
|
beq _oops
|
||||||
|
|
||||||
|
#ifdef CONFIG_IRQ_OFFLOAD
|
||||||
|
cmp r1, #_SVC_CALL_IRQ_OFFLOAD
|
||||||
|
beq offload
|
||||||
|
b inv
|
||||||
|
offload:
|
||||||
|
get_cpu r2
|
||||||
|
ldr r3, [r2, #___cpu_t_nested_OFFSET]
|
||||||
|
add r3, r3, #1
|
||||||
|
str r3, [r2, #___cpu_t_nested_OFFSET]
|
||||||
|
|
||||||
|
/* If not nested: switch to IRQ stack and save current sp on it. */
|
||||||
|
cmp r3, #1
|
||||||
|
bhi 1f
|
||||||
|
mov r0, sp
|
||||||
|
cps #MODE_IRQ
|
||||||
|
push {r0}
|
||||||
|
|
||||||
|
1:
|
||||||
|
blx z_irq_do_offload
|
||||||
|
b z_arm_cortex_ar_irq_done
|
||||||
|
#endif
|
||||||
|
b inv
|
||||||
|
|
||||||
|
_oops:
|
||||||
|
/*
|
||||||
|
* Pass the exception frame to z_do_kernel_oops. r0 contains the
|
||||||
|
* exception reason.
|
||||||
|
*/
|
||||||
|
mov r0, sp
|
||||||
|
bl z_do_kernel_oops
|
||||||
|
|
||||||
|
inv:
|
||||||
|
mov r0, #0 /* K_ERR_CPU_EXCEPTION */
|
||||||
|
mov r1, sp
|
||||||
|
bl z_arm_fatal_error
|
||||||
|
|
||||||
|
/* Return here only in case of recoverable error */
|
||||||
|
b z_arm_cortex_ar_exit_exc
|
|
@ -125,6 +125,13 @@ void arch_new_thread(struct k_thread *thread, k_thread_stack_t *stack,
|
||||||
* initial values in all other registers/thread entries are
|
* initial values in all other registers/thread entries are
|
||||||
* irrelevant.
|
* irrelevant.
|
||||||
*/
|
*/
|
||||||
|
#if defined(CONFIG_USE_SWITCH)
|
||||||
|
extern void z_arm_cortex_ar_exit_exc(void);
|
||||||
|
thread->switch_handle = thread;
|
||||||
|
/* thread birth happens through the exception return path */
|
||||||
|
thread->arch.exception_depth = 1;
|
||||||
|
thread->callee_saved.lr = (uint32_t)z_arm_cortex_ar_exit_exc;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(CONFIG_MPU_STACK_GUARD) && defined(CONFIG_FPU) \
|
#if defined(CONFIG_MPU_STACK_GUARD) && defined(CONFIG_FPU) \
|
||||||
|
|
|
@ -13,6 +13,8 @@
|
||||||
#include <zephyr/toolchain.h>
|
#include <zephyr/toolchain.h>
|
||||||
#include <zephyr/linker/sections.h>
|
#include <zephyr/linker/sections.h>
|
||||||
#include "vector_table.h"
|
#include "vector_table.h"
|
||||||
|
#include "offsets_short.h"
|
||||||
|
#include "macro_priv.inc"
|
||||||
|
|
||||||
_ASM_FILE_PROLOGUE
|
_ASM_FILE_PROLOGUE
|
||||||
|
|
||||||
|
@ -28,4 +30,28 @@ SECTION_SUBSEC_FUNC(exc_vector_table,_vector_table_section,_vector_table)
|
||||||
#else
|
#else
|
||||||
ldr pc, =z_irq_spurious
|
ldr pc, =z_irq_spurious
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef CONFIG_USE_SWITCH
|
||||||
ldr pc, =z_arm_nmi /* FIQ offset 0x1c */
|
ldr pc, =z_arm_nmi /* FIQ offset 0x1c */
|
||||||
|
#else
|
||||||
|
ldr pc,=z_irq_spurious
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef CONFIG_USE_SWITCH
|
||||||
|
GTEXT(z_arm_cortex_ar_exit_exc)
|
||||||
|
SECTION_SUBSEC_FUNC(TEXT, _HandlerModeExit, z_arm_cortex_ar_exit_exc)
|
||||||
|
|
||||||
|
/* decrement exception depth */
|
||||||
|
get_cpu r2
|
||||||
|
ldrb r1, [r2, #_cpu_offset_to_exc_depth]
|
||||||
|
sub r1, r1, #1
|
||||||
|
strb r1, [r2, #_cpu_offset_to_exc_depth]
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Restore r0-r3, r12, lr, lr_und and spsr_und from the exception stack
|
||||||
|
* and return to the current thread.
|
||||||
|
*/
|
||||||
|
ldmia sp, {r0-r3, r12, lr}^
|
||||||
|
add sp, #24
|
||||||
|
rfeia sp!
|
||||||
|
#endif
|
||||||
|
|
|
@ -32,6 +32,11 @@
|
||||||
GEN_OFFSET_SYM(_thread_arch_t, basepri);
|
GEN_OFFSET_SYM(_thread_arch_t, basepri);
|
||||||
GEN_OFFSET_SYM(_thread_arch_t, swap_return_value);
|
GEN_OFFSET_SYM(_thread_arch_t, swap_return_value);
|
||||||
|
|
||||||
|
#if defined(CONFIG_CPU_AARCH32_CORTEX_A) || defined(CONFIG_CPU_AARCH32_CORTEX_R)
|
||||||
|
GEN_OFFSET_SYM(_thread_arch_t, exception_depth);
|
||||||
|
GEN_OFFSET_SYM(_cpu_arch_t, exc_depth);
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(CONFIG_ARM_STORE_EXC_RETURN) || defined(CONFIG_USERSPACE)
|
#if defined(CONFIG_ARM_STORE_EXC_RETURN) || defined(CONFIG_USERSPACE)
|
||||||
GEN_OFFSET_SYM(_thread_arch_t, mode);
|
GEN_OFFSET_SYM(_thread_arch_t, mode);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -40,7 +40,7 @@ static ALWAYS_INLINE bool arch_is_in_isr(void)
|
||||||
|
|
||||||
static ALWAYS_INLINE bool arch_is_in_nested_exception(const z_arch_esf_t *esf)
|
static ALWAYS_INLINE bool arch_is_in_nested_exception(const z_arch_esf_t *esf)
|
||||||
{
|
{
|
||||||
return (arch_curr_cpu()->nested > 1U) ? (true) : (false);
|
return (arch_curr_cpu()->arch.exc_depth > 1U) ? (true) : (false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(CONFIG_USERSPACE)
|
#if defined(CONFIG_USERSPACE)
|
||||||
|
@ -54,7 +54,9 @@ static ALWAYS_INLINE bool z_arm_preempted_thread_in_user_mode(const z_arch_esf_t
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef CONFIG_USE_SWITCH
|
||||||
extern void z_arm_cortex_r_svc(void);
|
extern void z_arm_cortex_r_svc(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,12 +30,30 @@ static ALWAYS_INLINE void arch_kernel_init(void)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef CONFIG_USE_SWITCH
|
||||||
|
|
||||||
static ALWAYS_INLINE void
|
static ALWAYS_INLINE void
|
||||||
arch_thread_return_value_set(struct k_thread *thread, unsigned int value)
|
arch_thread_return_value_set(struct k_thread *thread, unsigned int value)
|
||||||
{
|
{
|
||||||
thread->arch.swap_return_value = value;
|
thread->arch.swap_return_value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static ALWAYS_INLINE void arch_switch(void *switch_to, void **switched_from)
|
||||||
|
{
|
||||||
|
extern void z_arm_context_switch(struct k_thread *new,
|
||||||
|
struct k_thread *old);
|
||||||
|
|
||||||
|
struct k_thread *new = switch_to;
|
||||||
|
struct k_thread *old = CONTAINER_OF(switched_from, struct k_thread,
|
||||||
|
switch_handle);
|
||||||
|
|
||||||
|
z_arm_context_switch(new, old);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
extern FUNC_NORETURN void z_arm_userspace_enter(k_thread_entry_t user_entry,
|
extern FUNC_NORETURN void z_arm_userspace_enter(k_thread_entry_t user_entry,
|
||||||
void *p1, void *p2, void *p3,
|
void *p1, void *p2, void *p3,
|
||||||
uint32_t stack_end,
|
uint32_t stack_end,
|
||||||
|
|
|
@ -23,6 +23,14 @@
|
||||||
#define _thread_offset_to_preempt_float \
|
#define _thread_offset_to_preempt_float \
|
||||||
(___thread_t_arch_OFFSET + ___thread_arch_t_preempt_float_OFFSET)
|
(___thread_t_arch_OFFSET + ___thread_arch_t_preempt_float_OFFSET)
|
||||||
|
|
||||||
|
#if defined(CONFIG_CPU_AARCH32_CORTEX_A) || defined(CONFIG_CPU_AARCH32_CORTEX_R)
|
||||||
|
#define _thread_offset_to_exception_depth \
|
||||||
|
(___thread_t_arch_OFFSET + ___thread_arch_t_exception_depth_OFFSET)
|
||||||
|
|
||||||
|
#define _cpu_offset_to_exc_depth \
|
||||||
|
(___cpu_t_arch_OFFSET + ___cpu_arch_t_exc_depth_OFFSET)
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(CONFIG_USERSPACE) || defined(CONFIG_FPU_SHARING)
|
#if defined(CONFIG_USERSPACE) || defined(CONFIG_FPU_SHARING)
|
||||||
#define _thread_offset_to_mode \
|
#define _thread_offset_to_mode \
|
||||||
(___thread_t_arch_OFFSET + ___thread_arch_t_mode_OFFSET)
|
(___thread_t_arch_OFFSET + ___thread_arch_t_mode_OFFSET)
|
||||||
|
|
33
include/zephyr/arch/arm/structs.h
Normal file
33
include/zephyr/arch/arm/structs.h
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 Arm Limited (or its affiliates). All rights reserved.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ZEPHYR_INCLUDE_ARM_STRUCTS_H_
|
||||||
|
#define ZEPHYR_INCLUDE_ARM_STRUCTS_H_
|
||||||
|
|
||||||
|
#include <zephyr/types.h>
|
||||||
|
|
||||||
|
#if defined(CONFIG_CPU_AARCH32_CORTEX_A) || defined(CONFIG_CPU_AARCH32_CORTEX_R)
|
||||||
|
/* Per CPU architecture specifics */
|
||||||
|
struct _cpu_arch {
|
||||||
|
int8_t exc_depth;
|
||||||
|
};
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
/* Default definitions when no architecture specific definitions exist. */
|
||||||
|
|
||||||
|
/* Per CPU architecture specifics (empty) */
|
||||||
|
struct _cpu_arch {
|
||||||
|
#ifdef __cplusplus
|
||||||
|
/* This struct will have a size 0 in C which is not allowed in C++ (it'll have a size 1). To
|
||||||
|
* prevent this, we add a 1 byte dummy variable.
|
||||||
|
*/
|
||||||
|
uint8_t dummy;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* ZEPHYR_INCLUDE_ARM_STRUCTS_H_ */
|
|
@ -32,6 +32,9 @@ struct _callee_saved {
|
||||||
uint32_t v7; /* r10 */
|
uint32_t v7; /* r10 */
|
||||||
uint32_t v8; /* r11 */
|
uint32_t v8; /* r11 */
|
||||||
uint32_t psp; /* r13 */
|
uint32_t psp; /* r13 */
|
||||||
|
#ifdef CONFIG_USE_SWITCH
|
||||||
|
uint32_t lr; /* lr */
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct _callee_saved _callee_saved_t;
|
typedef struct _callee_saved _callee_saved_t;
|
||||||
|
@ -74,6 +77,10 @@ struct _thread_arch {
|
||||||
struct _preempt_float preempt_float;
|
struct _preempt_float preempt_float;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(CONFIG_CPU_AARCH32_CORTEX_A) || defined(CONFIG_CPU_AARCH32_CORTEX_R)
|
||||||
|
int8_t exception_depth;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(CONFIG_ARM_STORE_EXC_RETURN) || defined(CONFIG_USERSPACE)
|
#if defined(CONFIG_ARM_STORE_EXC_RETURN) || defined(CONFIG_USERSPACE)
|
||||||
/*
|
/*
|
||||||
* Status variable holding several thread status flags
|
* Status variable holding several thread status flags
|
||||||
|
|
|
@ -27,6 +27,8 @@
|
||||||
#include <zephyr/arch/arm64/structs.h>
|
#include <zephyr/arch/arm64/structs.h>
|
||||||
#elif defined(CONFIG_RISCV)
|
#elif defined(CONFIG_RISCV)
|
||||||
#include <zephyr/arch/riscv/structs.h>
|
#include <zephyr/arch/riscv/structs.h>
|
||||||
|
#elif defined(CONFIG_ARM)
|
||||||
|
#include <zephyr/arch/arm/structs.h>
|
||||||
#else
|
#else
|
||||||
|
|
||||||
/* Default definitions when no architecture specific definitions exist. */
|
/* Default definitions when no architecture specific definitions exist. */
|
||||||
|
|
|
@ -10,7 +10,7 @@ config SOC_FVP_AEMV8R_AARCH32
|
||||||
select CPU_CORTEX_R52
|
select CPU_CORTEX_R52
|
||||||
select CPU_HAS_ARM_MPU
|
select CPU_HAS_ARM_MPU
|
||||||
select CPU_HAS_MPU
|
select CPU_HAS_MPU
|
||||||
select VFP_DP_D32_FP16_FMAC
|
select VFP_DP_D32_FP16_FMAC if !USE_SWITCH
|
||||||
select GIC_V3
|
select GIC_V3
|
||||||
select GIC_SINGLE_SECURITY_STATE
|
select GIC_SINGLE_SECURITY_STATE
|
||||||
select PLATFORM_SPECIFIC_INIT
|
select PLATFORM_SPECIFIC_INIT
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue