summaryrefslogtreecommitdiff
path: root/arch/openrisc/kernel/entry.S
diff options
context:
space:
mode:
Diffstat (limited to 'arch/openrisc/kernel/entry.S')
-rw-r--r--arch/openrisc/kernel/entry.S179
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