This commit refactors kernel and arch headers to establish a boundary between private and public interface headers. The refactoring strategy used in this commit is detailed in the issue This commit introduces the following major changes: 1. Establish a clear boundary between private and public headers by removing "kernel/include" and "arch/*/include" from the global include paths. Ideally, only kernel/ and arch/*/ source files should reference the headers in these directories. If these headers must be used by a component, these include paths shall be manually added to the CMakeLists.txt file of the component. This is intended to discourage applications from including private kernel and arch headers either knowingly and unknowingly. - kernel/include/ (PRIVATE) This directory contains the private headers that provide private kernel definitions which should not be visible outside the kernel and arch source code. All public kernel definitions must be added to an appropriate header located under include/. - arch/*/include/ (PRIVATE) This directory contains the private headers that provide private architecture-specific definitions which should not be visible outside the arch and kernel source code. All public architecture- specific definitions must be added to an appropriate header located under include/arch/*/. - include/ AND include/sys/ (PUBLIC) This directory contains the public headers that provide public kernel definitions which can be referenced by both kernel and application code. - include/arch/*/ (PUBLIC) This directory contains the public headers that provide public architecture-specific definitions which can be referenced by both kernel and application code. 2. Split arch_interface.h into "kernel-to-arch interface" and "public arch interface" divisions. - kernel/include/kernel_arch_interface.h * provides private "kernel-to-arch interface" definition. * includes arch/*/include/kernel_arch_func.h to ensure that the interface function implementations are always available. * includes sys/arch_interface.h so that public arch interface definitions are automatically included when including this file. - arch/*/include/kernel_arch_func.h * provides architecture-specific "kernel-to-arch interface" implementation. * only the functions that will be used in kernel and arch source files are defined here. - include/sys/arch_interface.h * provides "public arch interface" definition. * includes include/arch/arch_inlines.h to ensure that the architecture-specific public inline interface function implementations are always available. - include/arch/arch_inlines.h * includes architecture-specific arch_inlines.h in include/arch/*/arch_inline.h. - include/arch/*/arch_inline.h * provides architecture-specific "public arch interface" inline function implementation. * supersedes include/sys/arch_inline.h. 3. Refactor kernel and the existing architecture implementations. - Remove circular dependency of kernel and arch headers. The following general rules should be observed: * Never include any private headers from public headers * Never include kernel_internal.h in kernel_arch_data.h * Always include kernel_arch_data.h from kernel_arch_func.h * Never include kernel.h from kernel_struct.h either directly or indirectly. Only add the kernel structures that must be referenced from public arch headers in this file. - Relocate syscall_handler.h to include/ so it can be used in the public code. This is necessary because many user-mode public codes reference the functions defined in this header. - Relocate kernel_arch_thread.h to include/arch/*/thread.h. This is necessary to provide architecture-specific thread definition for 'struct k_thread' in kernel.h. - Remove any private header dependencies from public headers using the following methods: * If dependency is not required, simply omit * If dependency is required, - Relocate a portion of the required dependencies from the private header to an appropriate public header OR - Relocate the required private header to make it public. This commit supersedes #20047, addresses #19666, and fixes #3056. Signed-off-by: Stephanos Ioannidis <root@stephanos.io>
227 lines
6.5 KiB
ArmAsm
227 lines
6.5 KiB
ArmAsm
/*
|
|
* Copyright (c) 2016 Intel Corporation
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <toolchain.h>
|
|
#include <linker/sections.h>
|
|
#include <offsets_short.h>
|
|
|
|
/* exports */
|
|
GTEXT(_exception)
|
|
|
|
/* import */
|
|
GTEXT(_Fault)
|
|
GTEXT(z_arch_swap)
|
|
#ifdef CONFIG_IRQ_OFFLOAD
|
|
GTEXT(z_irq_do_offload)
|
|
GTEXT(_offload_routine)
|
|
#endif
|
|
|
|
/* Allows use of r1/at register, otherwise reserved for assembler use */
|
|
.set noat
|
|
|
|
/* Placed into special 'exception' section so that the linker can put this code
|
|
* at ALT_CPU_EXCEPTION_ADDR defined in system.h
|
|
*
|
|
* This is the common entry point for processor exceptions and interrupts from
|
|
* the Internal Interrupt Controller (IIC).
|
|
*
|
|
* If the External (EIC) controller is in use, then we will never get here on
|
|
* behalf of an interrupt, instead the EIC driver will have set up a vector
|
|
* table and the processor will jump directly into the appropriate table
|
|
* entry.
|
|
*/
|
|
SECTION_FUNC(exception.entry, _exception)
|
|
/* Reserve thread stack space for saving context */
|
|
subi sp, sp, __z_arch_esf_t_SIZEOF
|
|
|
|
/* Preserve all caller-saved registers onto the thread's stack */
|
|
stw ra, __z_arch_esf_t_ra_OFFSET(sp)
|
|
stw r1, __z_arch_esf_t_r1_OFFSET(sp)
|
|
stw r2, __z_arch_esf_t_r2_OFFSET(sp)
|
|
stw r3, __z_arch_esf_t_r3_OFFSET(sp)
|
|
stw r4, __z_arch_esf_t_r4_OFFSET(sp)
|
|
stw r5, __z_arch_esf_t_r5_OFFSET(sp)
|
|
stw r6, __z_arch_esf_t_r6_OFFSET(sp)
|
|
stw r7, __z_arch_esf_t_r7_OFFSET(sp)
|
|
stw r8, __z_arch_esf_t_r8_OFFSET(sp)
|
|
stw r9, __z_arch_esf_t_r9_OFFSET(sp)
|
|
stw r10, __z_arch_esf_t_r10_OFFSET(sp)
|
|
stw r11, __z_arch_esf_t_r11_OFFSET(sp)
|
|
stw r12, __z_arch_esf_t_r12_OFFSET(sp)
|
|
stw r13, __z_arch_esf_t_r13_OFFSET(sp)
|
|
stw r14, __z_arch_esf_t_r14_OFFSET(sp)
|
|
stw r15, __z_arch_esf_t_r15_OFFSET(sp)
|
|
|
|
/* Store value of estatus control register */
|
|
rdctl et, estatus
|
|
stw et, __z_arch_esf_t_estatus_OFFSET(sp)
|
|
|
|
/* ea-4 is the address of the instruction when the exception happened,
|
|
* put this in the stack frame as well
|
|
*/
|
|
addi r15, ea, -4
|
|
stw r15, __z_arch_esf_t_instr_OFFSET(sp)
|
|
|
|
/* Figure out whether we are here because of an interrupt or an
|
|
* exception. If an interrupt, switch stacks and enter IRQ handling
|
|
* code. If an exception, remain on current stack and enter exception
|
|
* handing code. From the CPU manual, ipending must be nonzero and
|
|
* estatis.PIE must be enabled for this to be considered an interrupt.
|
|
*
|
|
* Stick ipending in r4 since it will be an arg for _enter_irq
|
|
*/
|
|
rdctl r4, ipending
|
|
beq r4, zero, not_interrupt
|
|
/* We stashed estatus in et earlier */
|
|
andi r15, et, 1
|
|
beq r15, zero, not_interrupt
|
|
|
|
is_interrupt:
|
|
/* If we get here, this is an interrupt */
|
|
|
|
/* Grab a reference to _kernel in r10 so we can determine the
|
|
* current irq stack pointer
|
|
*/
|
|
movhi r10, %hi(_kernel)
|
|
ori r10, r10, %lo(_kernel)
|
|
|
|
/* Stash a copy of thread's sp in r12 so that we can put it on the IRQ
|
|
* stack
|
|
*/
|
|
mov r12, sp
|
|
|
|
/* Switch to interrupt stack */
|
|
ldw sp, _kernel_offset_to_irq_stack(r10)
|
|
|
|
/* Store thread stack pointer onto IRQ stack */
|
|
addi sp, sp, -4
|
|
stw r12, 0(sp)
|
|
|
|
on_irq_stack:
|
|
|
|
/* Enter C interrupt handling code. Value of ipending will be the
|
|
* function parameter since we put it in r4
|
|
*/
|
|
call _enter_irq
|
|
|
|
/* Interrupt handler finished and the interrupt should be serviced
|
|
* now, the appropriate bits in ipending should be cleared */
|
|
|
|
/* Get a reference to _kernel again in r10 */
|
|
movhi r10, %hi(_kernel)
|
|
ori r10, r10, %lo(_kernel)
|
|
|
|
#ifdef CONFIG_PREEMPT_ENABLED
|
|
ldw r11, _kernel_offset_to_current(r10)
|
|
/* Determine whether the exception of the ISR requires context
|
|
* switch
|
|
*/
|
|
|
|
/* Call into the kernel to see if a scheduling decision is necessary */
|
|
ldw r2, _kernel_offset_to_ready_q_cache(r10)
|
|
beq r2, r11, no_reschedule
|
|
|
|
/*
|
|
* A context reschedule is required: keep the volatile registers of
|
|
* the interrupted thread on the context's stack. Utilize
|
|
* the existing z_arch_swap() primitive to save the remaining
|
|
* thread's registers (including floating point) and perform
|
|
* a switch to the new thread.
|
|
*/
|
|
|
|
/* We put the thread stack pointer on top of the IRQ stack before
|
|
* we switched stacks. Restore it to go back to thread stack
|
|
*/
|
|
ldw sp, 0(sp)
|
|
|
|
/* Argument to Swap() is estatus since that's the state of the
|
|
* status register before the exception happened. When coming
|
|
* out of the context switch we need this info to restore
|
|
* IRQ lock state. We put this value in et earlier.
|
|
*/
|
|
mov r4, et
|
|
|
|
call z_arch_swap
|
|
jmpi _exception_exit
|
|
#else
|
|
jmpi no_reschedule
|
|
#endif /* CONFIG_PREEMPT_ENABLED */
|
|
|
|
not_interrupt:
|
|
|
|
/* Since this wasn't an interrupt we're not going to restart the
|
|
* faulting instruction.
|
|
*
|
|
* We earlier put ea - 4 in the stack frame, replace it with just ea
|
|
*/
|
|
stw ea, __z_arch_esf_t_instr_OFFSET(sp)
|
|
|
|
#ifdef CONFIG_IRQ_OFFLOAD
|
|
/* Check the contents of _offload_routine. If non-NULL, jump into
|
|
* the interrupt code anyway.
|
|
*/
|
|
movhi r10, %hi(_offload_routine)
|
|
ori r10, r10, %lo(_offload_routine)
|
|
ldw r11, (r10)
|
|
bne r11, zero, is_interrupt
|
|
#endif
|
|
|
|
_exception_enter_fault:
|
|
/* If we get here, the exception wasn't in interrupt or an
|
|
* invocation of irq_oflload(). Let _Fault() handle it in
|
|
* C domain
|
|
*/
|
|
|
|
mov r4, sp
|
|
call _Fault
|
|
jmpi _exception_exit
|
|
|
|
no_reschedule:
|
|
|
|
/* We put the thread stack pointer on top of the IRQ stack before
|
|
* we switched stacks. Restore it to go back to thread stack
|
|
*/
|
|
ldw sp, 0(sp)
|
|
|
|
/* Fall through */
|
|
|
|
_exception_exit:
|
|
/* We are on the thread stack. Restore all saved registers
|
|
* and return to the interrupted context */
|
|
|
|
/* Return address from the exception */
|
|
ldw ea, __z_arch_esf_t_instr_OFFSET(sp)
|
|
|
|
/* Restore estatus
|
|
* XXX is this right??? */
|
|
ldw r5, __z_arch_esf_t_estatus_OFFSET(sp)
|
|
wrctl estatus, r5
|
|
|
|
/* Restore caller-saved registers */
|
|
ldw ra, __z_arch_esf_t_ra_OFFSET(sp)
|
|
ldw r1, __z_arch_esf_t_r1_OFFSET(sp)
|
|
ldw r2, __z_arch_esf_t_r2_OFFSET(sp)
|
|
ldw r3, __z_arch_esf_t_r3_OFFSET(sp)
|
|
ldw r4, __z_arch_esf_t_r4_OFFSET(sp)
|
|
ldw r5, __z_arch_esf_t_r5_OFFSET(sp)
|
|
ldw r6, __z_arch_esf_t_r6_OFFSET(sp)
|
|
ldw r7, __z_arch_esf_t_r7_OFFSET(sp)
|
|
ldw r8, __z_arch_esf_t_r8_OFFSET(sp)
|
|
ldw r9, __z_arch_esf_t_r9_OFFSET(sp)
|
|
ldw r10, __z_arch_esf_t_r10_OFFSET(sp)
|
|
ldw r11, __z_arch_esf_t_r11_OFFSET(sp)
|
|
ldw r12, __z_arch_esf_t_r12_OFFSET(sp)
|
|
ldw r13, __z_arch_esf_t_r13_OFFSET(sp)
|
|
ldw r14, __z_arch_esf_t_r14_OFFSET(sp)
|
|
ldw r15, __z_arch_esf_t_r15_OFFSET(sp)
|
|
|
|
/* Put the stack pointer back where it was when we entered
|
|
* exception state
|
|
*/
|
|
addi sp, sp, __z_arch_esf_t_SIZEOF
|
|
|
|
/* All done, copy estatus into status and transfer to ea */
|
|
eret
|