diff --git a/arch/Kconfig b/arch/Kconfig index 7f785d3ab81..274d5bdafc5 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -37,6 +37,17 @@ config ARM help ARM architecture +config SPARC + bool + select ARCH_IS_SET + select USE_SWITCH + select USE_SWITCH_SUPPORTED + select BIG_ENDIAN + select ATOMIC_OPERATIONS_BUILTIN if SPARC_CASA + select ATOMIC_OPERATIONS_C if !SPARC_CASA + help + SPARC architecture + config X86 bool select ARCH_IS_SET diff --git a/arch/sparc/CMakeLists.txt b/arch/sparc/CMakeLists.txt new file mode 100644 index 00000000000..a14cb31af44 --- /dev/null +++ b/arch/sparc/CMakeLists.txt @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: Apache-2.0 + +set_property(GLOBAL PROPERTY PROPERTY_OUTPUT_FORMAT "elf32-sparc") +add_subdirectory(core) diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig new file mode 100644 index 00000000000..b2042165425 --- /dev/null +++ b/arch/sparc/Kconfig @@ -0,0 +1,67 @@ +# Copyright (c) 2019-2020 Cobham Gaisler AB +# SPDX-License-Identifier: Apache-2.0 + +menu "SPARC Options" + depends on SPARC + +config ARCH + default "sparc" + +config SPARC_NWIN + int "Number of register windows" + default 8 + help + Number of implemented register windows. + +config GEN_ISR_TABLES + default y + +config GEN_IRQ_VECTOR_TABLE + default n + +config GEN_SW_ISR_TABLE + default y + +config NUM_IRQS + int + default 32 + +config SPARC_CASA + bool "CASA instructions" + help + Use CASA atomic instructions. Defined by SPARC V9 and available + in some LEON processors. + +# The SPARC V8 ABI allocates a stack frame of minimum 96 byte for each SAVE +# instruction so we bump the kernel default values. +config MAIN_STACK_SIZE + default 4096 if COVERAGE_GCOV + default 2048 + +config IDLE_STACK_SIZE + default 1024 + +config ISR_STACK_SIZE + default 4096 + +config TEST_EXTRA_STACKSIZE + default 4096 if COVERAGE_GCOV + default 2048 + +config SYSTEM_WORKQUEUE_STACK_SIZE + default 4096 + +config CMSIS_THREAD_MAX_STACK_SIZE + default 2048 + +config CMSIS_V2_THREAD_MAX_STACK_SIZE + default 2048 + +config CMSIS_V2_THREAD_DYNAMIC_STACK_SIZE + default 2048 + +config IPM_CONSOLE_STACK_SIZE + default 4096 if COVERAGE + default 1024 + +endmenu diff --git a/arch/sparc/core/CMakeLists.txt b/arch/sparc/core/CMakeLists.txt new file mode 100644 index 00000000000..28b5559d3ab --- /dev/null +++ b/arch/sparc/core/CMakeLists.txt @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_sources( + fatal.c + reset_trap.S + prep_c.c + switch.S + interrupt_trap.S + fault_trap.S + irq_manage.c + thread.c + window_trap.S + sw_trap_set_pil.S + trap_table_mvt.S +) + +zephyr_library_sources_ifdef(CONFIG_IRQ_OFFLOAD irq_offload.c) diff --git a/arch/sparc/core/fatal.c b/arch/sparc/core/fatal.c new file mode 100644 index 00000000000..87a81a8edb5 --- /dev/null +++ b/arch/sparc/core/fatal.c @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2019-2020 Cobham Gaisler AB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +LOG_MODULE_DECLARE(os); + +FUNC_NORETURN void z_sparc_fatal_error(unsigned int reason, + const z_arch_esf_t *esf) +{ + if (esf != NULL) { + LOG_ERR(" pc: %08x", esf->pc); + LOG_ERR("npc: %08x", esf->npc); + LOG_ERR("psr: %08x", esf->psr); + LOG_ERR("tbr: %08x", esf->tbr); + LOG_ERR(" sp: %08x", esf->sp); + LOG_ERR(" y: %08x", esf->y); + } + + z_fatal_error(reason, esf); + CODE_UNREACHABLE; +} + +FUNC_NORETURN void _Fault(const z_arch_esf_t *esf) +{ + LOG_ERR("Trap tt=0x%02x", (esf->tbr >> 4) & 0xff); + + z_sparc_fatal_error(K_ERR_CPU_EXCEPTION, esf); +} diff --git a/arch/sparc/core/fault_trap.S b/arch/sparc/core/fault_trap.S new file mode 100644 index 00000000000..e9ac058f0c4 --- /dev/null +++ b/arch/sparc/core/fault_trap.S @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2019-2020 Cobham Gaisler AB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +GTEXT(__sparc_trap_fault) + +/* + * Fault trap handler + * + * - IU state is saved and restored + * + * On entry: + * %l0: psr (set by trap code) + * %l1: pc + * %l2: npc + * %l6: tbr (set by trap code) + * %fp: %sp of current register window at trap time + * + * This trap handler will trash some of the global registers, which is OK since + * we will not return to where we trapped. + */ +SECTION_FUNC(TEXT, __sparc_trap_fault) + /* We may have trapped into the invalid window. If so, make it valid. */ + rd %wim, %g2 + srl %g2, %l0, %g3 + cmp %g3, 1 + bne .Lwodone + nop + + /* Do the window overflow. */ + sll %g2, (CONFIG_SPARC_NWIN-1), %g3 + srl %g2, 1, %g2 + or %g2, %g3, %g2 + + /* Enter window to save. */ + save + /* Install new wim calculated above. */ + mov %g2, %wim + nop + nop + nop + /* Put registers on the dedicated save area of the ABI stack frame. */ + std %l0, [%sp + 0x00] + std %l2, [%sp + 0x08] + std %l4, [%sp + 0x10] + std %l6, [%sp + 0x18] + std %i0, [%sp + 0x20] + std %i2, [%sp + 0x28] + std %i4, [%sp + 0x30] + std %i6, [%sp + 0x38] + /* Leave saved window. */ + restore + +.Lwodone: + /* Allocate an ABI stack frame and exception stack frame */ + sub %fp, 96 + __z_arch_esf_t_SIZEOF, %sp + /* + * %fp: %sp of interrupted task + * %sp: %sp of interrupted task - ABI_frame - esf + */ + + /* Fill in the content of the exception stack frame */ + st %l1, [%sp + 96 + __z_arch_esf_t_pc_OFFSET] + st %l2, [%sp + 96 + __z_arch_esf_t_npc_OFFSET] + st %l0, [%sp + 96 + __z_arch_esf_t_psr_OFFSET] + st %l6, [%sp + 96 + __z_arch_esf_t_tbr_OFFSET] + st %fp, [%sp + 96 + __z_arch_esf_t_sp_OFFSET] + rd %y, %g1 + st %g1, [%sp + 96 + __z_arch_esf_t_y_OFFSET] + + /* Enable traps, raise PIL to mask all maskable interrupts. */ + or %l0, PSR_PIL, %o0 + wr %o0, PSR_ET, %psr + nop + nop + nop + /* Exception stack frame prepared earlier is the first argument. */ + call _Fault + add %sp, 96, %o0 diff --git a/arch/sparc/core/interrupt_trap.S b/arch/sparc/core/interrupt_trap.S new file mode 100644 index 00000000000..4e7f48e9688 --- /dev/null +++ b/arch/sparc/core/interrupt_trap.S @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2019-2020 Cobham Gaisler AB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include "stack_offsets.h" + +GTEXT(__sparc_trap_interrupt) +GTEXT(__sparc_trap_irq_offload) + +/* + * Interrupt trap handler + * + * - IU state is saved and restored + * + * On entry: + * %l0: psr (set by trap code) + * %l1: pc + * %l2: npc + * %l3: SPARC interrupt request level (bp_IRL) + * %fp: %sp of current register window at trap time + * + * This module also implements the IRQ offload support. The handling is the + * same as for asynchronous maskable interrupts, with the following exceptions: + * - Do not re-execute the causing (ta) instruction at trap exit. + * - A dedicated interrupt request level (0x8d) is used. + * - z_sparc_enter_irq() knows how to interpret this interrupt request level. + */ +SECTION_SUBSEC_FUNC(TEXT, __sparc_trap_interrupt, __sparc_trap_irq_offload) + /* Preparation in the case of synchronous IRQ offload. */ + mov %l2, %l1 + add %l2, 4, %l2 + set 0x8d, %l3 + +__sparc_trap_interrupt: + /* %g2, %g3 are used at manual window overflow so save temporarily */ + mov %g2, %l4 + mov %g3, %l5 + + /* We may have trapped into the invalid window. If so, make it valid. */ + rd %wim, %g2 + srl %g2, %l0, %g3 + cmp %g3, 1 + bne .Lwodone + nop + + /* Do the window overflow. */ + sll %g2, (CONFIG_SPARC_NWIN-1), %g3 + srl %g2, 1, %g2 + or %g2, %g3, %g2 + + /* Enter window to save. */ + save + /* Install new wim calculated above. */ + mov %g2, %wim + nop + nop + nop + /* Put registers on the dedicated save area of the ABI stack frame. */ + std %l0, [%sp + 0x00] + std %l2, [%sp + 0x08] + std %l4, [%sp + 0x10] + std %l6, [%sp + 0x18] + std %i0, [%sp + 0x20] + std %i2, [%sp + 0x28] + std %i4, [%sp + 0x30] + std %i6, [%sp + 0x38] + /* Leave saved window. */ + restore + +.Lwodone: + /* + * %l4: %g2 at trap time + * %l5: %g3 at trap time + * + * Save the state of the interrupted task including global registers on + * the task stack. + * + * IMPORTANT: Globals are saved here as well on the task stack, since a + * context switch might happen before the context of this interrupted + * task is restored. + */ + + /* Allocate stack for isr context including ABI frame. */ + sub %fp, ISF_SIZE, %sp + /* + * %fp: %sp of interrupted task + * %sp: %sp of interrupted task - ISF_SIZE. + * (fits a full ABI frame + what we store here) + * + * Save the interrupted context. + */ + std %l0, [%sp + ISF_PSR_OFFSET] /* psr pc */ + st %l2, [%sp + ISF_NPC_OFFSET] /* npc */ + st %g1, [%sp + ISF_G1_OFFSET] /* g1 */ + std %l4, [%sp + ISF_G2_OFFSET] /* g2 g3 */ + st %g4, [%sp + ISF_G4_OFFSET] /* g4 */ + std %i0, [%sp + ISF_I0_OFFSET] /* i0 i1 */ + std %i2, [%sp + ISF_I2_OFFSET] /* i2 i3 */ + std %i4, [%sp + ISF_I4_OFFSET] /* i4 i5 */ + std %i6, [%sp + ISF_I6_OFFSET] /* fp i7 */ + rd %y, %g1 + st %g1, [%sp + ISF_Y_OFFSET] /* y */ + + /* %l5: reference to _kernel */ + set _kernel, %l5 + /* Switch to interrupt stack. */ + mov %sp, %fp + ld [%l5 + _kernel_offset_to_irq_stack], %sp + + /* Allocate a full C stack frame */ + sub %sp, STACK_FRAME_SIZE, %sp + /* + * %fp: %sp of interrupted task - ISF_SIZE. + * %sp: irq stack - 96. An ABI frame + */ + + /* Enable traps, raise PIL to mask all maskable interrupts. */ + or %l0, PSR_PIL, %o0 + wr %o0, PSR_ET, %psr + nop + nop + nop + + /* SPARC interrupt request level is the first agrument */ + call z_sparc_enter_irq + mov %l3, %o0 + + /* + * Switch back to interrupted task stack + * %fp: %sp of interrupted task - ISF_SIZE. + * %sp: irq stack - 96. An ABI frame + */ + mov %fp, %sp + /* + * %fp: %sp of interrupted task - ISF_SIZE. + * %sp: %sp of interrupted task - ISF_SIZE. + */ + +#ifdef CONFIG_PREEMPT_ENABLED + sub %sp, (96+8), %sp + call z_arch_get_next_switch_handle + add %sp, 96, %o0 + /* we get old thread as "return value" on stack */ + ld [%sp + 96], %o1 + /* + * o0: new thread + * o1: old thread + */ + cmp %o0, %o1 + beq .Lno_reschedule + nop + call z_sparc_context_switch + nop +.Lno_reschedule: + add %sp, (96+8), %sp +#endif /* CONFIG_PREEMPT_ENABLED */ + + /* Restore the interrupted context. */ + ld [%sp + ISF_Y_OFFSET], %g1 + wr %g1, 0, %y + + ldd [%sp + ISF_PSR_OFFSET], %l0 /* psr, pc */ + ld [%sp + ISF_NPC_OFFSET], %l2 /* npc */ + /* NOTE: %g1 will be restored later */ + ldd [%sp + ISF_G2_OFFSET], %g2 + ld [%sp + ISF_G4_OFFSET], %g4 + ldd [%sp + ISF_I0_OFFSET], %i0 + ldd [%sp + ISF_I2_OFFSET], %i2 + ldd [%sp + ISF_I4_OFFSET], %i4 + ldd [%sp + ISF_I6_OFFSET], %i6 + /* %g1 is used to access the stack frame later */ + mov %sp, %g1 + + /* + * Install the PSR we got from the interrupt context. Current PSR.CWP + * is preserved. Keep PSR.ET=0 until we do "rett". + */ + rd %psr, %l3 + and %l3, PSR_CWP, %l3 + andn %l0, (PSR_CWP | PSR_ET), %l0 + or %l3, %l0, %l0 + mov %l0, %psr + nop + nop + nop + + /* Calculate %l6 := (cwp+1) % NWIN */ + rd %wim, %l3 + set (CONFIG_SPARC_NWIN), %l7 + add %l0, 1, %l6 + and %l6, PSR_CWP, %l6 + cmp %l6, %l7 + bge,a .Lwrapok + mov 0, %l6 + +.Lwrapok: + /* Determine if we must prepare the return window. */ + /* %l5 := %wim >> (cwp+1) */ + srl %l3, %l6, %l5 + /* %l5 is 1 if (cwp+1) is an invalid window */ + cmp %l5, 1 + bne .Lwudone + sub %l7, 1, %l7 /* %l7 := NWIN - 1 */ + + /* Do the window underflow. */ + sll %l3, 1, %l4 + srl %l3, %l7, %l5 + wr %l4, %l5, %wim + nop + nop + nop + + restore + ldd [%g1 + 0x00], %l0 + ldd [%g1 + 0x08], %l2 + ldd [%g1 + 0x10], %l4 + ldd [%g1 + 0x18], %l6 + ldd [%g1 + 0x20], %i0 + ldd [%g1 + 0x28], %i2 + ldd [%g1 + 0x30], %i4 + ldd [%g1 + 0x38], %i6 + save + +.Lwudone: + /* + * Restore %psr since we may have trashed condition codes. PSR.ET is + * still 0. + */ + wr %l0, %psr + nop + nop + nop + + /* restore g1 */ + ld [%g1 + ISF_G1_OFFSET], %g1 + + jmp %l1 + rett %l2 diff --git a/arch/sparc/core/irq_manage.c b/arch/sparc/core/irq_manage.c new file mode 100644 index 00000000000..28c73faf18e --- /dev/null +++ b/arch/sparc/core/irq_manage.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2019-2020 Cobham Gaisler AB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +LOG_MODULE_DECLARE(os); + +FUNC_NORETURN void z_irq_spurious(const void *unused) +{ + uint32_t tbr; + + ARG_UNUSED(unused); + + __asm__ volatile ( + "rd %%tbr, %0" : + "=r" (tbr) + ); + LOG_ERR("Spurious interrupt detected! IRQ: %d", (tbr >> 4) & 0xf); + z_sparc_fatal_error(K_ERR_SPURIOUS_IRQ, NULL); +} + +void z_sparc_enter_irq(uint32_t irl) +{ + struct _isr_table_entry *ite; + + _current_cpu->nested++; + +#ifdef CONFIG_IRQ_OFFLOAD + if (irl != 141) { + irl = z_sparc_int_get_source(irl); + ite = &_sw_isr_table[irl]; + ite->isr(ite->arg); + } else { + z_irq_do_offload(); + } +#else + /* Get the actual interrupt source from the interrupt controller */ + irl = z_sparc_int_get_source(irl); + ite = &_sw_isr_table[irl]; + ite->isr(ite->arg); +#endif + + _current_cpu->nested--; +#ifdef CONFIG_STACK_SENTINEL + z_check_stack_sentinel(); +#endif +} diff --git a/arch/sparc/core/irq_offload.c b/arch/sparc/core/irq_offload.c new file mode 100644 index 00000000000..cd75963dec7 --- /dev/null +++ b/arch/sparc/core/irq_offload.c @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2019-2020 Cobham Gaisler AB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +volatile irq_offload_routine_t _offload_routine; +static volatile const void *offload_param; + +void z_irq_do_offload(void) +{ + irq_offload_routine_t tmp; + + if (!_offload_routine) { + return; + } + + tmp = _offload_routine; + _offload_routine = NULL; + + tmp((const void *)offload_param); +} + +void arch_irq_offload(irq_offload_routine_t routine, const void *parameter) +{ + unsigned int key; + + key = irq_lock(); + _offload_routine = routine; + offload_param = parameter; + + /* Generate irq offload trap */ + __asm__ volatile ("ta 13"); + + irq_unlock(key); +} diff --git a/arch/sparc/core/offsets/offsets.c b/arch/sparc/core/offsets/offsets.c new file mode 100644 index 00000000000..cb4e2a8a485 --- /dev/null +++ b/arch/sparc/core/offsets/offsets.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2019-2020 Cobham Gaisler AB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief SPARC kernel structure member offset definition file + * + * This module is responsible for the generation of the absolute symbols whose + * value represents the member offsets for various SPARC kernel structures. + */ + +#include +#include +#include +#include + +GEN_OFFSET_SYM(_callee_saved_t, y); +GEN_OFFSET_SYM(_callee_saved_t, psr); + +GEN_OFFSET_SYM(_callee_saved_t, l0_and_l1); +GEN_OFFSET_SYM(_callee_saved_t, l2); +GEN_OFFSET_SYM(_callee_saved_t, l3); +GEN_OFFSET_SYM(_callee_saved_t, l4); +GEN_OFFSET_SYM(_callee_saved_t, l5); +GEN_OFFSET_SYM(_callee_saved_t, l6); +GEN_OFFSET_SYM(_callee_saved_t, l7); +GEN_OFFSET_SYM(_callee_saved_t, i0); +GEN_OFFSET_SYM(_callee_saved_t, i1); +GEN_OFFSET_SYM(_callee_saved_t, i2); +GEN_OFFSET_SYM(_callee_saved_t, i3); +GEN_OFFSET_SYM(_callee_saved_t, i4); +GEN_OFFSET_SYM(_callee_saved_t, i5); +GEN_OFFSET_SYM(_callee_saved_t, i6); +GEN_OFFSET_SYM(_callee_saved_t, i7); +GEN_OFFSET_SYM(_callee_saved_t, o6); +GEN_OFFSET_SYM(_callee_saved_t, o7); + +/* esf member offsets */ +GEN_OFFSET_SYM(z_arch_esf_t, pc); +GEN_OFFSET_SYM(z_arch_esf_t, npc); +GEN_OFFSET_SYM(z_arch_esf_t, psr); +GEN_OFFSET_SYM(z_arch_esf_t, tbr); +GEN_OFFSET_SYM(z_arch_esf_t, sp); +GEN_OFFSET_SYM(z_arch_esf_t, y); +GEN_ABSOLUTE_SYM(__z_arch_esf_t_SIZEOF, STACK_ROUND_UP(sizeof(z_arch_esf_t))); + +/* + * size of the struct k_thread structure sans save area for floating + * point regs + */ +GEN_ABSOLUTE_SYM(_K_THREAD_NO_FLOAT_SIZEOF, sizeof(struct k_thread)); + +GEN_ABS_SYM_END diff --git a/arch/sparc/core/prep_c.c b/arch/sparc/core/prep_c.c new file mode 100644 index 00000000000..54c9eed513b --- /dev/null +++ b/arch/sparc/core/prep_c.c @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2019-2020 Cobham Gaisler AB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Full C support initialization + */ + +#include + +/** + * + * @brief Prepare to and run C code + * + * This routine prepares for the execution of and runs C code. + * + * @return N/A + */ + +void _PrepC(void) +{ +#ifdef CONFIG_XIP + z_data_copy(); +#endif + z_cstart(); + CODE_UNREACHABLE; +} diff --git a/arch/sparc/core/reset_trap.S b/arch/sparc/core/reset_trap.S new file mode 100644 index 00000000000..095a70357fd --- /dev/null +++ b/arch/sparc/core/reset_trap.S @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2019-2020 Cobham Gaisler AB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +/* The trap table reset entry jumps to here. */ + +GTEXT(__sparc_trap_reset) +SECTION_FUNC(TEXT, __sparc_trap_reset) + set __sparc_trap_table, %g1 + wr %g1, %tbr + wr %g0, 4, %wim + /* %psr := pil=0, et=0, cwp=1 */ + set (PSR_S | PSR_PS | 1), %g7 + wr %g7, %psr + nop + nop + nop + /* NOTE: wrpsr above may have changed the current register window. */ + + /* + * According to SPARC ABI, Chapter 3: The system marks the deepest + * stack frame by setting the frame pointer to zero. No other frame's + * %fp has a zero value. + */ + set z_interrupt_stacks, %o0 + set CONFIG_ISR_STACK_SIZE, %o2 + add %o0, %o2, %l2 + and %l2, 0xfffffff0, %l3 + sub %l3, 96, %sp + clr %fp + clr %i7 + +#ifdef CONFIG_INIT_STACKS + /* already have z_interrupt_stacks and CONFIG_ISR_STACK_SIZE in place */ + call memset + mov 0xaa, %o1 +#endif + + call z_bss_zero + nop + + /* Enable traps for the first time */ + /* %psr := pil=0, et=1, cwp=1 */ + wr %g7, PSR_ET, %psr + nop + nop + nop + + call _PrepC + nop + +/* We halt the system by generating a "trap in trap" condition. */ +GTEXT(arch_system_halt) +SECTION_FUNC(TEXT, arch_system_halt) + mov %o0, %g0 + mov %g1, %g0 + set 1, %g1 + ta 0x00 diff --git a/arch/sparc/core/stack_offsets.h b/arch/sparc/core/stack_offsets.h new file mode 100644 index 00000000000..953e56e11b3 --- /dev/null +++ b/arch/sparc/core/stack_offsets.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2019-2020 Cobham Gaisler AB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_ARCH_SPARC_CORE_STACK_H_ +#define ZEPHYR_ARCH_SPARC_CORE_STACK_H_ + +/* + * Offsets for SPARC ABI stack frame. + * + * Reference: System V Application Binary Interface, SPARC Processor + * Supplement, Third Edition, Page 3-35. + */ +#define STACK_FRAME_L0_OFFSET 0x00 +#define STACK_FRAME_L1_OFFSET 0x04 +#define STACK_FRAME_L2_OFFSET 0x08 +#define STACK_FRAME_L3_OFFSET 0x0c +#define STACK_FRAME_L4_OFFSET 0x10 +#define STACK_FRAME_L5_OFFSET 0x14 +#define STACK_FRAME_L6_OFFSET 0x18 +#define STACK_FRAME_L7_OFFSET 0x1c +#define STACK_FRAME_I0_OFFSET 0x20 +#define STACK_FRAME_I1_OFFSET 0x24 +#define STACK_FRAME_I2_OFFSET 0x28 +#define STACK_FRAME_I3_OFFSET 0x2c +#define STACK_FRAME_I4_OFFSET 0x30 +#define STACK_FRAME_I5_OFFSET 0x34 +#define STACK_FRAME_I6_OFFSET 0x38 +#define STACK_FRAME_I7_OFFSET 0x3c +#define STACK_FRAME_STRUCTURE_RETURN_ADDRESS_OFFSET 0x40 +#define STACK_FRAME_SAVED_ARG0_OFFSET 0x44 +#define STACK_FRAME_SAVED_ARG1_OFFSET 0x48 +#define STACK_FRAME_SAVED_ARG2_OFFSET 0x4c +#define STACK_FRAME_SAVED_ARG3_OFFSET 0x50 +#define STACK_FRAME_SAVED_ARG4_OFFSET 0x54 +#define STACK_FRAME_SAVED_ARG5_OFFSET 0x58 +#define STACK_FRAME_PAD0_OFFSET 0x5c +#define STACK_FRAME_SIZE 0x60 + + +/* Interrupt stack frame */ +#define ISF_PSR_OFFSET (STACK_FRAME_SIZE + 0x00) +#define ISF_PC_OFFSET (STACK_FRAME_SIZE + 0x04) +#define ISF_NPC_OFFSET (STACK_FRAME_SIZE + 0x08) +#define ISF_G1_OFFSET (STACK_FRAME_SIZE + 0x0c) +#define ISF_G2_OFFSET (STACK_FRAME_SIZE + 0x10) +#define ISF_G3_OFFSET (STACK_FRAME_SIZE + 0x14) +#define ISF_G4_OFFSET (STACK_FRAME_SIZE + 0x18) +#define ISF_G5_OFFSET (STACK_FRAME_SIZE + 0x1c) +#define ISF_G7_OFFSET (STACK_FRAME_SIZE + 0x24) +#define ISF_I0_OFFSET (STACK_FRAME_SIZE + 0x28) +#define ISF_I1_OFFSET (STACK_FRAME_SIZE + 0x2c) +#define ISF_I2_OFFSET (STACK_FRAME_SIZE + 0x30) +#define ISF_I3_OFFSET (STACK_FRAME_SIZE + 0x34) +#define ISF_I4_OFFSET (STACK_FRAME_SIZE + 0x38) +#define ISF_I5_OFFSET (STACK_FRAME_SIZE + 0x3c) +#define ISF_I6_OFFSET (STACK_FRAME_SIZE + 0x40) +#define ISF_I7_OFFSET (STACK_FRAME_SIZE + 0x44) +#define ISF_Y_OFFSET (STACK_FRAME_SIZE + 0x48) + +#define ISF_SIZE (STACK_FRAME_SIZE + 0x50) + +#endif /* ZEPHYR_ARCH_SPARC_CORE_STACK_H_ */ diff --git a/arch/sparc/core/sw_trap_set_pil.S b/arch/sparc/core/sw_trap_set_pil.S new file mode 100644 index 00000000000..08ecf751002 --- /dev/null +++ b/arch/sparc/core/sw_trap_set_pil.S @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2019-2020 Cobham Gaisler AB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +GTEXT(__sparc_trap_sw_set_pil) + +/* + * Set processor interrupt level + * + * Handler for SPARC trap 0x89: trap_instruction, defined as "Reserved for the + * operating system" by SPARC-ABI. + * + * entry: + * - %l0: psr + * - %l1: pc + * - %l2: npc + * - %i0: New processor interrupt level + * + * return: + * - %i0: Old processor interrupt level + */ +SECTION_FUNC(TEXT, __sparc_trap_sw_set_pil) + /* %l5: new %psr */ + sll %i0, PSR_PIL_BIT, %i0 + andn %l0, PSR_PIL, %l5 + or %l5, %i0, %l5 + + wr %l5, %psr + nop + nop + nop + + and %l0, PSR_PIL, %l3 + srl %l3, PSR_PIL_BIT, %i0 + + jmp %l2 + rett %l2 + 4 diff --git a/arch/sparc/core/switch.S b/arch/sparc/core/switch.S new file mode 100644 index 00000000000..17b12ce6c0c --- /dev/null +++ b/arch/sparc/core/switch.S @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2019-2020 Cobham Gaisler AB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +GTEXT(z_sparc_arch_switch) +GTEXT(z_sparc_context_switch) +GTEXT(z_thread_entry_wrapper) + +/* In this implementation, switch_handle is the thread itself. */ +SECTION_FUNC(TEXT, z_sparc_arch_switch) + ba z_sparc_context_switch + sub %o1, ___thread_t_switch_handle_OFFSET, %o1 + +/* + * This is a leaf function, so only out registers + * can be used without saving their context first. + * + * o0: new thread to restore + * o1: old thread to save + */ +SECTION_FUNC(TEXT, z_sparc_context_switch) + mov %y, %o4 + st %o4, [%o1 + _thread_offset_to_y] + std %l0, [%o1 + _thread_offset_to_l0_and_l1] + std %l2, [%o1 + _thread_offset_to_l2] + std %l4, [%o1 + _thread_offset_to_l4] + std %l6, [%o1 + _thread_offset_to_l6] + std %i0, [%o1 + _thread_offset_to_i0] + std %i2, [%o1 + _thread_offset_to_i2] + std %i4, [%o1 + _thread_offset_to_i4] + std %i6, [%o1 + _thread_offset_to_i6] + + std %o6, [%o1 + _thread_offset_to_o6] + + rd %psr, %o4 + st %o4, [%o1 + _thread_offset_to_psr] + + and %o4, PSR_CWP, %g3 /* %g3 = CWP */ + andn %o4, PSR_ET, %g1 /* %g1 = psr with traps disabled */ + wr %g1, %psr /* disable traps */ + nop + nop + nop + + rd %wim, %g2 /* %g2 = wim */ + mov 1, %g4 + sll %g4, %g3, %g4 /* %g4 = wim mask for CW invalid */ + +.Lsave_frame_loop: + sll %g4, 1, %g5 /* rotate wim left by 1 */ + srl %g4, (CONFIG_SPARC_NWIN-1), %g4 + or %g4, %g5, %g4 /* %g4 = wim if we do one restore */ + + /* if restore would not underflow, continue */ + andcc %g4, %g2, %g0 /* window to flush? */ + bnz .Ldone_flushing /* continue */ + nop + restore /* go one window back */ + + /* essentially the same as window overflow */ + /* sp still points to task stack */ + std %l0, [%sp + 0x00] + std %l2, [%sp + 0x08] + std %l4, [%sp + 0x10] + std %l6, [%sp + 0x18] + std %i0, [%sp + 0x20] + std %i2, [%sp + 0x28] + std %i4, [%sp + 0x30] + std %i6, [%sp + 0x38] + ba .Lsave_frame_loop + nop + +.Ldone_flushing: + /* + * "wrpsr" is a delayed write instruction so wait three instructions + * after the write before using non-global registers or instructions + * affecting the CWP. + */ + wr %g1, %psr /* restore cwp */ + nop + nop + nop + add %g3, 1, %g2 /* calculate desired wim */ + cmp %g2, (CONFIG_SPARC_NWIN-1) /* check if wim is in range */ + bg,a .Lwim_overflow + mov 0, %g2 + +.Lwim_overflow: + + mov 1, %g4 + sll %g4, %g2, %g4 /* %g4 = new wim */ + wr %g4, %wim + nop + nop + nop + + ldd [%o0 + _thread_offset_to_y], %o4 + mov %o4, %y + + /* restore local registers */ + ldd [%o0 + _thread_offset_to_l0_and_l1], %l0 + ldd [%o0 + _thread_offset_to_l2], %l2 + ldd [%o0 + _thread_offset_to_l4], %l4 + ldd [%o0 + _thread_offset_to_l6], %l6 + + /* restore input registers */ + ldd [%o0 + _thread_offset_to_i0], %i0 + ldd [%o0 + _thread_offset_to_i2], %i2 + ldd [%o0 + _thread_offset_to_i4], %i4 + ldd [%o0 + _thread_offset_to_i6], %i6 + + /* restore output registers */ + ldd [%o0 + _thread_offset_to_o6], %o6 + + ld [%o0 + _thread_offset_to_psr], %g1 /* %g1 = new thread psr */ + + andn %g1, PSR_CWP, %g1 /* psr without cwp */ + or %g1, %g3, %g1 /* psr with new cwp */ + wr %g1, %psr /* restore status register and ET */ + nop + nop + nop + + /* jump into thread */ + jmp %o7 + 8 + nop + +SECTION_FUNC(TEXT, z_thread_entry_wrapper) + mov %g0, %o7 + ld [%sp + 0x40], %o0 + ld [%sp + 0x44], %o1 + ld [%sp + 0x48], %o2 + ld [%sp + 0x4C], %o3 + call z_thread_entry + nop diff --git a/arch/sparc/core/thread.c b/arch/sparc/core/thread.c new file mode 100644 index 00000000000..a96356cb09a --- /dev/null +++ b/arch/sparc/core/thread.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2019-2020 Cobham Gaisler AB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +void z_thread_entry_wrapper(k_thread_entry_t thread, + void *arg1, + void *arg2, + void *arg3); + +/* + * Frame used by _thread_entry_wrapper + * + * Allocate a 16 register window save area at bottom of the stack. This is + * required if we need to taken a trap (interrupt) in the thread entry wrapper. + */ +struct init_stack_frame { + uint32_t window_save_area[16]; + k_thread_entry_t entry_point; + void *arg1; + void *arg2; + void *arg3; + uint32_t pad[8]; +}; + +void arch_new_thread(struct k_thread *thread, k_thread_stack_t *stack, + char *stack_ptr, k_thread_entry_t entry, + void *p1, void *p2, void *p3) +{ + struct init_stack_frame *iframe; + + /* Initial stack frame data, stored at base of the stack */ + iframe = Z_STACK_PTR_TO_FRAME(struct init_stack_frame, stack_ptr); + + iframe->entry_point = entry; + iframe->arg1 = p1; + iframe->arg2 = p2; + iframe->arg3 = p3; + + /* Put values for debugging purposes */ + thread->callee_saved.i6 = 0; /* frame pointer */ + thread->callee_saved.o6 = (uint32_t) iframe; /* stack pointer */ + thread->callee_saved.o7 = (uint32_t) z_thread_entry_wrapper - 8; + thread->callee_saved.psr = PSR_S | PSR_PS | PSR_ET; + + thread->switch_handle = thread; +} + +void *z_arch_get_next_switch_handle(struct k_thread **old_thread) +{ + *old_thread = _current; + + return z_get_next_switch_handle(*old_thread); +} diff --git a/arch/sparc/core/trap_table_mvt.S b/arch/sparc/core/trap_table_mvt.S new file mode 100644 index 00000000000..9e44caf8250 --- /dev/null +++ b/arch/sparc/core/trap_table_mvt.S @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2019-2020 Cobham Gaisler AB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * This file contains a full SPARC V8 trap table. The processor redirects + * exection to the trap table on trap events. Each trap table entrys is four + * instructions. + */ + +#include +#include + +#define BAD_TRAP \ + rd %psr, %l0; \ + sethi %hi(__sparc_trap_fault), %l4; \ + jmp %l4+%lo(__sparc_trap_fault); \ + rd %tbr, %l6; + +#define INTERRUPT_TRAP(level) \ + rd %psr, %l0; \ + sethi %hi(INT_HANDLER), %l4; \ + jmp %l4+%lo(INT_HANDLER); \ + mov (0xf & level), %l3; + +#define TRAP(handler) \ + rd %psr, %l0; \ + sethi %hi(handler), %l4; \ + jmp %l4+%lo(handler); \ + nop; + +#define RESET_TRAP(handler) \ + mov %g0, %g4; \ + sethi %hi(handler), %g4; \ + jmp %g4+%lo(handler); \ + nop; + +#define SOFT_TRAP \ + ta 0x00; \ + nop; \ + nop; \ + nop; + +#define WOF_TRAP TRAP(__sparc_trap_window_overflow) +#define WUF_TRAP TRAP(__sparc_trap_window_underflow) +#define FLW_TRAP BAD_TRAP +#define INT_HANDLER __sparc_trap_interrupt + +#ifdef CONFIG_IRQ_OFFLOAD + #define IRQ_OFFLOAD_TRAP TRAP(__sparc_trap_irq_offload) +#else + #define IRQ_OFFLOAD_TRAP BAD_TRAP +#endif + +GTEXT(__sparc_trap_table) +GTEXT(__start) + +SECTION_SUBSEC_FUNC(TEXT, traptable, __sparc_trap_table) +__start: + /* + * Values in the range 0 to 0x5F that are not assigned in SPARC V8 + * specification Table 7-1 are reserved for future versions of the + * architecture. + */ + RESET_TRAP(__sparc_trap_reset); ! 00 reset + BAD_TRAP; ! 01 instruction_access_exception + BAD_TRAP; ! 02 illegal_instruction + BAD_TRAP; ! 03 priveleged_instruction + BAD_TRAP; ! 04 fp_disabled + WOF_TRAP; ! 05 window_overflow + WUF_TRAP; ! 06 window_underflow + BAD_TRAP; ! 07 mem_address_not_aligned + BAD_TRAP; ! 08 fp_exception + BAD_TRAP; ! 09 data_access_exception + BAD_TRAP; ! 0A tag_overflow + BAD_TRAP; ! 0B watchpoint_detected + BAD_TRAP; ! 0C reserved + BAD_TRAP; ! 0D reserved + BAD_TRAP; ! 0E reserved + BAD_TRAP; ! 0F reserved + BAD_TRAP; ! 10 reserved + + /* Interrupt traps */ + INTERRUPT_TRAP(1); ! 11 interrupt_level_1 + INTERRUPT_TRAP(2); ! 12 interrupt_level_2 + INTERRUPT_TRAP(3); ! 13 interrupt_level_3 + INTERRUPT_TRAP(4); ! 14 interrupt_level_4 + INTERRUPT_TRAP(5); ! 15 interrupt_level_5 + INTERRUPT_TRAP(6); ! 16 interrupt_level_6 + INTERRUPT_TRAP(7); ! 17 interrupt_level_7 + INTERRUPT_TRAP(8); ! 18 interrupt_level_8 + INTERRUPT_TRAP(9); ! 19 interrupt_level_9 + INTERRUPT_TRAP(10); ! 1A interrupt_level_1 + INTERRUPT_TRAP(11); ! 1B interrupt_level_11 + INTERRUPT_TRAP(12); ! 1C interrupt_level_12 + INTERRUPT_TRAP(13); ! 1D interrupt_level_13 + INTERRUPT_TRAP(14); ! 1E interrupt_level_14 + INTERRUPT_TRAP(15); ! 1F interrupt_level_15 + BAD_TRAP; ! 20 r_register_access_error + BAD_TRAP; ! 21 instruction_access_error + BAD_TRAP; ! 22 reserved + BAD_TRAP; ! 23 reserved + BAD_TRAP; ! 24 cp_disabled + BAD_TRAP; ! 25 unimplemented_FLUSH + BAD_TRAP; ! 26 reserved + BAD_TRAP; ! 27 reserved + BAD_TRAP; ! 28 cp_exception + BAD_TRAP; ! 29 data_access_error + BAD_TRAP; ! 2A division_by_zero + BAD_TRAP; ! 2B data_store_error + BAD_TRAP; ! 2C data_access_MMU_miss + BAD_TRAP; ! 2D reserved + BAD_TRAP; ! 2E reserved + BAD_TRAP; ! 2F reserved + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 30 - 33 reserved + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 34 - 37 reserved + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 38 - 3B reserved + BAD_TRAP; ! 3C instruction_access_MMU_miss + BAD_TRAP; ! 3D reserved + BAD_TRAP; ! 3E reserved + BAD_TRAP; ! 3F reserved + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 40 - 43 undefined + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 44 - 47 undefined + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 48 - 4B undefined + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 4C - 4F undefined + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 50 - 53 undefined + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 54 - 57 undefined + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 58 - 5B undefined + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 5C - 5F undefined + + /* + * tt values 0x60 to 0x7F are reserved for implementation-dependent + * exceptions. + */ + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 60 - 63 undefined + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 64 - 67 undefined + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 68 - 6B undefined + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 6C - 6F undefined + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 70 - 73 undefined + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 74 - 77 undefined + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 78 - 7B undefined + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 7C - 7F undefined + + /* trap_instruction 0x80 - 0xFF */ + /* NOTE: "ta 5" can be generated by compiler. */ + SOFT_TRAP; ! 0 System calls + SOFT_TRAP; ! 1 Breakpoints + SOFT_TRAP; ! 2 Division by zero + FLW_TRAP; ! 3 Flush windows + SOFT_TRAP; ! 4 Clean windows + SOFT_TRAP; ! 5 Range checking + SOFT_TRAP; ! 6 Fix alignment + SOFT_TRAP; ! 7 Integer overflow + SOFT_TRAP ! 8 System calls + TRAP(__sparc_trap_sw_set_pil); ! 9 Reserved for the os + SOFT_TRAP; ! 10 Reserved for the os + SOFT_TRAP; ! 11 Reserved for the os + /* See SPARC-ABI for purpose of the following software traps */ + SOFT_TRAP; ! 12 + IRQ_OFFLOAD_TRAP; ! 13 + SOFT_TRAP; ! 14 + SOFT_TRAP; ! 15 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 90 - 93 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 94 - 97 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 98 - 9B + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 9C - 9F + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! A0 - A3 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! A4 - A7 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! A8 - AB + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! AC - AF + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! B0 - B3 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! B4 - B7 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! B8 - BB + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! BC - BF + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! C0 - C3 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! C4 - C7 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! C8 - CB + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! CC - CF + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! D0 - D3 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! D4 - D7 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! D8 - DB + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! DC - DF + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! E0 - E3 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! E4 - E7 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! E8 - EB + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! EC - EF + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! F0 - F3 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! F4 - F7 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! F8 - FB + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! FC - FF diff --git a/arch/sparc/core/window_trap.S b/arch/sparc/core/window_trap.S new file mode 100644 index 00000000000..a348340e669 --- /dev/null +++ b/arch/sparc/core/window_trap.S @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2019-2020 Cobham Gaisler AB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * This file contains standard handlers for the SPARC V8 window overflow and + * underflow traps. + */ + +#include +#include + +GTEXT(__sparc_trap_window_overflow) +GTEXT(__sparc_trap_window_underflow) + +SECTION_FUNC(TEXT, __sparc_trap_window_overflow) + /* Enter the window to be stored. */ + save + /* Save local register set. */ + std %l0, [%sp + 0x00] + std %l2, [%sp + 0x08] + std %l4, [%sp + 0x10] + rd %wim, %l3 + std %l6, [%sp + 0x18] + /* l2 := WIM << (NWIN-1) */ + sll %l3, (CONFIG_SPARC_NWIN-1), %l2 + /* Save input register set. */ + std %i0, [%sp + 0x20] + /* l3 := WIM >> 1 */ + srl %l3, 1, %l3 + std %i2, [%sp + 0x28] + /* WIM := (WIM >> 1) ^ (WIM << (NWIN-1)) */ + wr %l3, %l2, %wim + /* NOTE: 3 instruction before restore (delayed write instruction) */ + std %i4, [%sp + 0x30] + nop + std %i6, [%sp + 0x38] + /* Go back to trap window. */ + restore + /* Re-execute save. */ + jmp %l1 + rett %l2 + +SECTION_FUNC(TEXT, __sparc_trap_window_underflow) + rd %wim, %l3 + /* l4 := WIM << 1 */ + sll %l3, 1, %l4 + /* l5 := WIM >> (NWIN-1) */ + srl %l3, (CONFIG_SPARC_NWIN-1), %l5 + /* WIM := (WIM << 1) ^ (WIM >> (NWIN-1)) */ + wr %l4, %l5, %wim + /* WIM is implicitly read so nops are needed. */ + nop + nop + nop + + /* Enter the window to restore requires two restore instructions. */ + restore + restore + ldd [%sp + 0x00], %l0 + ldd [%sp + 0x08], %l2 + ldd [%sp + 0x10], %l4 + ldd [%sp + 0x18], %l6 + ldd [%sp + 0x20], %i0 + ldd [%sp + 0x28], %i2 + ldd [%sp + 0x30], %i4 + ldd [%sp + 0x38], %i6 + /* Go back to the trap window. */ + save + save + /* Re-execute restore. */ + jmp %l1 + rett %l2 diff --git a/arch/sparc/include/kernel_arch_data.h b/arch/sparc/include/kernel_arch_data.h new file mode 100644 index 00000000000..ff3dbfc6324 --- /dev/null +++ b/arch/sparc/include/kernel_arch_data.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2019-2020 Cobham Gaisler AB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Private kernel definitions + * + * This file contains private kernel structures definitions and various + * other definitions for the SPARC processor architecture. + */ + +#ifndef ZEPHYR_ARCH_SPARC_INCLUDE_KERNEL_ARCH_DATA_H_ +#define ZEPHYR_ARCH_SPARC_INCLUDE_KERNEL_ARCH_DATA_H_ + +#include +#include +#include + +#ifndef _ASMLANGUAGE +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _ASMLANGUAGE */ + +#endif /* ZEPHYR_ARCH_SPARC_INCLUDE_KERNEL_ARCH_DATA_H_ */ diff --git a/arch/sparc/include/kernel_arch_func.h b/arch/sparc/include/kernel_arch_func.h new file mode 100644 index 00000000000..889048e463a --- /dev/null +++ b/arch/sparc/include/kernel_arch_func.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2019-2020 Cobham Gaisler AB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Private kernel definitions + * + * This file contains private kernel function/macro definitions and various + * other definitions for the SPARC processor architecture. + */ + +#ifndef ZEPHYR_ARCH_SPARC_INCLUDE_KERNEL_ARCH_FUNC_H_ +#define ZEPHYR_ARCH_SPARC_INCLUDE_KERNEL_ARCH_FUNC_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _ASMLANGUAGE +static ALWAYS_INLINE void arch_kernel_init(void) +{ +} + +void z_sparc_arch_switch(void *switch_to, void **switched_from); + +static inline void arch_switch(void *switch_to, void **switched_from) +{ + z_sparc_arch_switch(switch_to, switched_from); +} + +FUNC_NORETURN void z_sparc_fatal_error(unsigned int reason, + const z_arch_esf_t *esf); + +static inline bool arch_is_in_isr(void) +{ + return _current_cpu->nested != 0U; +} + +#ifdef CONFIG_IRQ_OFFLOAD +void z_irq_do_offload(void); +#endif + +#endif /* _ASMLANGUAGE */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_ARCH_SPARC_INCLUDE_KERNEL_ARCH_FUNC_H_ */ diff --git a/arch/sparc/include/offsets_short_arch.h b/arch/sparc/include/offsets_short_arch.h new file mode 100644 index 00000000000..074f82ae71f --- /dev/null +++ b/arch/sparc/include/offsets_short_arch.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2019-2020 Cobham Gaisler AB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_ARCH_SPARC_INCLUDE_OFFSETS_SHORT_ARCH_H_ +#define ZEPHYR_ARCH_SPARC_INCLUDE_OFFSETS_SHORT_ARCH_H_ + +#include + +#define _thread_offset_to_y \ + (___thread_t_callee_saved_OFFSET + ___callee_saved_t_y_OFFSET) + +#define _thread_offset_to_l0_and_l1 \ + (___thread_t_callee_saved_OFFSET + ___callee_saved_t_l0_and_l1_OFFSET) + +#define _thread_offset_to_l2 \ + (___thread_t_callee_saved_OFFSET + ___callee_saved_t_l2_OFFSET) + +#define _thread_offset_to_l3 \ + (___thread_t_callee_saved_OFFSET + ___callee_saved_t_l3_OFFSET) + +#define _thread_offset_to_l4 \ + (___thread_t_callee_saved_OFFSET + ___callee_saved_t_l4_OFFSET) + +#define _thread_offset_to_l5 \ + (___thread_t_callee_saved_OFFSET + ___callee_saved_t_l5_OFFSET) + +#define _thread_offset_to_l6 \ + (___thread_t_callee_saved_OFFSET + ___callee_saved_t_l6_OFFSET) + +#define _thread_offset_to_l7 \ + (___thread_t_callee_saved_OFFSET + ___callee_saved_t_l7_OFFSET) + +#define _thread_offset_to_i0 \ + (___thread_t_callee_saved_OFFSET + ___callee_saved_t_i0_OFFSET) + +#define _thread_offset_to_i1 \ + (___thread_t_callee_saved_OFFSET + ___callee_saved_t_i1_OFFSET) + +#define _thread_offset_to_i2 \ + (___thread_t_callee_saved_OFFSET + ___callee_saved_t_i2_OFFSET) + +#define _thread_offset_to_i3 \ + (___thread_t_callee_saved_OFFSET + ___callee_saved_t_i3_OFFSET) + +#define _thread_offset_to_i4 \ + (___thread_t_callee_saved_OFFSET + ___callee_saved_t_i4_OFFSET) + +#define _thread_offset_to_i5 \ + (___thread_t_callee_saved_OFFSET + ___callee_saved_t_i5_OFFSET) + +#define _thread_offset_to_i6 \ + (___thread_t_callee_saved_OFFSET + ___callee_saved_t_i6_OFFSET) + +#define _thread_offset_to_i7 \ + (___thread_t_callee_saved_OFFSET + ___callee_saved_t_i7_OFFSET) + +#define _thread_offset_to_o6 \ + (___thread_t_callee_saved_OFFSET + ___callee_saved_t_o6_OFFSET) + +#define _thread_offset_to_o7 \ + (___thread_t_callee_saved_OFFSET + ___callee_saved_t_o7_OFFSET) + +#define _thread_offset_to_psr \ + (___thread_t_callee_saved_OFFSET + ___callee_saved_t_psr_OFFSET) + +#endif /* ZEPHYR_ARCH_SPARC_INCLUDE_OFFSETS_SHORT_ARCH_H_ */ diff --git a/include/arch/cpu.h b/include/arch/cpu.h index 35fb64cc288..0ff2e286d85 100644 --- a/include/arch/cpu.h +++ b/include/arch/cpu.h @@ -27,6 +27,8 @@ #include #elif defined(CONFIG_ARCH_POSIX) #include +#elif defined(CONFIG_SPARC) +#include #else #error "Unknown Architecture" #endif diff --git a/include/arch/sparc/arch.h b/include/arch/sparc/arch.h new file mode 100644 index 00000000000..da62981fec9 --- /dev/null +++ b/include/arch/sparc/arch.h @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2019-2020 Cobham Gaisler AB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief SPARC specific kernel interface header + * This header contains the SPARC specific kernel interface. It is + * included by the generic kernel interface header (arch/cpu.h) + */ + +#ifndef ZEPHYR_INCLUDE_ARCH_SPARC_ARCH_H_ +#define ZEPHYR_INCLUDE_ARCH_SPARC_ARCH_H_ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* stacks, for SPARC architecture stack shall be 8byte-aligned */ +#define ARCH_STACK_PTR_ALIGN 8 + +/* + * Software trap numbers. + * Assembly usage: "ta SPARC_SW_TRAP_" + */ +#define SPARC_SW_TRAP_FLUSH_WINDOWS 0x03 +#define SPARC_SW_TRAP_SET_PIL 0x09 + +#ifndef _ASMLANGUAGE +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define STACK_ROUND_UP(x) ROUND_UP(x, ARCH_STACK_PTR_ALIGN) + +/* + * SOC specific function to translate from processor interrupt request level + * (1..15) to logical interrupt source number. For example by probing the + * interrupt controller. + */ +int z_sparc_int_get_source(int irl); +void z_irq_spurious(const void *unused); + + +#define ARCH_IRQ_CONNECT(irq_p, priority_p, isr_p, isr_param_p, flags_p) \ + { \ + Z_ISR_DECLARE(irq_p, 0, isr_p, isr_param_p); \ + } + + +static ALWAYS_INLINE unsigned int z_sparc_set_pil_inline(unsigned int newpil) +{ + register uint32_t oldpil __asm__ ("o0") = newpil; + + __asm__ volatile ( + "ta %1\nnop\n" : + "=r" (oldpil) : + "i" (SPARC_SW_TRAP_SET_PIL), "r" (oldpil) + ); + return oldpil; +} + +static ALWAYS_INLINE unsigned int arch_irq_lock(void) +{ + return z_sparc_set_pil_inline(15); +} + +static ALWAYS_INLINE void arch_irq_unlock(unsigned int key) +{ + z_sparc_set_pil_inline(key); +} + +static ALWAYS_INLINE bool arch_irq_unlocked(unsigned int key) +{ + return key == 0; +} + +static ALWAYS_INLINE void arch_nop(void) +{ + __asm__ volatile ("nop"); +} + +extern uint32_t z_timer_cycle_get_32(void); + +static inline uint32_t arch_k_cycle_get_32(void) +{ + return z_timer_cycle_get_32(); +} + + +struct __esf { + uint32_t pc; + uint32_t npc; + uint32_t psr; + uint32_t tbr; + uint32_t sp; + uint32_t y; +}; + +typedef struct __esf z_arch_esf_t; + +#ifdef __cplusplus +} +#endif + +#endif /*_ASMLANGUAGE */ + +#endif /* ZEPHYR_INCLUDE_ARCH_SPARC_ARCH_H_ */ diff --git a/include/arch/sparc/linker.ld b/include/arch/sparc/linker.ld new file mode 100644 index 00000000000..f7b1fb02d28 --- /dev/null +++ b/include/arch/sparc/linker.ld @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2019-2020 Cobham Gaisler AB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Linker command/script file for SPARC + */ + +#include + +#include +#include + +#include +#include + +ENTRY(CONFIG_KERNEL_ENTRY) + +SECTIONS + { + +#include + + _image_rom_start = .; + + SECTION_PROLOGUE(_TEXT_SECTION_NAME,,) + { + /* Trap table alignment required by SPARC V8 specification. */ + . = ALIGN(0x1000); + _image_text_start = .; + + *(.text.traptable) + *(.text) + *(.text.*) + *(.stub) + *(.gnu.linkonce.t.*) + } GROUP_LINK_IN(REGION_TEXT) + + _image_text_end = .; + +#include + + SECTION_PROLOGUE(_RODATA_SECTION_NAME,,) + { + . = ALIGN(8); + *(.rodata) + *(.rodata.*) + *(.gnu.linkonce.r.*) + *(.rodata1) + +/* Located in generated directory. This file is populated by the + * zephyr_linker_sources() Cmake function. + */ +#include + + } GROUP_LINK_IN(REGION_RODATA) + +#include + + _image_rom_end = .; + __data_rom_start = .; + + + SECTION_PROLOGUE(.plt,,) + { + *(.plt) + } + + SECTION_PROLOGUE(.iplt,,) + { + *(.iplt) + } + + SECTION_DATA_PROLOGUE(_DATA_SECTION_NAME,,) + { + . = ALIGN(8); + _image_ram_start = .; + __data_ram_start = .; + + *(.data) + *(.data.*) + *(.gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + +/* Located in generated directory. This file is populated by the + * zephyr_linker_sources() Cmake function. + */ +#include + + } GROUP_DATA_LINK_IN(REGION_DATA_VMA, REGION_DATA_LMA) + +#include + +/* Located in generated directory. This file is populated by the + * zephyr_linker_sources() Cmake function. + */ +#include + __data_ram_end = .; + + SECTION_DATA_PROLOGUE(_BSS_SECTION_NAME,(NOLOAD),) + { + /* + * For performance, BSS section is assumed to be 4 byte aligned and + * a multiple of 4 bytes + */ + . = ALIGN(4); + __bss_start = .; + *(.dynbss) + *(.bss) + *(.bss.*) + *(.gnu.linkonce.b.*) + COMMON_SYMBOLS + /* + * As memory is cleared in words only, it is simpler to ensure the BSS + * section ends on a 4 byte boundary. This wastes a maximum of 3 bytes. + */ + __bss_end = ALIGN(4); + } GROUP_LINK_IN(REGION_BSS) + + SECTION_PROLOGUE(_NOINIT_SECTION_NAME,(NOLOAD),) + { + /* + * This section is used for non-initialized objects that + * will not be cleared during the boot process. + */ + *(.noinit) + *(.noinit.*) + +/* Located in generated directory. This file is populated by the + * zephyr_linker_sources() Cmake function. + */ +#include + + } GROUP_LINK_IN(REGION_BSS) + +#include + + _image_ram_end = .; + _end = .; /* end of image */ + +/* Located in generated directory. This file is populated by the + * zephyr_linker_sources() Cmake function. + */ +#include + +#include + + /DISCARD/ : { *(.note.GNU-stack) } + /DISCARD/ : { *(.gnu_debuglink) } + /DISCARD/ : { *(.gnu.lto_*) } + + SECTION_PROLOGUE(.gnu.attributes, 0,) + { + KEEP(*(.gnu.attributes)) + } + +} diff --git a/include/arch/sparc/sparc.h b/include/arch/sparc/sparc.h new file mode 100644 index 00000000000..ca0e49b4226 --- /dev/null +++ b/include/arch/sparc/sparc.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019-2020 Cobham Gaisler AB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_ARCH_SPARC_SPARC_H_ +#define ZEPHYR_INCLUDE_ARCH_SPARC_SPARC_H_ + +/* + * @file + * @brief Definitions for the SPARC V8 architecture. + */ + +/* Processor State Register */ +#define PSR_VER_BIT 24 +#define PSR_PIL_BIT 8 + +#define PSR_VER (0xf << PSR_VER_BIT) +#define PSR_EF (1 << 12) +#define PSR_S (1 << 7) +#define PSR_PS (1 << 6) +#define PSR_ET (1 << 5) +#define PSR_PIL (0xf << PSR_PIL_BIT) +#define PSR_CWP 0x1f + + +/* Trap Base Register */ +#define TBR_TT_BIT 4 + +#define TBR_TBA 0xfffff000 +#define TBR_TT 0x00000ff0 + +/* Trap types in TBR.TT */ +#define TT_RESET 0x00 +#define TT_WINDOW_OVERFLOW 0x05 +#define TT_WINDOW_UNDERFLOW 0x06 +#define TT_DATA_ACCESS_EXCEPTION 0x09 + +#endif /* ZEPHYR_INCLUDE_ARCH_SPARC_SPARC_H_ */ diff --git a/include/arch/sparc/thread.h b/include/arch/sparc/thread.h new file mode 100644 index 00000000000..a09115db1f5 --- /dev/null +++ b/include/arch/sparc/thread.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2019-2020 Cobham Gaisler AB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Per-arch thread definition + * + * This file contains definitions for + * + * struct _thread_arch + * struct _callee_saved + * + * necessary to instantiate instances of struct k_thread. + */ + +#ifndef ZEPHYR_INCLUDE_ARCH_SPARC_THREAD_H_ +#define ZEPHYR_INCLUDE_ARCH_SPARC_THREAD_H_ + +#ifndef _ASMLANGUAGE +#include + +/* + * The following structure defines the list of registers that need to be + * saved/restored when a cooperative context switch occurs. + */ +struct _callee_saved { + /* y register used by mul/div */ + uint32_t y; + + /* processor status register */ + uint32_t psr; + + /* + * local registers + * + * Using uint64_t l0_and_l1 will put everything in this structure on a + * double word boundary which allows us to use double word loads and + * stores safely in the context switch. + */ + uint64_t l0_and_l1; + uint32_t l2; + uint32_t l3; + uint32_t l4; + uint32_t l5; + uint32_t l6; + uint32_t l7; + + /* input registers */ + uint32_t i0; + uint32_t i1; + uint32_t i2; + uint32_t i3; + uint32_t i4; + uint32_t i5; + uint32_t i6; /* frame pointer */ + uint32_t i7; + + /* output registers */ + uint32_t o6; /* stack pointer */ + uint32_t o7; + +}; +typedef struct _callee_saved _callee_saved_t; + +struct _thread_arch { + /* empty */ +}; + +typedef struct _thread_arch _thread_arch_t; + +#endif /* _ASMLANGUAGE */ + +#endif /* ZEPHYR_INCLUDE_ARCH_SPARC_THREAD_H_ */