diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index 5ad57eb0c8e1f3aff7d01abfad8ed2d16aedccb5..edbf3af85f57339a31238d9fb5be7ed104084b57 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig @@ -130,6 +130,12 @@ config SPARC_BOOTMEM_REQUEST_NEW_ON_DEMAND If unsure, say Y. endmenu +config SPARC_NESTED_IRQ + bool "Allow nested IRQs" + default y + help + Allow higher-priority interrupts to preempt interrupt service routines + of lower priority interrupts. If unsure, say Y. endmenu diff --git a/arch/sparc/include/asm/leon.h b/arch/sparc/include/asm/leon.h index f1b0a439c9d2b88c4c571b8fb80d1edac94a71ce..f127144941f8a955d1444463c5bb888d074338f6 100644 --- a/arch/sparc/include/asm/leon.h +++ b/arch/sparc/include/asm/leon.h @@ -193,17 +193,12 @@ static inline unsigned long leon_get_fp(void) __attribute__((unused)) -#ifdef CONFIG_ARCH_CUSTOM_BOOT_CODE -#include <kernel/printk.h> -#endif static inline void leon_reg_win_flush(void) { -#ifdef CONFIG_ARCH_CUSTOM_BOOT_CODE - pr_warn("NOT IMPLEMENTED: leon_reg_win_flush() %s:%d\n", __FILE__, __LINE__); -#else - /* BCC/libgloss provide such functionality via SW trap 3 */ + /* BCC/libgloss provide such functionality via SW trap 3, so does Linux + * and now we do too... + **/ __asm__ __volatile__("ta 3"); -#endif /* CONFIG_ARCH_CUSTOM_BOOT_CODE */ } diff --git a/arch/sparc/include/asm/ttable.h b/arch/sparc/include/asm/ttable.h index 0700b14112a67cdbd69568a50822fb698c99af99..3f0b939b2fbe9de03c4826bf07eb633b1066b2ba 100644 --- a/arch/sparc/include/asm/ttable.h +++ b/arch/sparc/include/asm/ttable.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _SPARC_HEAD_H -#define _SPARC_HEAD_H +#ifndef _SPARC_TTABLE_H +#define _SPARC_TTABLE_H #define SPARC_TRAP_TFLT 0x1 /* Text fault */ #define SPARC_TRAP_II 0x2 /* Illegal Instruction */ @@ -41,6 +41,13 @@ #define PSR_PS 0x00000040 /* previous privilege level */ +#define PSR_S 0x00000080 /* enable supervisor */ + +#define PSR_ET 0x00000020 /* enable traps */ +#define PSR_EF 0x00001000 /* enable FPU */ + +#define PSR_PIL 0x00000f00 /* processor interrupt level */ +#define PSR_PIL_SHIFT 8 /* PIL field shift */ #define TTBL_MASK 0xff0 /* trap type mask from tbr */ @@ -79,4 +86,20 @@ rd %psr, %l0; -#endif /* _SPARC_HEAD_H */ +/* This is the same convention as in leonbare and linux */ +/* All trap entry points _must_ begin with this macro or else you + * lose. It makes sure the kernel has a proper window so that + * c-code can be called. + */ +#define SAVE_ALL_HEAD \ + sethi %hi(trap_setup), %l4; \ + jmpl %l4 + %lo(trap_setup), %l6; +#define SAVE_ALL \ + SAVE_ALL_HEAD \ + nop; + +/* All traps low-level code here must end with this macro. */ +#define RESTORE_ALL b ret_trap_entry; clr %l6; + + +#endif /* _SPARC_TTABLE_H */ diff --git a/arch/sparc/include/asm/win.h b/arch/sparc/include/asm/win.h index bf3ac94ec67c812f644929efd15ce5f97393772b..14d746081395dc206337a366add849865fdac927 100644 --- a/arch/sparc/include/asm/win.h +++ b/arch/sparc/include/asm/win.h @@ -44,4 +44,65 @@ std %i6, [%reg + RW_I6]; +/* LOAD/STORE of trap frame */ + +#define LOAD_PT_INS(base_reg) \ + ldd [%base_reg + STACKFRAME_SZ + PT_I0], %i0; \ + ldd [%base_reg + STACKFRAME_SZ + PT_I2], %i2; \ + ldd [%base_reg + STACKFRAME_SZ + PT_I4], %i4; \ + ldd [%base_reg + STACKFRAME_SZ + PT_I6], %i6; + +#define LOAD_PT_GLOBALS(base_reg) \ + ld [%base_reg + STACKFRAME_SZ + PT_G1], %g1; \ + ldd [%base_reg + STACKFRAME_SZ + PT_G2], %g2; \ + ldd [%base_reg + STACKFRAME_SZ + PT_G4], %g4; \ + ldd [%base_reg + STACKFRAME_SZ + PT_G6], %g6; + +#define LOAD_PT_YREG(base_reg, scratch) \ + ld [%base_reg + STACKFRAME_SZ + PT_Y], %scratch; \ + wr %scratch, 0x0, %y; + +#define LOAD_PT_PRIV(base_reg, pt_psr, pt_pc, pt_npc) \ + ld [%base_reg + STACKFRAME_SZ + PT_PSR], %pt_psr; \ + ld [%base_reg + STACKFRAME_SZ + PT_PC], %pt_pc; \ + ld [%base_reg + STACKFRAME_SZ + PT_NPC], %pt_npc; + +#define LOAD_PT_ALL(base_reg, pt_psr, pt_pc, pt_npc, scratch) \ + LOAD_PT_YREG(base_reg, scratch) \ + LOAD_PT_INS(base_reg) \ + LOAD_PT_GLOBALS(base_reg) \ + LOAD_PT_PRIV(base_reg, pt_psr, pt_pc, pt_npc) + + + + +#define STORE_PT_INS(base_reg) \ + std %i0, [%base_reg + STACKFRAME_SZ + PT_I0]; \ + std %i2, [%base_reg + STACKFRAME_SZ + PT_I2]; \ + std %i4, [%base_reg + STACKFRAME_SZ + PT_I4]; \ + std %i6, [%base_reg + STACKFRAME_SZ + PT_I6]; + +#define STORE_PT_GLOBALS(base_reg) \ + st %g1, [%base_reg + STACKFRAME_SZ + PT_G1]; \ + std %g2, [%base_reg + STACKFRAME_SZ + PT_G2]; \ + std %g4, [%base_reg + STACKFRAME_SZ + PT_G4]; \ + std %g6, [%base_reg + STACKFRAME_SZ + PT_G6]; + +#define STORE_PT_YREG(base_reg, scratch) \ + rd %y, %scratch; \ + st %scratch, [%base_reg + STACKFRAME_SZ + PT_Y]; + +#define STORE_PT_PRIV(base_reg, pt_psr, pt_pc, pt_npc) \ + st %pt_psr, [%base_reg + STACKFRAME_SZ + PT_PSR]; \ + st %pt_pc, [%base_reg + STACKFRAME_SZ + PT_PC]; \ + st %pt_npc, [%base_reg + STACKFRAME_SZ + PT_NPC]; + +#define STORE_PT_ALL(base_reg, reg_psr, reg_pc, reg_npc, g_scratch) \ + STORE_PT_PRIV(base_reg, reg_psr, reg_pc, reg_npc) \ + STORE_PT_GLOBALS(base_reg) \ + STORE_PT_YREG(base_reg, g_scratch) \ + STORE_PT_INS(base_reg) + + + #endif /* _SPARC_WIN_H */ diff --git a/arch/sparc/include/stack.h b/arch/sparc/include/stack.h index 51386c2aa5d190295984ef2fd731ba8d84a93583..c3038350191b9446c6f4f3dda535d1cf62edee37 100644 --- a/arch/sparc/include/stack.h +++ b/arch/sparc/include/stack.h @@ -1,9 +1,13 @@ #ifndef _SPARC_STACK_H_ #define _SPARC_STACK_H_ +#ifndef __ASSEMBLY__ #include <kernel/types.h> +#endif /* !(__ASSEMBLY__) */ + #include <asm/win.h> + /* stack frame offsets */ #define SF_L0 0x00 #define SF_L1 0x04 @@ -75,16 +79,26 @@ +#define STACK_ALIGN 8 +#define STACKFRAME_SZ 96 +#define PTREG_SZ 80 +#ifndef __ASSEMBLY__ +/* SPARC v8 cpu registers not part of a regular stack frame that we need in + * a trap frame to store the state of the CPU at the time of the trap. + */ struct pt_regs { uint32_t psr; uint32_t pc; uint32_t npc; uint32_t y; - uint32_t u_regs[16]; /* globals and ins */ + uint32_t u_regs[16]; /* globals and outs */ }; +compile_time_assert(sizeof(struct pt_regs) == PTREG_SZ, + SPARC__CPU_REG_SIZE_INVALID); + struct leon_reg_win { uint32_t locals[8]; uint32_t ins[8]; @@ -102,13 +116,13 @@ struct sparc_stackf { /* everyting allocated on the stack follows here */ }; - -#define STACKFRAME_SZ sizeof(struct sparc_stackf) - -#define STACK_ALIGN 8 +compile_time_assert(sizeof(struct sparc_stackf) == STACKFRAME_SZ, + SPARC__STACK_FRAME_SIZE_INVALID); int stack_migrate(void *sp, void *stack_top_new); +#endif /* !(__ASSEMBLY__) */ + #endif /* _SPARC_STACK_H_ */ diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile index 5cfce14d28ff8e86a4fdc8d6e1f9534a54884537..54ce8bb4ad74e4523d65fb6ecfed183834c85287 100644 --- a/arch/sparc/kernel/Makefile +++ b/arch/sparc/kernel/Makefile @@ -6,6 +6,10 @@ obj-$(CONFIG_ARCH_CUSTOM_BOOT_CODE) += ttable.o obj-$(CONFIG_ARCH_CUSTOM_BOOT_CODE) += head.o obj-$(CONFIG_ARCH_CUSTOM_BOOT_CODE) += win_uflow.o obj-$(CONFIG_ARCH_CUSTOM_BOOT_CODE) += win_oflow.o +obj-$(CONFIG_ARCH_CUSTOM_BOOT_CODE) += flush_windows.o +obj-$(CONFIG_ARCH_CUSTOM_BOOT_CODE) += etrap.o +obj-$(CONFIG_ARCH_CUSTOM_BOOT_CODE) += rtrap.o +obj-$(CONFIG_ARCH_CUSTOM_BOOT_CODE) += irqtrap.o obj-y += setup.o obj-y += init.o diff --git a/arch/sparc/kernel/etrap.S b/arch/sparc/kernel/etrap.S new file mode 100644 index 0000000000000000000000000000000000000000..e40ee5e43f7c23ba14366d13f457d516988b5f68 --- /dev/null +++ b/arch/sparc/kernel/etrap.S @@ -0,0 +1,106 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * etrap.S: Sparc trap window preparation for entry into the + * Linux kernel. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + Armin Luntzer <armin.luntzer@univie.ac.at> + */ + +#include <asm/ttable.h> +#include <stack.h> + + +#ifndef CONFIG_SPARC_CPU_REG_WINDOWS +#define NWINDOWS 8 +#else +#define NWINDOWS CONFIG_SPARC_CPU_REG_WINDOWS +#endif /* CONFIG_SPARC_CPU_REG_WINDOWS */ + + +/* Registers to not touch at all. */ +#define t_psr l0 /* Set by caller */ +#define t_pc l1 /* Set by caller */ +#define t_npc l2 /* Set by caller */ +#define t_wim l3 /* Set by caller */ +#define t_twinmask l4 /* Set at beginning of this entry routine. */ +#define t_kstack l5 /* Set right before pt_regs frame is built */ +#define t_retpc l6 /* If you change this, change winmacro.h header file */ +#define t_systable l7 /* Never touch this, could be the syscall table ptr. */ +#define curptr g6 /* Set after pt_regs frame is built */ + + .text + .align 4 + + .globl trap_setup +trap_setup: + /* Calculate mask of trap window. See if from user + * or kernel and branch conditionally. + */ + mov 1, %t_twinmask + andcc %t_psr, PSR_PS, %g0 ! fromsupv_p = (psr & PSR_PS) + be trap_setup_from_user ! nope, from user mode + sll %t_twinmask, %t_psr, %t_twinmask ! t_twinmask = (1 << psr) + + /* From kernel, allocate more kernel stack and + * build a pt_regs trap frame. + */ + sub %fp, (STACKFRAME_SZ + PTREG_SZ), %t_kstack + STORE_PT_ALL(t_kstack, t_psr, t_pc, t_npc, g2) + + /* See if we hit a window marked invalid, i.e. whether we have + * overflowed/spilled as part of this trap + */ + andcc %t_twinmask, %t_wim, %g0 + bne trap_setup_kernel_win_oflow ! window overflow + nop + + /* Trap from kernel with a window available. + * Just do it... + */ + jmpl %t_retpc + 0x8, %g0 ! return to caller + mov %t_kstack, %sp ! jump onto new stack + + +trap_setup_kernel_win_oflow: + /* here we check whether there are user windows. this is not relevant + * until we do a form of lazy context switching between kernel and + * userspace */ +! ld [%curptr + TI_UWINMASK], %g1 +! orcc %g0, %g1, %g0 +! bne trap_setup_user_spill ! there are some user windows, yuck + + + /* We hit the invalid window (overflow), but there are no user windows, + * so we do mostly the same thing as in __wim_overflow + */ + + /* + * First, we rotate the window invalid mask to the right by one and + * to the left by (NWINDOWS - 1), then OR the results (which is done + * implicitly in the WRPSR instruction), so our WIM rotates modulo + * NWINDOWS just like the CWP in the PSR + */ + + srl %t_wim, 0x1, %g2 + sll %t_wim, (NWINDOWS - 1), %t_wim + or %t_wim, %g2, %g2 ! store new WIM globally + !and %g2, ((1 << NWINDOWS) - 1), %g2 !not needed, we can always write set bits of unused windows to the wim + + + save ! move to window + wr %g2, %g0, %wim ! delayed-branch instruction + ! delay cycles are covered in store block + + STORE_WINDOW(sp) ! store kernel window to memory stack + + restore ! return to trap window + + jmpl %t_retpc + 0x8, %g0 ! return to caller + mov %t_kstack, %sp ! and onto new kernel stack + + +trap_setup_user_spill: + ta 0 ! not implemented, same stuff as in win_oflow.S +trap_setup_from_user: + ta 0 ! not implemented diff --git a/arch/sparc/kernel/flush_windows.S b/arch/sparc/kernel/flush_windows.S new file mode 100644 index 0000000000000000000000000000000000000000..8ed2fe6ef49c91c28213b9b8e1e308ec01fa0724 --- /dev/null +++ b/arch/sparc/kernel/flush_windows.S @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef CONFIG_SPARC_CPU_REG_WINDOWS +#define NWINDOWS 8 +#else +#define NWINDOWS CONFIG_SPARC_CPU_REG_WINDOWS +#endif /* CONFIG_SPARC_CPU_REG_WINDOWS */ + +#include <asm/ttable.h> +#include <stack.h> + + .align 4 + .globl flush_windows + +flush_windows: + SAVE_ALL + + wr %l0, PSR_ET, %psr ! delayed-write instruction + ! no nops needed, the following + ! compare-and-branch fills all 3 slots + + andcc %l0, PSR_PS, %g0 + be flush_user_windows + nop + +flush_windows_kernel_all: + + .rept NWINDOWS + save %sp, -STACKFRAME_SZ, %sp + .endr + + .rept NWINDOWS + restore + .endr + + b flush_windows_done + nop + + +flush_user_windows: + + call flush_windows_user + nop + + +flush_windows_done: + /* Advance over the trap instruction. */ + ld [%sp + STACKFRAME_SZ + PT_NPC], %l1 + add %l1, 0x4, %l2 + st %l1, [%sp + STACKFRAME_SZ + PT_PC] + st %l2, [%sp + STACKFRAME_SZ + PT_NPC] + + RESTORE_ALL + + + + .align 4 + .globl flush_windows_user +flush_windows_user: + + ta 0 ! not implemented, + diff --git a/arch/sparc/kernel/head.S b/arch/sparc/kernel/head.S index f513d8e275b664f9e0ac60a2ae2bbbe59a36f678..768586a28c05e16be8a555d2805727d1fb762533 100644 --- a/arch/sparc/kernel/head.S +++ b/arch/sparc/kernel/head.S @@ -1,5 +1,12 @@ /* SPDX-License-Identifier: GPL-2.0 */ +#include <asm/ttable.h> + + +/* It's actually possible to detect windows at runtime, but we don't + * care (yet), because this will probably never run on any !8-window SPARC + */ + #ifndef CONFIG_SPARC_CPU_REG_WINDOWS #define NWINDOWS 8 #else @@ -74,8 +81,7 @@ zero_bss: * See the SPARCv8 User Manual pp.28 for the other set bits */ - sethi %hi(0x00001fc0), %g1 - or %g1, %lo(0x00001fc0 | (NWINDOWS - 2)), %g1 + set (PSR_PS | PSR_S | PSR_PIL | PSR_EF) | (NWINDOWS - 2), %g1 mov %g1, %psr ! delayed-write instruction nop @@ -90,8 +96,11 @@ zero_bss: sub %fp, 104, %sp ! create a new frame /* We have a stack now, so we can start handling traps. */ - or %g1, 0x00000020, %g1 + or %g1, PSR_ET, %g1 mov %g1, %psr ! delayed-write instruction + nop + nop + nop call do_basic_setup nop diff --git a/arch/sparc/kernel/irq.c b/arch/sparc/kernel/irq.c index 82d3729265f623df543489effd3ee98b2d8d6890..93e6f0ffd77e4bc919b50048a7ef05dfde875a79 100644 --- a/arch/sparc/kernel/irq.c +++ b/arch/sparc/kernel/irq.c @@ -264,11 +264,36 @@ static struct sobj_attribute *eirl_attributes[] = { #ifndef CONFIG_ARCH_CUSTOM_BOOT_CODE + /* provided by BCC's libgloss */ extern int catch_interrupt (int func, int irq); +extern unsigned int nestedirq; + #endif /* CONFIG_ARCH_CUSTOM_BOOT_CODE */ + +/** + * @brief enable all interrupts by clearing the PSR PIL field + */ + +static void leon_irq_enable(void) +{ + unsigned long tmp; + + __asm__ __volatile__( + "rd %%psr,%0 \n\t" + "andn %0, %1,%0 \n\t" + "wr %0, 0, %%psr\n\t" + "nop\n" + "nop\n" + "nop\n" + : "=&r" (tmp) + : "i" (PSR_PIL) + : "memory"); +} + + /** * @brief clear (acknowledge) a pending IRQ * @@ -462,7 +487,7 @@ void leon_irq_queue_execute(void) /** - * @brief he central interrupt handling routine + * @brief the central interrupt handling routine * * @param irq an interrupt number * @@ -470,10 +495,9 @@ void leon_irq_queue_execute(void) * * @note handler return codes ignored for now * - * XXX maybe we want to keep acking IRQs as in eirq_dispatch... */ -__attribute__((unused)) -static int leon_irq_dispatch(unsigned int irq) + +int leon_irq_dispatch(unsigned int irq) { struct irl_vector_elem *p_elem; @@ -631,8 +655,8 @@ int irl_register_handler(unsigned int irq, /* here goes the call to whatever the low level handler is */ #ifdef CONFIG_ARCH_CUSTOM_BOOT_CODE - pr_warn("NOT IMPLEMENTED: catch_interrupt() %s:%d\n", __FILE__, __LINE__); - return -1; + /* call is part of IRQ trap entry in irqtrap.S */ + return 0; #else /* provided by BCC/libgloss */ return catch_interrupt(((int) leon_irq_dispatch), irq); @@ -918,7 +942,8 @@ static void leon_setup_eirq(void) leon_eirq = eirq; #ifdef CONFIG_ARCH_CUSTOM_BOOT_CODE - pr_warn("NOT IMPLEMENTED: catch_interrupt() %s:%d\n", __FILE__, __LINE__); + BUG_ON(irl_register_handler(leon_eirq, ISR_PRIORITY_NOW, + (irq_handler_t) leon_eirq_dispatch, NULL)); #else /* provided by BCC/libgloss */ BUG_ON(catch_interrupt((int) leon_eirq_dispatch, leon_eirq)); @@ -1076,6 +1101,22 @@ void leon_irq_init(void) BUG_ON(irq_dispatch_init()); +#ifndef CONFIG_ARCH_CUSTOM_BOOT_CODE + +#ifdef CONFIG_SPARC_NESTED_IRQ + nestedirq = 1; +#else /* !(CONFIG_SPARC_NESTED_IRQ) */ + nestedirq = 0; +#endif /* CONFIG_SPARC_NESTED_IRQ */ + +#endif /* !(CONFIG_ARCH_CUSTOM_BOOT_CODE) */ + + + + /* set up extended interrupt controller if found */ leon_setup_eirq(); + + /* now set the PIL field to zero to enable all IRLs */ + leon_irq_enable(); } diff --git a/arch/sparc/kernel/irqtrap.S b/arch/sparc/kernel/irqtrap.S new file mode 100644 index 0000000000000000000000000000000000000000..739133d3d480af2ba2fdab936d391d244136bc2a --- /dev/null +++ b/arch/sparc/kernel/irqtrap.S @@ -0,0 +1,61 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#include <asm/ttable.h> +#include <stack.h> + + +/* don't touch these */ +#define t_psr l0 /* set by trap entry */ +#define t_pc l1 +#define t_npc l2 +#define t_wim l3 /* set by trap entry */ +#define t_tmp l4 +#define t_irqlvl l7 /* set by trap entry */ + + + + + .align 4 + .globl __interrupt_entry + +__interrupt_entry: + SAVE_ALL + +#ifdef CONFIG_SPARC_NESTED_IRQ + /* The 4 bits of the PSR field set the level above which interrupts + * may occur. If we want ISR preemption, we set the level according + * to the IRQ number that occured... + */ + + sll %t_irqlvl, PSR_PIL_SHIFT, %g1 ! shift into place + andn %t_psr, PSR_PIL, %g2 ! clear field + or %g1, %g2, %g2 ! set new level + +#else /* !(CONFIG_SPARC_NESTED_IRQ) + /* ... otherwise we just set it to max */ + + or %t_psr, PSR_PIL, %g2 + +#endif /* CONFIG_SPARC_NESTED_IRQ */ + wr %g2, PSR_ET, %psr ! traps are off at this point, so we + nop ! xor the bit in the new PSR to re-enable + nop ! this is delayed-write, we need only + ! 2 nops before the call + + mov %t_irqlvl, %o0 ! set arg 1: irq level + ! nothing else for now + + call leon_irq_dispatch ! call high-level manager +#ifndef CONFIG_SPARC_NESTED_IRQ + nop +#else /* CONFIG_SPARC_NESTED_IRQ */ + or %t_psr, PSR_PIL, %t_tmp + + wr %t_tmp, PSR_ET, %psr ! we can't be preemted here, so set PIL + ! to max and xor ET to enable + ! delayed-write; nops not needed if + ! RESTORE_ALL and rtrap.S is not touced +#endif /* CONFIG_SPARC_NESTED_IRQ */ + + RESTORE_ALL + diff --git a/arch/sparc/kernel/rtrap.S b/arch/sparc/kernel/rtrap.S new file mode 100644 index 0000000000000000000000000000000000000000..196d68ea79a7bd904a1b3cfe3a07f9d6ca28cd31 --- /dev/null +++ b/arch/sparc/kernel/rtrap.S @@ -0,0 +1,78 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * etrap.S: Sparc trap window preparation for entry into the + * Linux kernel. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + Armin Luntzer <armin.luntzer@univie.ac.at> + */ + +#include <asm/ttable.h> +#include <stack.h> + + +#ifndef CONFIG_SPARC_CPU_REG_WINDOWS +#define NWINDOWS 8 +#else +#define NWINDOWS CONFIG_SPARC_CPU_REG_WINDOWS +#endif /* CONFIG_SPARC_CPU_REG_WINDOWS */ + + +/* Registers to not touch at all. */ + +#define t_psr l0 +#define t_pc l1 +#define t_npc l2 +#define t_wim l3 +#define twin_tmp1 l4 +#define glob_tmp g4 +#define curptr g6 + + + .globl ret_trap_entry +ret_trap_entry: + + +ret_trap_kernel: + /* Will the rett land us in the invalid window? */ + mov 2, %g1 + sll %g1, %t_psr, %g1 + srl %g1, NWINDOWS, %g2 + or %g1, %g2, %g1 + rd %wim, %g2 + andcc %g2, %g1, %g0 + be 1f ! Nope, just return from the trap + sll %g2, 0x1, %g1 + + /* window would be invalid, apply rotated mask (same as in win_uflow) */ + srl %g2, (NWINDOWS - 1), %g2 + or %g1, %g2, %g1 + + /* no need to mask unused bits here, the CPU ignores any unimplemented + * windows + */ + wr %g1, 0x0, %wim + + LOAD_PT_ALL(sp, t_psr, t_pc, t_npc, g1) + + restore + LOAD_WINDOW(sp) + b 2f + save + + /* Reload the entire frame in case this is from a + * kernel system call or whatever... + */ +1: + LOAD_PT_ALL(sp, t_psr, t_pc, t_npc, g1) +2: + /* no syscall implemented yet */ +! sethi %hi(PSR_SYSCALL), %twin_tmp1 +! andn %t_psr, %twin_tmp1, %t_psr + + wr %t_psr, %g0, %psr ! restore PSR, delayed-write instruction + nop ! need 2 delays, rett modifies CWP + nop ! 3rd delay cycle is filled by jmp instr + + jmp %t_pc + rett %t_npc diff --git a/arch/sparc/kernel/ttable.S b/arch/sparc/kernel/ttable.S index 04a319a89987110bb5d1f72fc0943f89f8001dad..6d8648114d08f2d9125812fe62177f72fde69217 100644 --- a/arch/sparc/kernel/ttable.S +++ b/arch/sparc/kernel/ttable.S @@ -87,7 +87,7 @@ trapbase_cpu0: SYSCALL_TRAP ! 0x80 = SunOS syscall() TRAP_EXCEPTION ! 0x81 TRAP_EXCEPTION ! 0x82 - TRAP_EXCEPTION ! 0x83 + TRAP_ENTRY(0x83, flush_windows) ! 0x83 TRAP_EXCEPTION ! 0x84 TRAP_EXCEPTION ! 0x85 @@ -113,10 +113,6 @@ trapbase_cpu1: .global leonbare_trapsetup leonbare_trapsetup: - .global catch_interrupt -catch_interrupt: - .global coldboot_reset -coldboot_reset: .global __exception_entry __exception_entry: .global srmmu_fault @@ -125,8 +121,6 @@ srmmu_fault: ill_instruction_trap_handler: .global priv_instruction_trap_handler priv_instruction_trap_handler: - - .global leonbare_trapreturn leonbare_trapreturn: .global fpdis_trap_handler @@ -147,16 +141,12 @@ cpex_trap_handler: fpe_trap_handler: .global hw_div0_trap_handler hw_div0_trap_handler: - .global __interrupt_entry -__interrupt_entry: .global nmi_entry nmi_entry: .global reg_access_trap_handler reg_access_trap_handler: .global strchr strchr: - .global strtol -strtol: .global syscall_tbl syscall_tbl: .global syscall_trap diff --git a/arch/sparc/kernel/win_oflow.S b/arch/sparc/kernel/win_oflow.S index 3cc7fce46db1d3e98732c62a8f39918eda9b7ec6..6d4f94dcb1b94a09dd98ca020d90be828c7a73e3 100644 --- a/arch/sparc/kernel/win_oflow.S +++ b/arch/sparc/kernel/win_oflow.S @@ -53,7 +53,6 @@ __wim_overflow: srl %l3, 1, %l4 sll %l3, (NWINDOWS - 1), %g5 or %l4, %g5, %g5 ! store new WIM globally - !and %g5, ((1 << NWINDOWS) - 1), %g5 /* At this point, we proceed depending on the state of the previous * supervisor (PS) bit. The condition code has been set by the trap