diff options
Diffstat (limited to 'arch/openrisc/kernel/entry.S')
| -rw-r--r-- | arch/openrisc/kernel/entry.S | 179 |
1 files changed, 130 insertions, 49 deletions
diff --git a/arch/openrisc/kernel/entry.S b/arch/openrisc/kernel/entry.S index 1b7160c79646..c7e90b09645e 100644 --- a/arch/openrisc/kernel/entry.S +++ b/arch/openrisc/kernel/entry.S @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * OpenRISC entry.S * @@ -9,14 +10,10 @@ * Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com> * Copyright (C) 2005 Gyorgy Jeney <nog@bsemi.com> * Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. */ #include <linux/linkage.h> +#include <linux/pgtable.h> #include <asm/processor.h> #include <asm/unistd.h> @@ -25,7 +22,6 @@ #include <asm/spr_defs.h> #include <asm/page.h> #include <asm/mmu.h> -#include <asm/pgtable.h> #include <asm/asm-offsets.h> #define DISABLE_INTERRUPTS(t1,t2) \ @@ -42,6 +38,61 @@ /* =========================================================[ macros ]=== */ +#ifdef CONFIG_TRACE_IRQFLAGS +/* + * Trace irq on/off creating a stack frame. + */ +#define TRACE_IRQS_OP(trace_op) \ + l.sw -8(r1),r2 /* store frame pointer */ ;\ + l.sw -4(r1),r9 /* store return address */ ;\ + l.addi r2,r1,0 /* move sp to fp */ ;\ + l.jal trace_op ;\ + l.addi r1,r1,-8 ;\ + l.ori r1,r2,0 /* restore sp */ ;\ + l.lwz r9,-4(r1) /* restore return address */ ;\ + l.lwz r2,-8(r1) /* restore fp */ ;\ +/* + * Trace irq on/off and save registers we need that would otherwise be + * clobbered. + */ +#define TRACE_IRQS_SAVE(t1,trace_op) \ + l.sw -12(r1),t1 /* save extra reg */ ;\ + l.sw -8(r1),r2 /* store frame pointer */ ;\ + l.sw -4(r1),r9 /* store return address */ ;\ + l.addi r2,r1,0 /* move sp to fp */ ;\ + l.jal trace_op ;\ + l.addi r1,r1,-12 ;\ + l.ori r1,r2,0 /* restore sp */ ;\ + l.lwz r9,-4(r1) /* restore return address */ ;\ + l.lwz r2,-8(r1) /* restore fp */ ;\ + l.lwz t1,-12(r1) /* restore extra reg */ + +#define TRACE_IRQS_OFF TRACE_IRQS_OP(trace_hardirqs_off) +#define TRACE_IRQS_ON TRACE_IRQS_OP(trace_hardirqs_on) +#define TRACE_IRQS_ON_SYSCALL \ + TRACE_IRQS_SAVE(r10,trace_hardirqs_on) ;\ + l.lwz r3,PT_GPR3(r1) ;\ + l.lwz r4,PT_GPR4(r1) ;\ + l.lwz r5,PT_GPR5(r1) ;\ + l.lwz r6,PT_GPR6(r1) ;\ + l.lwz r7,PT_GPR7(r1) ;\ + l.lwz r8,PT_GPR8(r1) ;\ + l.lwz r11,PT_GPR11(r1) +#define TRACE_IRQS_OFF_ENTRY \ + l.lwz r5,PT_SR(r1) ;\ + l.andi r3,r5,(SPR_SR_IEE|SPR_SR_TEE) ;\ + l.sfeq r5,r0 /* skip trace if irqs were already off */;\ + l.bf 1f ;\ + l.nop ;\ + TRACE_IRQS_SAVE(r4,trace_hardirqs_off) ;\ +1: +#else +#define TRACE_IRQS_OFF +#define TRACE_IRQS_ON +#define TRACE_IRQS_OFF_ENTRY +#define TRACE_IRQS_ON_SYSCALL +#endif + /* * We need to disable interrupts at beginning of RESTORE_ALL * since interrupt might come in after we've loaded EPC return address @@ -122,8 +173,8 @@ handler: ;\ l.sw PT_GPR28(r1),r28 ;\ l.sw PT_GPR29(r1),r29 ;\ /* r30 already save */ ;\ -/* l.sw PT_GPR30(r1),r30*/ ;\ l.sw PT_GPR31(r1),r31 ;\ + TRACE_IRQS_OFF_ENTRY ;\ /* Store -1 in orig_gpr11 for non-syscall exceptions */ ;\ l.addi r30,r0,-1 ;\ l.sw PT_ORIG_GPR11(r1),r30 @@ -159,9 +210,8 @@ handler: ;\ l.sw PT_GPR27(r1),r27 ;\ l.sw PT_GPR28(r1),r28 ;\ l.sw PT_GPR29(r1),r29 ;\ - /* r31 already saved */ ;\ - l.sw PT_GPR30(r1),r30 ;\ -/* l.sw PT_GPR31(r1),r31 */ ;\ + /* r30 already saved */ ;\ + l.sw PT_GPR31(r1),r31 ;\ /* Store -1 in orig_gpr11 for non-syscall exceptions */ ;\ l.addi r30,r0,-1 ;\ l.sw PT_ORIG_GPR11(r1),r30 ;\ @@ -184,11 +234,13 @@ handler: ;\ * occured. in fact they never do. if you need them use * values saved on stack (for SPR_EPC, SPR_ESR) or content * of r4 (for SPR_EEAR). for details look at EXCEPTION_HANDLE() - * in 'arch/or32/kernel/head.S' + * in 'arch/openrisc/kernel/head.S' */ /* =====================================================[ exceptions] === */ + __REF + /* ---[ 0x100: RESET exception ]----------------------------------------- */ EXCEPTION_ENTRY(_tng_kernel_start) @@ -221,12 +273,6 @@ EXCEPTION_ENTRY(_data_page_fault_handler) l.addi r3,r1,0 // pt_regs /* r4 set be EXCEPTION_HANDLE */ // effective address of fault - /* - * __PHX__: TODO - * - * all this can be written much simpler. look at - * DTLB miss handler in the CONFIG_GUARD_PROTECTED_CORE part - */ #ifdef CONFIG_OPENRISC_NO_SPR_SR_DSX l.lwz r6,PT_PC(r3) // address of an offending insn l.lwz r6,0(r6) // instruction that caused pf @@ -258,7 +304,7 @@ EXCEPTION_ENTRY(_data_page_fault_handler) #else - l.lwz r6,PT_SR(r3) // SR + l.mfspr r6,r0,SPR_SR // SR l.andi r6,r6,SPR_SR_DSX // check for delay slot exception l.sfne r6,r0 // exception happened in delay slot l.bnf 7f @@ -280,7 +326,7 @@ EXCEPTION_ENTRY(_data_page_fault_handler) 1: l.ori r6,r0,0x0 // !write access 2: - /* call fault.c handler in or32/mm/fault.c */ + /* call fault.c handler in openrisc/mm/fault.c */ l.jal do_page_fault l.nop l.j _ret_from_exception @@ -302,7 +348,7 @@ EXCEPTION_ENTRY(_insn_page_fault_handler) /* r4 set be EXCEPTION_HANDLE */ // effective address of fault l.ori r6,r0,0x0 // !write access - /* call fault.c handler in or32/mm/fault.c */ + /* call fault.c handler in openrisc/mm/fault.c */ l.jal do_page_fault l.nop l.j _ret_from_exception @@ -501,11 +547,12 @@ EXCEPTION_ENTRY(_external_irq_handler) l.bnf 1f // ext irq enabled, all ok. l.nop +#ifdef CONFIG_PRINTK l.addi r1,r1,-0x8 l.movhi r3,hi(42f) l.ori r3,r3,lo(42f) l.sw 0x0(r1),r3 - l.jal printk + l.jal _printk l.sw 0x4(r1),r4 l.addi r1,r1,0x8 @@ -514,6 +561,7 @@ EXCEPTION_ENTRY(_external_irq_handler) .string "\n\rESR interrupt bug: in _external_irq_handler (ESR %x)\n\r" .align 4 .previous +#endif l.ori r4,r4,SPR_SR_IEE // fix the bug // l.sw PT_SR(r1),r4 @@ -521,8 +569,8 @@ EXCEPTION_ENTRY(_external_irq_handler) #endif CLEAR_LWA_FLAG(r3) l.addi r3,r1,0 - l.movhi r8,hi(do_IRQ) - l.ori r8,r8,lo(do_IRQ) + l.movhi r8,hi(generic_handle_arch_irq) + l.ori r8,r8,lo(generic_handle_arch_irq) l.jalr r8 l.nop l.j _ret_from_intr @@ -553,13 +601,10 @@ UNHANDLED_EXCEPTION(_vector_0xb00,0xb00) */ _string_syscall_return: - .string "syscall return %ld \n\r\0" + .string "syscall r9:0x%08x -> syscall(%ld) return %ld\0" .align 4 ENTRY(_sys_call_handler) - /* syscalls run with interrupts enabled */ - ENABLE_INTERRUPTS(r29) // enable interrupts, r29 is temp - /* r1, EPCR, ESR a already saved */ l.sw PT_GPR2(r1),r2 /* r3-r8 must be saved because syscall restart relies @@ -597,6 +642,10 @@ ENTRY(_sys_call_handler) /* l.sw PT_GPR30(r1),r30 */ _syscall_check_trace_enter: + /* syscalls run with interrupts enabled */ + TRACE_IRQS_ON_SYSCALL + ENABLE_INTERRUPTS(r29) // enable interrupts, r29 is temp + /* If TIF_SYSCALL_TRACE is set, then we want to do syscall tracing */ l.lwz r30,TI_FLAGS(r10) l.andi r30,r30,_TIF_SYSCALL_TRACE @@ -630,15 +679,25 @@ _syscall_return: _syscall_debug: l.movhi r3,hi(_string_syscall_return) l.ori r3,r3,lo(_string_syscall_return) - l.ori r27,r0,1 + l.ori r27,r0,2 l.sw -4(r1),r27 l.sw -8(r1),r11 - l.addi r1,r1,-8 - l.movhi r27,hi(printk) - l.ori r27,r27,lo(printk) + l.lwz r29,PT_ORIG_GPR11(r1) + l.sw -12(r1),r29 + l.lwz r29,PT_GPR9(r1) + l.sw -16(r1),r29 + l.movhi r27,hi(_printk) + l.ori r27,r27,lo(_printk) l.jalr r27 - l.nop - l.addi r1,r1,8 + l.addi r1,r1,-16 + l.addi r1,r1,16 +#endif +#if 0 +_syscall_show_regs: + l.movhi r27,hi(show_registers) + l.ori r27,r27,lo(show_registers) + l.jalr r27 + l.or r3,r1,r1 #endif _syscall_check_trace_leave: @@ -655,8 +714,13 @@ _syscall_check_trace_leave: * interrupts that set NEED_RESCHED or SIGNALPENDING... really true? */ _syscall_check_work: +#ifdef CONFIG_DEBUG_RSEQ + l.jal rseq_syscall + l.ori r3,r1,0 +#endif /* Here we need to disable interrupts */ DISABLE_INTERRUPTS(r27,r29) + TRACE_IRQS_OFF l.lwz r30,TI_FLAGS(r10) l.andi r30,r30,_TIF_WORK_MASK l.sfne r30,r0 @@ -784,9 +848,17 @@ _syscall_badsys: /******* END SYSCALL HANDLING *******/ -/* ---[ 0xd00: Trap exception ]------------------------------------------ */ +/* ---[ 0xd00: Floating Point exception ]-------------------------------- */ + +EXCEPTION_ENTRY(_fpe_trap_handler) + CLEAR_LWA_FLAG(r3) + + /* r4: EA of fault (set by EXCEPTION_HANDLE) */ + l.jal do_fpe_trap + l.addi r3,r1,0 /* pt_regs */ -UNHANDLED_EXCEPTION(_vector_0xd00,0xd00) + l.j _ret_from_exception + l.nop /* ---[ 0xe00: Trap exception ]------------------------------------------ */ @@ -871,6 +943,7 @@ UNHANDLED_EXCEPTION(_vector_0x1f00,0x1f00) _resume_userspace: DISABLE_INTERRUPTS(r3,r4) + TRACE_IRQS_OFF l.lwz r4,TI_FLAGS(r10) l.andi r13,r4,_TIF_WORK_MASK l.sfeqi r13,0 @@ -909,6 +982,15 @@ _work_pending: l.lwz r8,PT_GPR8(r1) _restore_all: +#ifdef CONFIG_TRACE_IRQFLAGS + l.lwz r4,PT_SR(r1) + l.andi r3,r4,(SPR_SR_IEE|SPR_SR_TEE) + l.sfeq r3,r0 /* skip trace if irqs were off */ + l.bf skip_hardirqs_on + l.nop + TRACE_IRQS_ON +skip_hardirqs_on: +#endif RESTORE_ALL /* This returns to userspace code */ @@ -941,11 +1023,10 @@ ENTRY(ret_from_fork) l.lwz r11,PT_GPR11(r1) /* The syscall fast path return expects call-saved registers - * r12-r28 to be untouched, so we restore them here as they + * r14-r28 to be untouched, so we restore them here as they * will have been effectively clobbered when arriving here * via the call to switch() */ - l.lwz r12,PT_GPR12(r1) l.lwz r14,PT_GPR14(r1) l.lwz r16,PT_GPR16(r1) l.lwz r18,PT_GPR18(r1) @@ -977,10 +1058,10 @@ ENTRY(ret_from_fork) /* _switch MUST never lay on page boundry, cause it runs from * effective addresses and beeing interrupted by iTLB miss would kill it. - * dTLB miss seams to never accour in the bad place since data accesses + * dTLB miss seems to never accour in the bad place since data accesses * are from task structures which are always page aligned. * - * The problem happens in RESTORE_ALL_NO_R11 where we first set the EPCR + * The problem happens in RESTORE_ALL where we first set the EPCR * register, then load the previous register values and only at the end call * the l.rfe instruction. If get TLB miss in beetwen the EPCR register gets * garbled and we end up calling l.rfe with the wrong EPCR. (same probably @@ -1008,9 +1089,8 @@ ENTRY(_switch) /* No need to store r1/PT_SP as it goes into KSP below */ l.sw PT_GPR2(r1),r2 l.sw PT_GPR9(r1),r9 - /* This is wrong, r12 shouldn't be here... but GCC is broken for the time being - * and expects r12 to be callee-saved... */ - l.sw PT_GPR12(r1),r12 + + /* Save callee-saved registers to the new pt_regs */ l.sw PT_GPR14(r1),r14 l.sw PT_GPR16(r1),r16 l.sw PT_GPR18(r1),r18 @@ -1051,9 +1131,7 @@ ENTRY(_switch) /* No need to restore r10 */ /* ...and do not restore r11 */ - /* This is wrong, r12 shouldn't be here... but GCC is broken for the time being - * and expects r12 to be callee-saved... */ - l.lwz r12,PT_GPR12(r1) + /* Restore callee-saved registers */ l.lwz r14,PT_GPR14(r1) l.lwz r16,PT_GPR16(r1) l.lwz r18,PT_GPR18(r1) @@ -1106,15 +1184,18 @@ _fork_save_extra_regs_and_call: ENTRY(__sys_clone) l.movhi r29,hi(sys_clone) - l.ori r29,r29,lo(sys_clone) l.j _fork_save_extra_regs_and_call - l.addi r7,r1,0 + l.ori r29,r29,lo(sys_clone) + +ENTRY(__sys_clone3) + l.movhi r29,hi(sys_clone3) + l.j _fork_save_extra_regs_and_call + l.ori r29,r29,lo(sys_clone3) ENTRY(__sys_fork) l.movhi r29,hi(sys_fork) - l.ori r29,r29,lo(sys_fork) l.j _fork_save_extra_regs_and_call - l.addi r3,r1,0 + l.ori r29,r29,lo(sys_fork) ENTRY(sys_rt_sigreturn) l.jal _sys_rt_sigreturn |
