xref: /openbmc/linux/arch/openrisc/kernel/entry.S (revision 27267655)
12874c5fdSThomas Gleixner/* SPDX-License-Identifier: GPL-2.0-or-later */
29d02a428SJonas Bonn/*
39d02a428SJonas Bonn * OpenRISC entry.S
49d02a428SJonas Bonn *
59d02a428SJonas Bonn * Linux architectural port borrowing liberally from similar works of
69d02a428SJonas Bonn * others.  All original copyrights apply as per the original source
79d02a428SJonas Bonn * declaration.
89d02a428SJonas Bonn *
99d02a428SJonas Bonn * Modifications for the OpenRISC architecture:
109d02a428SJonas Bonn * Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
119d02a428SJonas Bonn * Copyright (C) 2005 Gyorgy Jeney <nog@bsemi.com>
129d02a428SJonas Bonn * Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
139d02a428SJonas Bonn */
149d02a428SJonas Bonn
159d02a428SJonas Bonn#include <linux/linkage.h>
1665fddcfcSMike Rapoport#include <linux/pgtable.h>
179d02a428SJonas Bonn
189d02a428SJonas Bonn#include <asm/processor.h>
199d02a428SJonas Bonn#include <asm/unistd.h>
209d02a428SJonas Bonn#include <asm/thread_info.h>
219d02a428SJonas Bonn#include <asm/errno.h>
229d02a428SJonas Bonn#include <asm/spr_defs.h>
239d02a428SJonas Bonn#include <asm/page.h>
249d02a428SJonas Bonn#include <asm/mmu.h>
259d02a428SJonas Bonn#include <asm/asm-offsets.h>
269d02a428SJonas Bonn
279d02a428SJonas Bonn#define DISABLE_INTERRUPTS(t1,t2)			\
289d02a428SJonas Bonn	l.mfspr t2,r0,SPR_SR				;\
299d02a428SJonas Bonn	l.movhi	t1,hi(~(SPR_SR_IEE|SPR_SR_TEE))		;\
309d02a428SJonas Bonn	l.ori	t1,t1,lo(~(SPR_SR_IEE|SPR_SR_TEE))	;\
319d02a428SJonas Bonn	l.and   t2,t2,t1				;\
329d02a428SJonas Bonn	l.mtspr r0,t2,SPR_SR
339d02a428SJonas Bonn
349d02a428SJonas Bonn#define ENABLE_INTERRUPTS(t1)				\
359d02a428SJonas Bonn	l.mfspr	t1,r0,SPR_SR				;\
369d02a428SJonas Bonn	l.ori	t1,t1,lo(SPR_SR_IEE|SPR_SR_TEE)		;\
379d02a428SJonas Bonn	l.mtspr	r0,t1,SPR_SR
389d02a428SJonas Bonn
399d02a428SJonas Bonn/* =========================================================[ macros ]=== */
409d02a428SJonas Bonn
4178cdfb5cSStafford Horne#ifdef CONFIG_TRACE_IRQFLAGS
4278cdfb5cSStafford Horne/*
4378cdfb5cSStafford Horne * Trace irq on/off creating a stack frame.
4478cdfb5cSStafford Horne */
4578cdfb5cSStafford Horne#define TRACE_IRQS_OP(trace_op)					\
4678cdfb5cSStafford Horne	l.sw 	-8(r1),r2	/* store frame pointer */		;\
4778cdfb5cSStafford Horne	l.sw	-4(r1),r9	/* store return address */		;\
4878cdfb5cSStafford Horne	l.addi	r2,r1,0		/* move sp to fp */			;\
4978cdfb5cSStafford Horne	l.jal	trace_op						;\
5078cdfb5cSStafford Horne	 l.addi	r1,r1,-8						;\
5178cdfb5cSStafford Horne	l.ori	r1,r2,0		/* restore sp */			;\
5278cdfb5cSStafford Horne	l.lwz	r9,-4(r1)	/* restore return address */		;\
5378cdfb5cSStafford Horne	l.lwz	r2,-8(r1)	/* restore fp */			;\
5478cdfb5cSStafford Horne/*
5578cdfb5cSStafford Horne * Trace irq on/off and save registers we need that would otherwise be
5678cdfb5cSStafford Horne * clobbered.
5778cdfb5cSStafford Horne */
5878cdfb5cSStafford Horne#define TRACE_IRQS_SAVE(t1,trace_op)					\
5978cdfb5cSStafford Horne	l.sw	-12(r1),t1	/* save extra reg */			;\
6078cdfb5cSStafford Horne	l.sw 	-8(r1),r2	/* store frame pointer */		;\
6178cdfb5cSStafford Horne	l.sw	-4(r1),r9	/* store return address */		;\
6278cdfb5cSStafford Horne	l.addi	r2,r1,0		/* move sp to fp */			;\
6378cdfb5cSStafford Horne	l.jal	trace_op						;\
6478cdfb5cSStafford Horne	 l.addi	r1,r1,-12						;\
6578cdfb5cSStafford Horne	l.ori	r1,r2,0		/* restore sp */			;\
6678cdfb5cSStafford Horne	l.lwz	r9,-4(r1)	/* restore return address */		;\
6778cdfb5cSStafford Horne	l.lwz	r2,-8(r1)	/* restore fp */			;\
6878cdfb5cSStafford Horne	l.lwz	t1,-12(r1)	/* restore extra reg */
6978cdfb5cSStafford Horne
7078cdfb5cSStafford Horne#define TRACE_IRQS_OFF	TRACE_IRQS_OP(trace_hardirqs_off)
7178cdfb5cSStafford Horne#define TRACE_IRQS_ON	TRACE_IRQS_OP(trace_hardirqs_on)
7278cdfb5cSStafford Horne#define TRACE_IRQS_ON_SYSCALL						\
7378cdfb5cSStafford Horne	TRACE_IRQS_SAVE(r10,trace_hardirqs_on)				;\
7478cdfb5cSStafford Horne	l.lwz	r3,PT_GPR3(r1)						;\
7578cdfb5cSStafford Horne	l.lwz	r4,PT_GPR4(r1)						;\
7678cdfb5cSStafford Horne	l.lwz	r5,PT_GPR5(r1)						;\
7778cdfb5cSStafford Horne	l.lwz	r6,PT_GPR6(r1)						;\
7878cdfb5cSStafford Horne	l.lwz	r7,PT_GPR7(r1)						;\
7978cdfb5cSStafford Horne	l.lwz	r8,PT_GPR8(r1)						;\
8078cdfb5cSStafford Horne	l.lwz	r11,PT_GPR11(r1)
8178cdfb5cSStafford Horne#define TRACE_IRQS_OFF_ENTRY						\
8278cdfb5cSStafford Horne	l.lwz	r5,PT_SR(r1)						;\
8378cdfb5cSStafford Horne	l.andi	r3,r5,(SPR_SR_IEE|SPR_SR_TEE)				;\
8478cdfb5cSStafford Horne	l.sfeq	r5,r0		/* skip trace if irqs were already off */;\
8578cdfb5cSStafford Horne	l.bf	1f							;\
8678cdfb5cSStafford Horne	 l.nop								;\
8778cdfb5cSStafford Horne	TRACE_IRQS_SAVE(r4,trace_hardirqs_off)				;\
8878cdfb5cSStafford Horne1:
8978cdfb5cSStafford Horne#else
9078cdfb5cSStafford Horne#define TRACE_IRQS_OFF
9178cdfb5cSStafford Horne#define TRACE_IRQS_ON
9278cdfb5cSStafford Horne#define TRACE_IRQS_OFF_ENTRY
9378cdfb5cSStafford Horne#define TRACE_IRQS_ON_SYSCALL
9478cdfb5cSStafford Horne#endif
9578cdfb5cSStafford Horne
969d02a428SJonas Bonn/*
979d02a428SJonas Bonn * We need to disable interrupts at beginning of RESTORE_ALL
989d02a428SJonas Bonn * since interrupt might come in after we've loaded EPC return address
999d02a428SJonas Bonn * and overwrite EPC with address somewhere in RESTORE_ALL
1009d02a428SJonas Bonn * which is of course wrong!
1019d02a428SJonas Bonn */
1029d02a428SJonas Bonn
1039d02a428SJonas Bonn#define RESTORE_ALL						\
1049d02a428SJonas Bonn	DISABLE_INTERRUPTS(r3,r4)				;\
1059d02a428SJonas Bonn	l.lwz   r3,PT_PC(r1)					;\
1069d02a428SJonas Bonn	l.mtspr r0,r3,SPR_EPCR_BASE				;\
1079d02a428SJonas Bonn	l.lwz   r3,PT_SR(r1)					;\
1089d02a428SJonas Bonn	l.mtspr r0,r3,SPR_ESR_BASE				;\
10963d7f9f1SStafford Horne	l.lwz	r3,PT_FPCSR(r1)					;\
11063d7f9f1SStafford Horne	l.mtspr	r0,r3,SPR_FPCSR					;\
1119d02a428SJonas Bonn	l.lwz   r2,PT_GPR2(r1)					;\
1129d02a428SJonas Bonn	l.lwz   r3,PT_GPR3(r1)					;\
1139d02a428SJonas Bonn	l.lwz   r4,PT_GPR4(r1)					;\
1149d02a428SJonas Bonn	l.lwz   r5,PT_GPR5(r1)					;\
1159d02a428SJonas Bonn	l.lwz   r6,PT_GPR6(r1)					;\
1169d02a428SJonas Bonn	l.lwz   r7,PT_GPR7(r1)					;\
1179d02a428SJonas Bonn	l.lwz   r8,PT_GPR8(r1)					;\
1189d02a428SJonas Bonn	l.lwz   r9,PT_GPR9(r1)					;\
1199d02a428SJonas Bonn	l.lwz   r10,PT_GPR10(r1)					;\
1209d02a428SJonas Bonn	l.lwz   r11,PT_GPR11(r1)					;\
1219d02a428SJonas Bonn	l.lwz   r12,PT_GPR12(r1)					;\
1229d02a428SJonas Bonn	l.lwz   r13,PT_GPR13(r1)					;\
1239d02a428SJonas Bonn	l.lwz   r14,PT_GPR14(r1)					;\
1249d02a428SJonas Bonn	l.lwz   r15,PT_GPR15(r1)					;\
1259d02a428SJonas Bonn	l.lwz   r16,PT_GPR16(r1)					;\
1269d02a428SJonas Bonn	l.lwz   r17,PT_GPR17(r1)					;\
1279d02a428SJonas Bonn	l.lwz   r18,PT_GPR18(r1)					;\
1289d02a428SJonas Bonn	l.lwz   r19,PT_GPR19(r1)					;\
1299d02a428SJonas Bonn	l.lwz   r20,PT_GPR20(r1)					;\
1309d02a428SJonas Bonn	l.lwz   r21,PT_GPR21(r1)					;\
1319d02a428SJonas Bonn	l.lwz   r22,PT_GPR22(r1)					;\
1329d02a428SJonas Bonn	l.lwz   r23,PT_GPR23(r1)					;\
1339d02a428SJonas Bonn	l.lwz   r24,PT_GPR24(r1)					;\
1349d02a428SJonas Bonn	l.lwz   r25,PT_GPR25(r1)					;\
1359d02a428SJonas Bonn	l.lwz   r26,PT_GPR26(r1)					;\
1369d02a428SJonas Bonn	l.lwz   r27,PT_GPR27(r1)					;\
1379d02a428SJonas Bonn	l.lwz   r28,PT_GPR28(r1)					;\
1389d02a428SJonas Bonn	l.lwz   r29,PT_GPR29(r1)					;\
1399d02a428SJonas Bonn	l.lwz   r30,PT_GPR30(r1)					;\
1409d02a428SJonas Bonn	l.lwz   r31,PT_GPR31(r1)					;\
1419d02a428SJonas Bonn	l.lwz   r1,PT_SP(r1)					;\
1429d02a428SJonas Bonn	l.rfe
1439d02a428SJonas Bonn
1449d02a428SJonas Bonn
1459d02a428SJonas Bonn#define EXCEPTION_ENTRY(handler)				\
1469d02a428SJonas Bonn	.global	handler						;\
1479d02a428SJonas Bonnhandler:							;\
1489d02a428SJonas Bonn	/* r1, EPCR, ESR a already saved */			;\
1499d02a428SJonas Bonn	l.sw	PT_GPR2(r1),r2					;\
1509d02a428SJonas Bonn	l.sw    PT_GPR3(r1),r3					;\
1519d02a428SJonas Bonn	/* r4 already save */					;\
1529d02a428SJonas Bonn	l.sw    PT_GPR5(r1),r5					;\
1539d02a428SJonas Bonn	l.sw    PT_GPR6(r1),r6					;\
1549d02a428SJonas Bonn	l.sw    PT_GPR7(r1),r7					;\
1559d02a428SJonas Bonn	l.sw    PT_GPR8(r1),r8					;\
1569d02a428SJonas Bonn	l.sw    PT_GPR9(r1),r9					;\
1579d02a428SJonas Bonn	/* r10 already saved */					;\
1589d02a428SJonas Bonn	l.sw    PT_GPR11(r1),r11					;\
1599d02a428SJonas Bonn	/* r12 already saved */					;\
1609d02a428SJonas Bonn	l.sw    PT_GPR13(r1),r13					;\
1619d02a428SJonas Bonn	l.sw    PT_GPR14(r1),r14					;\
1629d02a428SJonas Bonn	l.sw    PT_GPR15(r1),r15					;\
1639d02a428SJonas Bonn	l.sw    PT_GPR16(r1),r16					;\
1649d02a428SJonas Bonn	l.sw    PT_GPR17(r1),r17					;\
1659d02a428SJonas Bonn	l.sw    PT_GPR18(r1),r18					;\
1669d02a428SJonas Bonn	l.sw    PT_GPR19(r1),r19					;\
1679d02a428SJonas Bonn	l.sw    PT_GPR20(r1),r20					;\
1689d02a428SJonas Bonn	l.sw    PT_GPR21(r1),r21					;\
1699d02a428SJonas Bonn	l.sw    PT_GPR22(r1),r22					;\
1709d02a428SJonas Bonn	l.sw    PT_GPR23(r1),r23					;\
1719d02a428SJonas Bonn	l.sw    PT_GPR24(r1),r24					;\
1729d02a428SJonas Bonn	l.sw    PT_GPR25(r1),r25					;\
1739d02a428SJonas Bonn	l.sw    PT_GPR26(r1),r26					;\
1749d02a428SJonas Bonn	l.sw    PT_GPR27(r1),r27					;\
1759d02a428SJonas Bonn	l.sw    PT_GPR28(r1),r28					;\
1769d02a428SJonas Bonn	l.sw    PT_GPR29(r1),r29					;\
1779d02a428SJonas Bonn	/* r30 already save */					;\
1789d02a428SJonas Bonn	l.sw    PT_GPR31(r1),r31					;\
17978cdfb5cSStafford Horne	TRACE_IRQS_OFF_ENTRY						;\
18063d7f9f1SStafford Horne	l.mfspr	r30,r0,SPR_FPCSR				;\
18163d7f9f1SStafford Horne	l.sw	PT_FPCSR(r1),r30				;\
1826cbe5e95SJonas Bonn	/* Store -1 in orig_gpr11 for non-syscall exceptions */	;\
1836cbe5e95SJonas Bonn	l.addi	r30,r0,-1					;\
1846cbe5e95SJonas Bonn	l.sw	PT_ORIG_GPR11(r1),r30
1859d02a428SJonas Bonn
1869d02a428SJonas Bonn#define UNHANDLED_EXCEPTION(handler,vector)			\
1879d02a428SJonas Bonn	.global	handler						;\
1889d02a428SJonas Bonnhandler:							;\
1899d02a428SJonas Bonn	/* r1, EPCR, ESR already saved */			;\
1909d02a428SJonas Bonn	l.sw    PT_GPR2(r1),r2					;\
1919d02a428SJonas Bonn	l.sw    PT_GPR3(r1),r3					;\
1929d02a428SJonas Bonn	l.sw    PT_GPR5(r1),r5					;\
1939d02a428SJonas Bonn	l.sw    PT_GPR6(r1),r6					;\
1949d02a428SJonas Bonn	l.sw    PT_GPR7(r1),r7					;\
1959d02a428SJonas Bonn	l.sw    PT_GPR8(r1),r8					;\
1969d02a428SJonas Bonn	l.sw    PT_GPR9(r1),r9					;\
1979d02a428SJonas Bonn	/* r10 already saved */					;\
1989d02a428SJonas Bonn	l.sw    PT_GPR11(r1),r11					;\
1999d02a428SJonas Bonn	/* r12 already saved */					;\
2009d02a428SJonas Bonn	l.sw    PT_GPR13(r1),r13					;\
2019d02a428SJonas Bonn	l.sw    PT_GPR14(r1),r14					;\
2029d02a428SJonas Bonn	l.sw    PT_GPR15(r1),r15					;\
2039d02a428SJonas Bonn	l.sw    PT_GPR16(r1),r16					;\
2049d02a428SJonas Bonn	l.sw    PT_GPR17(r1),r17					;\
2059d02a428SJonas Bonn	l.sw    PT_GPR18(r1),r18					;\
2069d02a428SJonas Bonn	l.sw    PT_GPR19(r1),r19					;\
2079d02a428SJonas Bonn	l.sw    PT_GPR20(r1),r20					;\
2089d02a428SJonas Bonn	l.sw    PT_GPR21(r1),r21					;\
2099d02a428SJonas Bonn	l.sw    PT_GPR22(r1),r22					;\
2109d02a428SJonas Bonn	l.sw    PT_GPR23(r1),r23					;\
2119d02a428SJonas Bonn	l.sw    PT_GPR24(r1),r24					;\
2129d02a428SJonas Bonn	l.sw    PT_GPR25(r1),r25					;\
2139d02a428SJonas Bonn	l.sw    PT_GPR26(r1),r26					;\
2149d02a428SJonas Bonn	l.sw    PT_GPR27(r1),r27					;\
2159d02a428SJonas Bonn	l.sw    PT_GPR28(r1),r28					;\
2169d02a428SJonas Bonn	l.sw    PT_GPR29(r1),r29					;\
217812489acSStafford Horne	/* r30 already saved */						;\
218812489acSStafford Horne	l.sw    PT_GPR31(r1),r31					;\
2196cbe5e95SJonas Bonn	/* Store -1 in orig_gpr11 for non-syscall exceptions */	;\
2206cbe5e95SJonas Bonn	l.addi	r30,r0,-1					;\
2216cbe5e95SJonas Bonn	l.sw	PT_ORIG_GPR11(r1),r30				;\
22263d7f9f1SStafford Horne	l.mfspr	r30,r0,SPR_FPCSR				;\
22363d7f9f1SStafford Horne	l.sw	PT_FPCSR(r1),r30				;\
2249d02a428SJonas Bonn	l.addi	r3,r1,0						;\
2259d02a428SJonas Bonn	/* r4 is exception EA */				;\
2269d02a428SJonas Bonn	l.addi	r5,r0,vector					;\
2279d02a428SJonas Bonn	l.jal	unhandled_exception				;\
2289d02a428SJonas Bonn	 l.nop							;\
2299d02a428SJonas Bonn	l.j	_ret_from_exception				;\
2309d02a428SJonas Bonn	 l.nop
2319d02a428SJonas Bonn
23263104c06SStefan Kristiansson/* clobbers 'reg' */
23363104c06SStefan Kristiansson#define CLEAR_LWA_FLAG(reg)		\
23463104c06SStefan Kristiansson	l.movhi	reg,hi(lwa_flag)	;\
23563104c06SStefan Kristiansson	l.ori	reg,reg,lo(lwa_flag)	;\
23663104c06SStefan Kristiansson	l.sw	0(reg),r0
2379d02a428SJonas Bonn/*
2389d02a428SJonas Bonn * NOTE: one should never assume that SPR_EPC, SPR_ESR, SPR_EEAR
2399d02a428SJonas Bonn *       contain the same values as when exception we're handling
2409d02a428SJonas Bonn *	 occured. in fact they never do. if you need them use
2419d02a428SJonas Bonn *	 values saved on stack (for SPR_EPC, SPR_ESR) or content
2429d02a428SJonas Bonn *       of r4 (for SPR_EEAR). for details look at EXCEPTION_HANDLE()
24357ce8ba0SGeert Uytterhoeven *       in 'arch/openrisc/kernel/head.S'
2449d02a428SJonas Bonn */
2459d02a428SJonas Bonn
2469d02a428SJonas Bonn/* =====================================================[ exceptions] === */
2479d02a428SJonas Bonn
2489d02a428SJonas Bonn/* ---[ 0x100: RESET exception ]----------------------------------------- */
2499d02a428SJonas Bonn
2509d02a428SJonas BonnEXCEPTION_ENTRY(_tng_kernel_start)
2519d02a428SJonas Bonn	l.jal	_start
2529d02a428SJonas Bonn	 l.andi r0,r0,0
2539d02a428SJonas Bonn
2549d02a428SJonas Bonn/* ---[ 0x200: BUS exception ]------------------------------------------- */
2559d02a428SJonas Bonn
2569d02a428SJonas BonnEXCEPTION_ENTRY(_bus_fault_handler)
25763104c06SStefan Kristiansson	CLEAR_LWA_FLAG(r3)
2589d02a428SJonas Bonn	/* r4: EA of fault (set by EXCEPTION_HANDLE) */
2599d02a428SJonas Bonn	l.jal   do_bus_fault
2609d02a428SJonas Bonn	 l.addi  r3,r1,0 /* pt_regs */
2619d02a428SJonas Bonn
2629d02a428SJonas Bonn	l.j     _ret_from_exception
2639d02a428SJonas Bonn	 l.nop
2649d02a428SJonas Bonn
2659d02a428SJonas Bonn/* ---[ 0x300: Data Page Fault exception ]------------------------------- */
266a81252d7SJonas BonnEXCEPTION_ENTRY(_dtlb_miss_page_fault_handler)
26763104c06SStefan Kristiansson	CLEAR_LWA_FLAG(r3)
268a81252d7SJonas Bonn	l.and	r5,r5,r0
269a81252d7SJonas Bonn	l.j	1f
270a81252d7SJonas Bonn	 l.nop
2719d02a428SJonas Bonn
2729d02a428SJonas BonnEXCEPTION_ENTRY(_data_page_fault_handler)
27363104c06SStefan Kristiansson	CLEAR_LWA_FLAG(r3)
2749d02a428SJonas Bonn	/* set up parameters for do_page_fault */
275a81252d7SJonas Bonn	l.ori	r5,r0,0x300		   // exception vector
276a81252d7SJonas Bonn1:
2779d02a428SJonas Bonn	l.addi  r3,r1,0                    // pt_regs
2789d02a428SJonas Bonn	/* r4 set be EXCEPTION_HANDLE */   // effective address of fault
2799d02a428SJonas Bonn
2809d02a428SJonas Bonn#ifdef CONFIG_OPENRISC_NO_SPR_SR_DSX
2819d02a428SJonas Bonn	l.lwz   r6,PT_PC(r3)               // address of an offending insn
2829d02a428SJonas Bonn	l.lwz   r6,0(r6)                   // instruction that caused pf
2839d02a428SJonas Bonn
2849d02a428SJonas Bonn	l.srli  r6,r6,26                   // check opcode for jump insn
2859d02a428SJonas Bonn	l.sfeqi r6,0                       // l.j
2869d02a428SJonas Bonn	l.bf    8f
2879d02a428SJonas Bonn	l.sfeqi r6,1                       // l.jal
2889d02a428SJonas Bonn	l.bf    8f
2899d02a428SJonas Bonn	l.sfeqi r6,3                       // l.bnf
2909d02a428SJonas Bonn	l.bf    8f
2919d02a428SJonas Bonn	l.sfeqi r6,4                       // l.bf
2929d02a428SJonas Bonn	l.bf    8f
2939d02a428SJonas Bonn	l.sfeqi r6,0x11                    // l.jr
2949d02a428SJonas Bonn	l.bf    8f
2959d02a428SJonas Bonn	l.sfeqi r6,0x12                    // l.jalr
2969d02a428SJonas Bonn	l.bf    8f
2979d02a428SJonas Bonn	 l.nop
2989d02a428SJonas Bonn
2999d02a428SJonas Bonn	l.j     9f
3009d02a428SJonas Bonn	 l.nop
3019d02a428SJonas Bonn
3022ead7abaSStafford Horne8: // offending insn is in delay slot
3039d02a428SJonas Bonn	l.lwz   r6,PT_PC(r3)               // address of an offending insn
3049d02a428SJonas Bonn	l.addi  r6,r6,4
3059d02a428SJonas Bonn	l.lwz   r6,0(r6)                   // instruction that caused pf
3069d02a428SJonas Bonn	l.srli  r6,r6,26                   // get opcode
3072ead7abaSStafford Horne9: // offending instruction opcode loaded in r6
3089d02a428SJonas Bonn
3099d02a428SJonas Bonn#else
3109d02a428SJonas Bonn
311ae15a41aSStafford Horne	l.mfspr r6,r0,SPR_SR               // SR
3129d02a428SJonas Bonn	l.andi  r6,r6,SPR_SR_DSX           // check for delay slot exception
313e6d20c55SStafford Horne	l.sfne  r6,r0                      // exception happened in delay slot
3149d02a428SJonas Bonn	l.bnf   7f
3159d02a428SJonas Bonn	 l.lwz  r6,PT_PC(r3)               // address of an offending insn
3169d02a428SJonas Bonn
3179d02a428SJonas Bonn	l.addi	r6,r6,4                    // offending insn is in delay slot
3189d02a428SJonas Bonn7:
3199d02a428SJonas Bonn	l.lwz   r6,0(r6)                   // instruction that caused pf
3209d02a428SJonas Bonn	l.srli  r6,r6,26                   // check opcode for write access
3219d02a428SJonas Bonn#endif
3229d02a428SJonas Bonn
323cdb75442SStefan Kristiansson	l.sfgeui r6,0x33                   // check opcode for write access
3249d02a428SJonas Bonn	l.bnf   1f
3259d02a428SJonas Bonn	l.sfleui r6,0x37
3269d02a428SJonas Bonn	l.bnf   1f
3279d02a428SJonas Bonn	l.ori   r6,r0,0x1                  // write access
3289d02a428SJonas Bonn	l.j     2f
3299d02a428SJonas Bonn	 l.nop
3309d02a428SJonas Bonn1:	l.ori   r6,r0,0x0                  // !write access
3319d02a428SJonas Bonn2:
3329d02a428SJonas Bonn
33311648cbbSRandy Dunlap	/* call fault.c handler in openrisc/mm/fault.c */
3349d02a428SJonas Bonn	l.jal   do_page_fault
3359d02a428SJonas Bonn	 l.nop
3369d02a428SJonas Bonn	l.j     _ret_from_exception
3379d02a428SJonas Bonn	 l.nop
3389d02a428SJonas Bonn
3399d02a428SJonas Bonn/* ---[ 0x400: Insn Page Fault exception ]------------------------------- */
340a81252d7SJonas BonnEXCEPTION_ENTRY(_itlb_miss_page_fault_handler)
34163104c06SStefan Kristiansson	CLEAR_LWA_FLAG(r3)
342a81252d7SJonas Bonn	l.and	r5,r5,r0
343a81252d7SJonas Bonn	l.j	1f
344a81252d7SJonas Bonn	 l.nop
3459d02a428SJonas Bonn
3469d02a428SJonas BonnEXCEPTION_ENTRY(_insn_page_fault_handler)
34763104c06SStefan Kristiansson	CLEAR_LWA_FLAG(r3)
3489d02a428SJonas Bonn	/* set up parameters for do_page_fault */
349a81252d7SJonas Bonn	l.ori	r5,r0,0x400		   // exception vector
350a81252d7SJonas Bonn1:
3519d02a428SJonas Bonn	l.addi  r3,r1,0                    // pt_regs
3529d02a428SJonas Bonn	/* r4 set be EXCEPTION_HANDLE */   // effective address of fault
3539d02a428SJonas Bonn	l.ori	r6,r0,0x0		   // !write access
3549d02a428SJonas Bonn
35511648cbbSRandy Dunlap	/* call fault.c handler in openrisc/mm/fault.c */
3569d02a428SJonas Bonn	l.jal   do_page_fault
3579d02a428SJonas Bonn	 l.nop
3589d02a428SJonas Bonn	l.j     _ret_from_exception
3599d02a428SJonas Bonn	 l.nop
3609d02a428SJonas Bonn
3619d02a428SJonas Bonn
3629d02a428SJonas Bonn/* ---[ 0x500: Timer exception ]----------------------------------------- */
3639d02a428SJonas Bonn
3649d02a428SJonas BonnEXCEPTION_ENTRY(_timer_handler)
36563104c06SStefan Kristiansson	CLEAR_LWA_FLAG(r3)
3669d02a428SJonas Bonn	l.jal	timer_interrupt
3679d02a428SJonas Bonn	 l.addi r3,r1,0 /* pt_regs */
3689d02a428SJonas Bonn
3699d02a428SJonas Bonn	l.j    _ret_from_intr
3709d02a428SJonas Bonn	 l.nop
3719d02a428SJonas Bonn
372550116d2SMasahiro Yamada/* ---[ 0x600: Alignment exception ]-------------------------------------- */
3739d02a428SJonas Bonn
3749d02a428SJonas BonnEXCEPTION_ENTRY(_alignment_handler)
37563104c06SStefan Kristiansson	CLEAR_LWA_FLAG(r3)
3769d02a428SJonas Bonn	/* r4: EA of fault (set by EXCEPTION_HANDLE) */
3779d02a428SJonas Bonn	l.jal   do_unaligned_access
3789d02a428SJonas Bonn	 l.addi  r3,r1,0 /* pt_regs */
3799d02a428SJonas Bonn
3809d02a428SJonas Bonn	l.j     _ret_from_exception
3819d02a428SJonas Bonn	 l.nop
3829d02a428SJonas Bonn
3839d02a428SJonas Bonn#if 0
384550116d2SMasahiro YamadaEXCEPTION_ENTRY(_alignment_handler)
3854e0385ddSMasahiro Yamada//        l.mfspr r2,r0,SPR_EEAR_BASE     /* Load the effective address */
3869d02a428SJonas Bonn	l.addi	r2,r4,0
3879d02a428SJonas Bonn//        l.mfspr r5,r0,SPR_EPCR_BASE     /* Load the insn address */
3889d02a428SJonas Bonn	l.lwz   r5,PT_PC(r1)
3899d02a428SJonas Bonn
3909d02a428SJonas Bonn	l.lwz   r3,0(r5)                /* Load insn */
3919d02a428SJonas Bonn	l.srli  r4,r3,26                /* Shift left to get the insn opcode */
3929d02a428SJonas Bonn
3939d02a428SJonas Bonn	l.sfeqi r4,0x00                 /* Check if the load/store insn is in delay slot */
3949d02a428SJonas Bonn	l.bf    jmp
3959d02a428SJonas Bonn	l.sfeqi r4,0x01
3969d02a428SJonas Bonn	l.bf    jmp
3979d02a428SJonas Bonn	l.sfeqi r4,0x03
3989d02a428SJonas Bonn	l.bf    jmp
3999d02a428SJonas Bonn	l.sfeqi r4,0x04
4009d02a428SJonas Bonn	l.bf    jmp
4019d02a428SJonas Bonn	l.sfeqi r4,0x11
4029d02a428SJonas Bonn	l.bf    jr
4039d02a428SJonas Bonn	l.sfeqi r4,0x12
4049d02a428SJonas Bonn	l.bf    jr
4059d02a428SJonas Bonn	l.nop
4069d02a428SJonas Bonn	l.j     1f
4079d02a428SJonas Bonn	l.addi  r5,r5,4                 /* Increment PC to get return insn address */
4089d02a428SJonas Bonn
4099d02a428SJonas Bonnjmp:
4109d02a428SJonas Bonn	l.slli  r4,r3,6                 /* Get the signed extended jump length */
4119d02a428SJonas Bonn	l.srai  r4,r4,4
4129d02a428SJonas Bonn
4139d02a428SJonas Bonn	l.lwz   r3,4(r5)                /* Load the real load/store insn */
4149d02a428SJonas Bonn
4159d02a428SJonas Bonn	l.add   r5,r5,r4                /* Calculate jump target address */
4169d02a428SJonas Bonn
4179d02a428SJonas Bonn	l.j     1f
4189d02a428SJonas Bonn	l.srli  r4,r3,26                /* Shift left to get the insn opcode */
4199d02a428SJonas Bonn
4209d02a428SJonas Bonnjr:
4219d02a428SJonas Bonn	l.slli  r4,r3,9                 /* Shift to get the reg nb */
4229d02a428SJonas Bonn	l.andi  r4,r4,0x7c
4239d02a428SJonas Bonn
4249d02a428SJonas Bonn	l.lwz   r3,4(r5)                /* Load the real load/store insn */
4259d02a428SJonas Bonn
4269d02a428SJonas Bonn	l.add   r4,r4,r1                /* Load the jump register value from the stack */
4279d02a428SJonas Bonn	l.lwz   r5,0(r4)
4289d02a428SJonas Bonn
4299d02a428SJonas Bonn	l.srli  r4,r3,26                /* Shift left to get the insn opcode */
4309d02a428SJonas Bonn
4319d02a428SJonas Bonn
4329d02a428SJonas Bonn1:
4339d02a428SJonas Bonn//	  l.mtspr r0,r5,SPR_EPCR_BASE
4349d02a428SJonas Bonn	l.sw	PT_PC(r1),r5
4359d02a428SJonas Bonn
4369d02a428SJonas Bonn	l.sfeqi r4,0x26
4379d02a428SJonas Bonn	l.bf    lhs
4389d02a428SJonas Bonn	l.sfeqi r4,0x25
4399d02a428SJonas Bonn	l.bf    lhz
4409d02a428SJonas Bonn	l.sfeqi r4,0x22
4419d02a428SJonas Bonn	l.bf    lws
4429d02a428SJonas Bonn	l.sfeqi r4,0x21
4439d02a428SJonas Bonn	l.bf    lwz
4449d02a428SJonas Bonn	l.sfeqi r4,0x37
4459d02a428SJonas Bonn	l.bf    sh
4469d02a428SJonas Bonn	l.sfeqi r4,0x35
4479d02a428SJonas Bonn	l.bf    sw
4489d02a428SJonas Bonn	l.nop
4499d02a428SJonas Bonn
4509d02a428SJonas Bonn1:      l.j     1b                      /* I don't know what to do */
4519d02a428SJonas Bonn	l.nop
4529d02a428SJonas Bonn
4539d02a428SJonas Bonnlhs:    l.lbs   r5,0(r2)
4549d02a428SJonas Bonn	l.slli  r5,r5,8
4559d02a428SJonas Bonn	l.lbz   r6,1(r2)
4569d02a428SJonas Bonn	l.or    r5,r5,r6
4579d02a428SJonas Bonn	l.srli  r4,r3,19
4589d02a428SJonas Bonn	l.andi  r4,r4,0x7c
4599d02a428SJonas Bonn	l.add   r4,r4,r1
4609d02a428SJonas Bonn	l.j     align_end
4619d02a428SJonas Bonn	l.sw    0(r4),r5
4629d02a428SJonas Bonn
4639d02a428SJonas Bonnlhz:    l.lbz   r5,0(r2)
4649d02a428SJonas Bonn	l.slli  r5,r5,8
4659d02a428SJonas Bonn	l.lbz   r6,1(r2)
4669d02a428SJonas Bonn	l.or    r5,r5,r6
4679d02a428SJonas Bonn	l.srli  r4,r3,19
4689d02a428SJonas Bonn	l.andi  r4,r4,0x7c
4699d02a428SJonas Bonn	l.add   r4,r4,r1
4709d02a428SJonas Bonn	l.j     align_end
4719d02a428SJonas Bonn	l.sw    0(r4),r5
4729d02a428SJonas Bonn
4739d02a428SJonas Bonnlws:    l.lbs   r5,0(r2)
4749d02a428SJonas Bonn	l.slli  r5,r5,24
4759d02a428SJonas Bonn	l.lbz   r6,1(r2)
4769d02a428SJonas Bonn	l.slli  r6,r6,16
4779d02a428SJonas Bonn	l.or    r5,r5,r6
4789d02a428SJonas Bonn	l.lbz   r6,2(r2)
4799d02a428SJonas Bonn	l.slli  r6,r6,8
4809d02a428SJonas Bonn	l.or    r5,r5,r6
4819d02a428SJonas Bonn	l.lbz   r6,3(r2)
4829d02a428SJonas Bonn	l.or    r5,r5,r6
4839d02a428SJonas Bonn	l.srli  r4,r3,19
4849d02a428SJonas Bonn	l.andi  r4,r4,0x7c
4859d02a428SJonas Bonn	l.add   r4,r4,r1
4869d02a428SJonas Bonn	l.j     align_end
4879d02a428SJonas Bonn	l.sw    0(r4),r5
4889d02a428SJonas Bonn
4899d02a428SJonas Bonnlwz:    l.lbz   r5,0(r2)
4909d02a428SJonas Bonn	l.slli  r5,r5,24
4919d02a428SJonas Bonn	l.lbz   r6,1(r2)
4929d02a428SJonas Bonn	l.slli  r6,r6,16
4939d02a428SJonas Bonn	l.or    r5,r5,r6
4949d02a428SJonas Bonn	l.lbz   r6,2(r2)
4959d02a428SJonas Bonn	l.slli  r6,r6,8
4969d02a428SJonas Bonn	l.or    r5,r5,r6
4979d02a428SJonas Bonn	l.lbz   r6,3(r2)
4989d02a428SJonas Bonn	l.or    r5,r5,r6
4999d02a428SJonas Bonn	l.srli  r4,r3,19
5009d02a428SJonas Bonn	l.andi  r4,r4,0x7c
5019d02a428SJonas Bonn	l.add   r4,r4,r1
5029d02a428SJonas Bonn	l.j     align_end
5039d02a428SJonas Bonn	l.sw    0(r4),r5
5049d02a428SJonas Bonn
5059d02a428SJonas Bonnsh:
5069d02a428SJonas Bonn	l.srli  r4,r3,9
5079d02a428SJonas Bonn	l.andi  r4,r4,0x7c
5089d02a428SJonas Bonn	l.add   r4,r4,r1
5099d02a428SJonas Bonn	l.lwz   r5,0(r4)
5109d02a428SJonas Bonn	l.sb    1(r2),r5
5119d02a428SJonas Bonn	l.srli  r5,r5,8
5129d02a428SJonas Bonn	l.j     align_end
5139d02a428SJonas Bonn	l.sb    0(r2),r5
5149d02a428SJonas Bonn
5159d02a428SJonas Bonnsw:
5169d02a428SJonas Bonn	l.srli  r4,r3,9
5179d02a428SJonas Bonn	l.andi  r4,r4,0x7c
5189d02a428SJonas Bonn	l.add   r4,r4,r1
5199d02a428SJonas Bonn	l.lwz   r5,0(r4)
5209d02a428SJonas Bonn	l.sb    3(r2),r5
5219d02a428SJonas Bonn	l.srli  r5,r5,8
5229d02a428SJonas Bonn	l.sb    2(r2),r5
5239d02a428SJonas Bonn	l.srli  r5,r5,8
5249d02a428SJonas Bonn	l.sb    1(r2),r5
5259d02a428SJonas Bonn	l.srli  r5,r5,8
5269d02a428SJonas Bonn	l.j     align_end
5279d02a428SJonas Bonn	l.sb    0(r2),r5
5289d02a428SJonas Bonn
5299d02a428SJonas Bonnalign_end:
5309d02a428SJonas Bonn	l.j    _ret_from_intr
5319d02a428SJonas Bonn	l.nop
5329d02a428SJonas Bonn#endif
5339d02a428SJonas Bonn
5349d02a428SJonas Bonn/* ---[ 0x700: Illegal insn exception ]---------------------------------- */
5359d02a428SJonas Bonn
5369d02a428SJonas BonnEXCEPTION_ENTRY(_illegal_instruction_handler)
5379d02a428SJonas Bonn	/* r4: EA of fault (set by EXCEPTION_HANDLE) */
5389d02a428SJonas Bonn	l.jal   do_illegal_instruction
5399d02a428SJonas Bonn	 l.addi  r3,r1,0 /* pt_regs */
5409d02a428SJonas Bonn
5419d02a428SJonas Bonn	l.j     _ret_from_exception
5429d02a428SJonas Bonn	 l.nop
5439d02a428SJonas Bonn
5449d02a428SJonas Bonn/* ---[ 0x800: External interrupt exception ]---------------------------- */
5459d02a428SJonas Bonn
5469d02a428SJonas BonnEXCEPTION_ENTRY(_external_irq_handler)
5479d02a428SJonas Bonn#ifdef CONFIG_OPENRISC_ESR_EXCEPTION_BUG_CHECK
5489d02a428SJonas Bonn	l.lwz	r4,PT_SR(r1)		// were interrupts enabled ?
5499d02a428SJonas Bonn	l.andi	r4,r4,SPR_SR_IEE
5509d02a428SJonas Bonn	l.sfeqi	r4,0
5519d02a428SJonas Bonn	l.bnf	1f			// ext irq enabled, all ok.
5529d02a428SJonas Bonn	l.nop
5539d02a428SJonas Bonn
554946e1052SRandy Dunlap#ifdef CONFIG_PRINTK
5559d02a428SJonas Bonn	l.addi  r1,r1,-0x8
5569d02a428SJonas Bonn	l.movhi r3,hi(42f)
5579d02a428SJonas Bonn	l.ori	r3,r3,lo(42f)
5589d02a428SJonas Bonn	l.sw    0x0(r1),r3
55933701557SChris Down	l.jal   _printk
5609d02a428SJonas Bonn	l.sw    0x4(r1),r4
5619d02a428SJonas Bonn	l.addi  r1,r1,0x8
5629d02a428SJonas Bonn
5639d02a428SJonas Bonn	.section .rodata, "a"
5649d02a428SJonas Bonn42:
5659d02a428SJonas Bonn		.string "\n\rESR interrupt bug: in _external_irq_handler (ESR %x)\n\r"
5669d02a428SJonas Bonn		.align 4
5679d02a428SJonas Bonn	.previous
568946e1052SRandy Dunlap#endif
5699d02a428SJonas Bonn
5709d02a428SJonas Bonn	l.ori	r4,r4,SPR_SR_IEE	// fix the bug
5719d02a428SJonas Bonn//	l.sw	PT_SR(r1),r4
5729d02a428SJonas Bonn1:
5739d02a428SJonas Bonn#endif
57463104c06SStefan Kristiansson	CLEAR_LWA_FLAG(r3)
5759d02a428SJonas Bonn	l.addi	r3,r1,0
576418360b2SMark Rutland	l.movhi	r8,hi(generic_handle_arch_irq)
577418360b2SMark Rutland	l.ori	r8,r8,lo(generic_handle_arch_irq)
5789d02a428SJonas Bonn	l.jalr r8
5799d02a428SJonas Bonn	l.nop
5809d02a428SJonas Bonn	l.j    _ret_from_intr
5819d02a428SJonas Bonn	l.nop
5829d02a428SJonas Bonn
5839d02a428SJonas Bonn/* ---[ 0x900: DTLB miss exception ]------------------------------------- */
5849d02a428SJonas Bonn
5859d02a428SJonas Bonn
5869d02a428SJonas Bonn/* ---[ 0xa00: ITLB miss exception ]------------------------------------- */
5879d02a428SJonas Bonn
5889d02a428SJonas Bonn
5899d02a428SJonas Bonn/* ---[ 0xb00: Range exception ]----------------------------------------- */
5909d02a428SJonas Bonn
5919d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0xb00,0xb00)
5929d02a428SJonas Bonn
5939d02a428SJonas Bonn/* ---[ 0xc00: Syscall exception ]--------------------------------------- */
5949d02a428SJonas Bonn
5959d02a428SJonas Bonn/*
5969d02a428SJonas Bonn * Syscalls are a special type of exception in that they are
5979d02a428SJonas Bonn * _explicitly_ invoked by userspace and can therefore be
5989d02a428SJonas Bonn * held to conform to the same ABI as normal functions with
5999d02a428SJonas Bonn * respect to whether registers are preserved across the call
6009d02a428SJonas Bonn * or not.
6019d02a428SJonas Bonn */
6029d02a428SJonas Bonn
6039d02a428SJonas Bonn/* Upon syscall entry we just save the callee-saved registers
6049d02a428SJonas Bonn * and not the call-clobbered ones.
6059d02a428SJonas Bonn */
6069d02a428SJonas Bonn
6079d02a428SJonas Bonn_string_syscall_return:
608a0a94bc9SStafford Horne	.string "syscall r9:0x%08x -> syscall(%ld) return %ld\0"
6099d02a428SJonas Bonn	.align 4
6109d02a428SJonas Bonn
6119d02a428SJonas BonnENTRY(_sys_call_handler)
6129d02a428SJonas Bonn	/* r1, EPCR, ESR a already saved */
6139d02a428SJonas Bonn	l.sw	PT_GPR2(r1),r2
6149d02a428SJonas Bonn	/* r3-r8 must be saved because syscall restart relies
6159d02a428SJonas Bonn	 * on us being able to restart the syscall args... technically
6169d02a428SJonas Bonn	 * they should be clobbered, otherwise
6179d02a428SJonas Bonn	 */
6189d02a428SJonas Bonn	l.sw    PT_GPR3(r1),r3
61963104c06SStefan Kristiansson	/*
62063104c06SStefan Kristiansson	 * r4 already saved
62163104c06SStefan Kristiansson	 * r4 holds the EEAR address of the fault, use it as screatch reg and
62263104c06SStefan Kristiansson	 * then load the original r4
62363104c06SStefan Kristiansson	 */
62463104c06SStefan Kristiansson	CLEAR_LWA_FLAG(r4)
6259d02a428SJonas Bonn	l.lwz	r4,PT_GPR4(r1)
6269d02a428SJonas Bonn	l.sw    PT_GPR5(r1),r5
6279d02a428SJonas Bonn	l.sw    PT_GPR6(r1),r6
6289d02a428SJonas Bonn	l.sw    PT_GPR7(r1),r7
6299d02a428SJonas Bonn	l.sw    PT_GPR8(r1),r8
6309d02a428SJonas Bonn	l.sw    PT_GPR9(r1),r9
6319d02a428SJonas Bonn	/* r10 already saved */
6329d02a428SJonas Bonn	l.sw    PT_GPR11(r1),r11
6336cbe5e95SJonas Bonn	/* orig_gpr11 must be set for syscalls */
6349d02a428SJonas Bonn	l.sw    PT_ORIG_GPR11(r1),r11
6359d02a428SJonas Bonn	/* r12,r13 already saved */
6369d02a428SJonas Bonn
6379d02a428SJonas Bonn	/* r14-r28 (even) aren't touched by the syscall fast path below
6389d02a428SJonas Bonn	 * so we don't need to save them.  However, the functions that return
6399d02a428SJonas Bonn	 * to userspace via a call to switch() DO need to save these because
6409d02a428SJonas Bonn	 * switch() effectively clobbers them... saving these registers for
6419d02a428SJonas Bonn	 * such functions is handled in their syscall wrappers (see fork, vfork,
6429d02a428SJonas Bonn	 * and clone, below).
6439d02a428SJonas Bonn
6449d02a428SJonas Bonn	/* r30 is the only register we clobber in the fast path */
6459d02a428SJonas Bonn	/* r30 already saved */
6469d02a428SJonas Bonn/*	l.sw    PT_GPR30(r1),r30 */
6479d02a428SJonas Bonn
6489d02a428SJonas Bonn_syscall_check_trace_enter:
64978cdfb5cSStafford Horne	/* syscalls run with interrupts enabled */
65078cdfb5cSStafford Horne	TRACE_IRQS_ON_SYSCALL
65178cdfb5cSStafford Horne	ENABLE_INTERRUPTS(r29)		// enable interrupts, r29 is temp
65278cdfb5cSStafford Horne
6539d02a428SJonas Bonn	/* If TIF_SYSCALL_TRACE is set, then we want to do syscall tracing */
6549d02a428SJonas Bonn	l.lwz	r30,TI_FLAGS(r10)
6559d02a428SJonas Bonn	l.andi	r30,r30,_TIF_SYSCALL_TRACE
6569d02a428SJonas Bonn	l.sfne	r30,r0
6579d02a428SJonas Bonn	l.bf	_syscall_trace_enter
6589d02a428SJonas Bonn	 l.nop
6599d02a428SJonas Bonn
6609d02a428SJonas Bonn_syscall_check:
6619d02a428SJonas Bonn	/* Ensure that the syscall number is reasonable */
6629d02a428SJonas Bonn	l.sfgeui r11,__NR_syscalls
6639d02a428SJonas Bonn	l.bf	_syscall_badsys
6649d02a428SJonas Bonn	 l.nop
6659d02a428SJonas Bonn
6669d02a428SJonas Bonn_syscall_call:
6679d02a428SJonas Bonn	l.movhi r29,hi(sys_call_table)
6689d02a428SJonas Bonn	l.ori   r29,r29,lo(sys_call_table)
6699d02a428SJonas Bonn	l.slli  r11,r11,2
6709d02a428SJonas Bonn	l.add   r29,r29,r11
6719d02a428SJonas Bonn	l.lwz   r29,0(r29)
6729d02a428SJonas Bonn
6739d02a428SJonas Bonn	l.jalr  r29
6749d02a428SJonas Bonn	 l.nop
6759d02a428SJonas Bonn
6769d02a428SJonas Bonn_syscall_return:
6779d02a428SJonas Bonn	/* All syscalls return here... just pay attention to ret_from_fork
6789d02a428SJonas Bonn	 * which does it in a round-about way.
6799d02a428SJonas Bonn	 */
6809d02a428SJonas Bonn	l.sw    PT_GPR11(r1),r11           // save return value
6819d02a428SJonas Bonn
6829d02a428SJonas Bonn#if 0
6839d02a428SJonas Bonn_syscall_debug:
6849d02a428SJonas Bonn	l.movhi r3,hi(_string_syscall_return)
6859d02a428SJonas Bonn	l.ori   r3,r3,lo(_string_syscall_return)
686a0a94bc9SStafford Horne	l.ori   r27,r0,2
6879d02a428SJonas Bonn	l.sw    -4(r1),r27
6889d02a428SJonas Bonn	l.sw    -8(r1),r11
689a0a94bc9SStafford Horne	l.lwz	r29,PT_ORIG_GPR11(r1)
690a0a94bc9SStafford Horne	l.sw    -12(r1),r29
691a0a94bc9SStafford Horne	l.lwz	r29,PT_GPR9(r1)
692a0a94bc9SStafford Horne	l.sw    -16(r1),r29
69333701557SChris Down	l.movhi r27,hi(_printk)
69433701557SChris Down	l.ori   r27,r27,lo(_printk)
6959d02a428SJonas Bonn	l.jalr  r27
696a0a94bc9SStafford Horne	 l.addi  r1,r1,-16
697a0a94bc9SStafford Horne	l.addi  r1,r1,16
698a0a94bc9SStafford Horne#endif
699a0a94bc9SStafford Horne#if 0
700a0a94bc9SStafford Horne_syscall_show_regs:
701a0a94bc9SStafford Horne	l.movhi r27,hi(show_registers)
702a0a94bc9SStafford Horne	l.ori   r27,r27,lo(show_registers)
703a0a94bc9SStafford Horne	l.jalr  r27
704a0a94bc9SStafford Horne	 l.or	r3,r1,r1
7059d02a428SJonas Bonn#endif
7069d02a428SJonas Bonn
7079d02a428SJonas Bonn_syscall_check_trace_leave:
7089d02a428SJonas Bonn	/* r30 is a callee-saved register so this should still hold the
7099d02a428SJonas Bonn	 * _TIF_SYSCALL_TRACE flag from _syscall_check_trace_enter above...
7109d02a428SJonas Bonn	 * _syscall_trace_leave expects syscall result to be in pt_regs->r11.
7119d02a428SJonas Bonn	 */
7129d02a428SJonas Bonn	l.sfne	r30,r0
7139d02a428SJonas Bonn	l.bf	_syscall_trace_leave
7149d02a428SJonas Bonn	 l.nop
7159d02a428SJonas Bonn
7169d02a428SJonas Bonn/* This is where the exception-return code begins... interrupts need to be
7179d02a428SJonas Bonn * disabled the rest of the way here because we can't afford to miss any
7189d02a428SJonas Bonn * interrupts that set NEED_RESCHED or SIGNALPENDING... really true? */
7199d02a428SJonas Bonn
7209d02a428SJonas Bonn_syscall_check_work:
7219d02a428SJonas Bonn	/* Here we need to disable interrupts */
7229d02a428SJonas Bonn	DISABLE_INTERRUPTS(r27,r29)
72378cdfb5cSStafford Horne	TRACE_IRQS_OFF
7249d02a428SJonas Bonn	l.lwz	r30,TI_FLAGS(r10)
7259d02a428SJonas Bonn	l.andi	r30,r30,_TIF_WORK_MASK
7269d02a428SJonas Bonn	l.sfne	r30,r0
7279d02a428SJonas Bonn
7289d02a428SJonas Bonn	l.bnf	_syscall_resume_userspace
7299d02a428SJonas Bonn	 l.nop
7309d02a428SJonas Bonn
7319d02a428SJonas Bonn	/* Work pending follows a different return path, so we need to
7329d02a428SJonas Bonn	 * make sure that all the call-saved registers get into pt_regs
7339d02a428SJonas Bonn	 * before branching...
7349d02a428SJonas Bonn	 */
7359d02a428SJonas Bonn	l.sw    PT_GPR14(r1),r14
7369d02a428SJonas Bonn	l.sw    PT_GPR16(r1),r16
7379d02a428SJonas Bonn	l.sw    PT_GPR18(r1),r18
7389d02a428SJonas Bonn	l.sw    PT_GPR20(r1),r20
7399d02a428SJonas Bonn	l.sw    PT_GPR22(r1),r22
7409d02a428SJonas Bonn	l.sw    PT_GPR24(r1),r24
7419d02a428SJonas Bonn	l.sw    PT_GPR26(r1),r26
7429d02a428SJonas Bonn	l.sw    PT_GPR28(r1),r28
7439d02a428SJonas Bonn
7449d02a428SJonas Bonn	/* _work_pending needs to be called with interrupts disabled */
7459d02a428SJonas Bonn	l.j	_work_pending
7469d02a428SJonas Bonn	 l.nop
7479d02a428SJonas Bonn
7489d02a428SJonas Bonn_syscall_resume_userspace:
7499d02a428SJonas Bonn//	ENABLE_INTERRUPTS(r29)
7509d02a428SJonas Bonn
7519d02a428SJonas Bonn
7529d02a428SJonas Bonn/* This is the hot path for returning to userspace from a syscall.  If there's
7539d02a428SJonas Bonn * work to be done and the branch to _work_pending was taken above, then the
7549d02a428SJonas Bonn * return to userspace will be done via the normal exception return path...
7559d02a428SJonas Bonn * that path restores _all_ registers and will overwrite the "clobbered"
7569d02a428SJonas Bonn * registers with whatever garbage is in pt_regs -- that's OK because those
7579d02a428SJonas Bonn * registers are clobbered anyway and because the extra work is insignificant
7589d02a428SJonas Bonn * in the context of the extra work that _work_pending is doing.
7599d02a428SJonas Bonn
7609d02a428SJonas Bonn/* Once again, syscalls are special and only guarantee to preserve the
7619d02a428SJonas Bonn * same registers as a normal function call */
7629d02a428SJonas Bonn
7639d02a428SJonas Bonn/* The assumption here is that the registers r14-r28 (even) are untouched and
7649d02a428SJonas Bonn * don't need to be restored... be sure that that's really the case!
7659d02a428SJonas Bonn */
7669d02a428SJonas Bonn
7679d02a428SJonas Bonn/* This is still too much... we should only be restoring what we actually
7689d02a428SJonas Bonn * clobbered... we should even be using 'scratch' (odd) regs above so that
7699d02a428SJonas Bonn * we don't need to restore anything, hardly...
7709d02a428SJonas Bonn */
7719d02a428SJonas Bonn
7729d02a428SJonas Bonn	l.lwz	r2,PT_GPR2(r1)
7739d02a428SJonas Bonn
7749d02a428SJonas Bonn	/* Restore args */
7759d02a428SJonas Bonn	/* r3-r8 are technically clobbered, but syscall restart needs these
7769d02a428SJonas Bonn	 * to be restored...
7779d02a428SJonas Bonn	 */
7789d02a428SJonas Bonn	l.lwz	r3,PT_GPR3(r1)
7799d02a428SJonas Bonn	l.lwz	r4,PT_GPR4(r1)
7809d02a428SJonas Bonn	l.lwz	r5,PT_GPR5(r1)
7819d02a428SJonas Bonn	l.lwz	r6,PT_GPR6(r1)
7829d02a428SJonas Bonn	l.lwz	r7,PT_GPR7(r1)
7839d02a428SJonas Bonn	l.lwz	r8,PT_GPR8(r1)
7849d02a428SJonas Bonn
7859d02a428SJonas Bonn	l.lwz	r9,PT_GPR9(r1)
7869d02a428SJonas Bonn	l.lwz	r10,PT_GPR10(r1)
7879d02a428SJonas Bonn	l.lwz	r11,PT_GPR11(r1)
7889d02a428SJonas Bonn
7899d02a428SJonas Bonn	/* r30 is the only register we clobber in the fast path */
7909d02a428SJonas Bonn	l.lwz	r30,PT_GPR30(r1)
7919d02a428SJonas Bonn
7929d02a428SJonas Bonn	/* Here we use r13-r19 (odd) as scratch regs */
7939d02a428SJonas Bonn	l.lwz   r13,PT_PC(r1)
7949d02a428SJonas Bonn	l.lwz   r15,PT_SR(r1)
7959d02a428SJonas Bonn	l.lwz	r1,PT_SP(r1)
7969d02a428SJonas Bonn	/* Interrupts need to be disabled for setting EPCR and ESR
7979d02a428SJonas Bonn	 * so that another interrupt doesn't come in here and clobber
7989d02a428SJonas Bonn	 * them before we can use them for our l.rfe */
7999d02a428SJonas Bonn	DISABLE_INTERRUPTS(r17,r19)
8009d02a428SJonas Bonn	l.mtspr r0,r13,SPR_EPCR_BASE
8019d02a428SJonas Bonn	l.mtspr r0,r15,SPR_ESR_BASE
8029d02a428SJonas Bonn	l.rfe
8039d02a428SJonas Bonn
8049d02a428SJonas Bonn/* End of hot path!
8059d02a428SJonas Bonn * Keep the below tracing and error handling out of the hot path...
8069d02a428SJonas Bonn*/
8079d02a428SJonas Bonn
8089d02a428SJonas Bonn_syscall_trace_enter:
8099d02a428SJonas Bonn	/* Here we pass pt_regs to do_syscall_trace_enter.  Make sure
8109d02a428SJonas Bonn	 * that function is really getting all the info it needs as
8119d02a428SJonas Bonn	 * pt_regs isn't a complete set of userspace regs, just the
8129d02a428SJonas Bonn	 * ones relevant to the syscall...
8139d02a428SJonas Bonn	 *
8149d02a428SJonas Bonn	 * Note use of delay slot for setting argument.
8159d02a428SJonas Bonn	 */
8169d02a428SJonas Bonn	l.jal	do_syscall_trace_enter
8179d02a428SJonas Bonn	 l.addi	r3,r1,0
8189d02a428SJonas Bonn
8199d02a428SJonas Bonn	/* Restore arguments (not preserved across do_syscall_trace_enter)
8209d02a428SJonas Bonn	 * so that we can do the syscall for real and return to the syscall
8219d02a428SJonas Bonn	 * hot path.
8229d02a428SJonas Bonn	 */
8236cbe5e95SJonas Bonn	l.lwz	r11,PT_GPR11(r1)
8249d02a428SJonas Bonn	l.lwz	r3,PT_GPR3(r1)
8259d02a428SJonas Bonn	l.lwz	r4,PT_GPR4(r1)
8269d02a428SJonas Bonn	l.lwz	r5,PT_GPR5(r1)
8279d02a428SJonas Bonn	l.lwz	r6,PT_GPR6(r1)
8289d02a428SJonas Bonn	l.lwz	r7,PT_GPR7(r1)
8299d02a428SJonas Bonn
8309d02a428SJonas Bonn	l.j	_syscall_check
8319d02a428SJonas Bonn	 l.lwz	r8,PT_GPR8(r1)
8329d02a428SJonas Bonn
8339d02a428SJonas Bonn_syscall_trace_leave:
8349d02a428SJonas Bonn	l.jal	do_syscall_trace_leave
8359d02a428SJonas Bonn	 l.addi	r3,r1,0
8369d02a428SJonas Bonn
8379d02a428SJonas Bonn	l.j	_syscall_check_work
8389d02a428SJonas Bonn	 l.nop
8399d02a428SJonas Bonn
8409d02a428SJonas Bonn_syscall_badsys:
8419d02a428SJonas Bonn	/* Here we effectively pretend to have executed an imaginary
8429d02a428SJonas Bonn	 * syscall that returns -ENOSYS and then return to the regular
8439d02a428SJonas Bonn	 * syscall hot path.
8449d02a428SJonas Bonn	 * Note that "return value" is set in the delay slot...
8459d02a428SJonas Bonn	 */
8469d02a428SJonas Bonn	l.j	_syscall_return
8479d02a428SJonas Bonn	 l.addi	r11,r0,-ENOSYS
8489d02a428SJonas Bonn
8499d02a428SJonas Bonn/******* END SYSCALL HANDLING *******/
8509d02a428SJonas Bonn
851*27267655SStafford Horne/* ---[ 0xd00: Floating Point exception ]-------------------------------- */
8529d02a428SJonas Bonn
853*27267655SStafford HorneEXCEPTION_ENTRY(_fpe_trap_handler)
854*27267655SStafford Horne	CLEAR_LWA_FLAG(r3)
855*27267655SStafford Horne	/* r4: EA of fault (set by EXCEPTION_HANDLE) */
856*27267655SStafford Horne	l.jal   do_fpe_trap
857*27267655SStafford Horne	 l.addi  r3,r1,0 /* pt_regs */
858*27267655SStafford Horne
859*27267655SStafford Horne	l.j     _ret_from_exception
860*27267655SStafford Horne	 l.nop
8619d02a428SJonas Bonn
8629d02a428SJonas Bonn/* ---[ 0xe00: Trap exception ]------------------------------------------ */
8639d02a428SJonas Bonn
8649d02a428SJonas BonnEXCEPTION_ENTRY(_trap_handler)
86563104c06SStefan Kristiansson	CLEAR_LWA_FLAG(r3)
8669d02a428SJonas Bonn	/* r4: EA of fault (set by EXCEPTION_HANDLE) */
8679d02a428SJonas Bonn	l.jal   do_trap
8689d02a428SJonas Bonn	 l.addi  r3,r1,0 /* pt_regs */
8699d02a428SJonas Bonn
8709d02a428SJonas Bonn	l.j     _ret_from_exception
8719d02a428SJonas Bonn	 l.nop
8729d02a428SJonas Bonn
8739d02a428SJonas Bonn/* ---[ 0xf00: Reserved exception ]-------------------------------------- */
8749d02a428SJonas Bonn
8759d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0xf00,0xf00)
8769d02a428SJonas Bonn
8779d02a428SJonas Bonn/* ---[ 0x1000: Reserved exception ]------------------------------------- */
8789d02a428SJonas Bonn
8799d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1000,0x1000)
8809d02a428SJonas Bonn
8819d02a428SJonas Bonn/* ---[ 0x1100: Reserved exception ]------------------------------------- */
8829d02a428SJonas Bonn
8839d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1100,0x1100)
8849d02a428SJonas Bonn
8859d02a428SJonas Bonn/* ---[ 0x1200: Reserved exception ]------------------------------------- */
8869d02a428SJonas Bonn
8879d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1200,0x1200)
8889d02a428SJonas Bonn
8899d02a428SJonas Bonn/* ---[ 0x1300: Reserved exception ]------------------------------------- */
8909d02a428SJonas Bonn
8919d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1300,0x1300)
8929d02a428SJonas Bonn
8939d02a428SJonas Bonn/* ---[ 0x1400: Reserved exception ]------------------------------------- */
8949d02a428SJonas Bonn
8959d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1400,0x1400)
8969d02a428SJonas Bonn
8979d02a428SJonas Bonn/* ---[ 0x1500: Reserved exception ]------------------------------------- */
8989d02a428SJonas Bonn
8999d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1500,0x1500)
9009d02a428SJonas Bonn
9019d02a428SJonas Bonn/* ---[ 0x1600: Reserved exception ]------------------------------------- */
9029d02a428SJonas Bonn
9039d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1600,0x1600)
9049d02a428SJonas Bonn
9059d02a428SJonas Bonn/* ---[ 0x1700: Reserved exception ]------------------------------------- */
9069d02a428SJonas Bonn
9079d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1700,0x1700)
9089d02a428SJonas Bonn
9099d02a428SJonas Bonn/* ---[ 0x1800: Reserved exception ]------------------------------------- */
9109d02a428SJonas Bonn
9119d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1800,0x1800)
9129d02a428SJonas Bonn
9139d02a428SJonas Bonn/* ---[ 0x1900: Reserved exception ]------------------------------------- */
9149d02a428SJonas Bonn
9159d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1900,0x1900)
9169d02a428SJonas Bonn
9179d02a428SJonas Bonn/* ---[ 0x1a00: Reserved exception ]------------------------------------- */
9189d02a428SJonas Bonn
9199d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1a00,0x1a00)
9209d02a428SJonas Bonn
9219d02a428SJonas Bonn/* ---[ 0x1b00: Reserved exception ]------------------------------------- */
9229d02a428SJonas Bonn
9239d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1b00,0x1b00)
9249d02a428SJonas Bonn
9259d02a428SJonas Bonn/* ---[ 0x1c00: Reserved exception ]------------------------------------- */
9269d02a428SJonas Bonn
9279d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1c00,0x1c00)
9289d02a428SJonas Bonn
9299d02a428SJonas Bonn/* ---[ 0x1d00: Reserved exception ]------------------------------------- */
9309d02a428SJonas Bonn
9319d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1d00,0x1d00)
9329d02a428SJonas Bonn
9339d02a428SJonas Bonn/* ---[ 0x1e00: Reserved exception ]------------------------------------- */
9349d02a428SJonas Bonn
9359d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1e00,0x1e00)
9369d02a428SJonas Bonn
9379d02a428SJonas Bonn/* ---[ 0x1f00: Reserved exception ]------------------------------------- */
9389d02a428SJonas Bonn
9399d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1f00,0x1f00)
9409d02a428SJonas Bonn
9419d02a428SJonas Bonn/* ========================================================[ return ] === */
9429d02a428SJonas Bonn
9439d02a428SJonas Bonn_resume_userspace:
9449d02a428SJonas Bonn	DISABLE_INTERRUPTS(r3,r4)
94578cdfb5cSStafford Horne	TRACE_IRQS_OFF
94610f67dbfSJonas Bonn	l.lwz	r4,TI_FLAGS(r10)
94710f67dbfSJonas Bonn	l.andi	r13,r4,_TIF_WORK_MASK
94810f67dbfSJonas Bonn	l.sfeqi	r13,0
94910f67dbfSJonas Bonn	l.bf	_restore_all
9509d02a428SJonas Bonn	 l.nop
9519d02a428SJonas Bonn
95210f67dbfSJonas Bonn_work_pending:
95310f67dbfSJonas Bonn	l.lwz	r5,PT_ORIG_GPR11(r1)
95410f67dbfSJonas Bonn	l.sfltsi r5,0
95510f67dbfSJonas Bonn	l.bnf	1f
95610f67dbfSJonas Bonn	 l.nop
95710f67dbfSJonas Bonn	l.andi	r5,r5,0
95810f67dbfSJonas Bonn1:
95910f67dbfSJonas Bonn	l.jal	do_work_pending
96010f67dbfSJonas Bonn	 l.ori	r3,r1,0			/* pt_regs */
96110f67dbfSJonas Bonn
96210f67dbfSJonas Bonn	l.sfeqi	r11,0
96310f67dbfSJonas Bonn	l.bf	_restore_all
96410f67dbfSJonas Bonn	 l.nop
96510f67dbfSJonas Bonn	l.sfltsi r11,0
96610f67dbfSJonas Bonn	l.bnf	1f
96710f67dbfSJonas Bonn	 l.nop
96810f67dbfSJonas Bonn	l.and	r11,r11,r0
96910f67dbfSJonas Bonn	l.ori	r11,r11,__NR_restart_syscall
97010f67dbfSJonas Bonn	l.j	_syscall_check_trace_enter
97110f67dbfSJonas Bonn	 l.nop
97210f67dbfSJonas Bonn1:
97310f67dbfSJonas Bonn	l.lwz	r11,PT_ORIG_GPR11(r1)
97410f67dbfSJonas Bonn	/* Restore arg registers */
97510f67dbfSJonas Bonn	l.lwz	r3,PT_GPR3(r1)
97610f67dbfSJonas Bonn	l.lwz	r4,PT_GPR4(r1)
97710f67dbfSJonas Bonn	l.lwz	r5,PT_GPR5(r1)
97810f67dbfSJonas Bonn	l.lwz	r6,PT_GPR6(r1)
97910f67dbfSJonas Bonn	l.lwz	r7,PT_GPR7(r1)
98010f67dbfSJonas Bonn	l.j	_syscall_check_trace_enter
98110f67dbfSJonas Bonn	 l.lwz	r8,PT_GPR8(r1)
98210f67dbfSJonas Bonn
9839d02a428SJonas Bonn_restore_all:
98478cdfb5cSStafford Horne#ifdef CONFIG_TRACE_IRQFLAGS
98578cdfb5cSStafford Horne	l.lwz	r4,PT_SR(r1)
98678cdfb5cSStafford Horne	l.andi	r3,r4,(SPR_SR_IEE|SPR_SR_TEE)
98778cdfb5cSStafford Horne	l.sfeq	r3,r0		/* skip trace if irqs were off */
98878cdfb5cSStafford Horne	l.bf	skip_hardirqs_on
98978cdfb5cSStafford Horne	 l.nop
99078cdfb5cSStafford Horne	TRACE_IRQS_ON
99178cdfb5cSStafford Horneskip_hardirqs_on:
99278cdfb5cSStafford Horne#endif
9939d02a428SJonas Bonn	RESTORE_ALL
9949d02a428SJonas Bonn	/* This returns to userspace code */
9959d02a428SJonas Bonn
9969d02a428SJonas Bonn
9979d02a428SJonas BonnENTRY(_ret_from_intr)
9989d02a428SJonas BonnENTRY(_ret_from_exception)
9999d02a428SJonas Bonn	l.lwz	r4,PT_SR(r1)
10009d02a428SJonas Bonn	l.andi	r3,r4,SPR_SR_SM
10019d02a428SJonas Bonn	l.sfeqi	r3,0
10029d02a428SJonas Bonn	l.bnf	_restore_all
10039d02a428SJonas Bonn	 l.nop
10049d02a428SJonas Bonn	l.j	_resume_userspace
10059d02a428SJonas Bonn	 l.nop
10069d02a428SJonas Bonn
10079d02a428SJonas BonnENTRY(ret_from_fork)
10089d02a428SJonas Bonn	l.jal	schedule_tail
10099d02a428SJonas Bonn	 l.nop
10109d02a428SJonas Bonn
1011cbf23cf1SJonas Bonn	/* Check if we are a kernel thread */
1012cbf23cf1SJonas Bonn	l.sfeqi	r20,0
1013cbf23cf1SJonas Bonn	l.bf	1f
1014cbf23cf1SJonas Bonn	 l.nop
1015cbf23cf1SJonas Bonn
1016cbf23cf1SJonas Bonn	/* ...we are a kernel thread so invoke the requested callback */
1017cbf23cf1SJonas Bonn	l.jalr	r20
1018cbf23cf1SJonas Bonn	 l.or	r3,r22,r0
1019cbf23cf1SJonas Bonn
1020cbf23cf1SJonas Bonn1:
10219d02a428SJonas Bonn	/* _syscall_returns expect r11 to contain return value */
10229d02a428SJonas Bonn	l.lwz	r11,PT_GPR11(r1)
10239d02a428SJonas Bonn
10249d02a428SJonas Bonn	/* The syscall fast path return expects call-saved registers
1025840b66c2SStafford Horne	 * r14-r28 to be untouched, so we restore them here as they
10269d02a428SJonas Bonn	 * will have been effectively clobbered when arriving here
10279d02a428SJonas Bonn	 * via the call to switch()
10289d02a428SJonas Bonn	 */
10299d02a428SJonas Bonn	l.lwz	r14,PT_GPR14(r1)
10309d02a428SJonas Bonn	l.lwz	r16,PT_GPR16(r1)
10319d02a428SJonas Bonn	l.lwz	r18,PT_GPR18(r1)
10329d02a428SJonas Bonn	l.lwz	r20,PT_GPR20(r1)
10339d02a428SJonas Bonn	l.lwz	r22,PT_GPR22(r1)
10349d02a428SJonas Bonn	l.lwz	r24,PT_GPR24(r1)
10359d02a428SJonas Bonn	l.lwz	r26,PT_GPR26(r1)
10369d02a428SJonas Bonn	l.lwz	r28,PT_GPR28(r1)
10379d02a428SJonas Bonn
10389d02a428SJonas Bonn	l.j	_syscall_return
10399d02a428SJonas Bonn	 l.nop
10409d02a428SJonas Bonn
10419d02a428SJonas Bonn/* ========================================================[ switch ] === */
10429d02a428SJonas Bonn
10439d02a428SJonas Bonn/*
10449d02a428SJonas Bonn * This routine switches between two different tasks.  The process
10459d02a428SJonas Bonn * state of one is saved on its kernel stack.  Then the state
10469d02a428SJonas Bonn * of the other is restored from its kernel stack.  The memory
10479d02a428SJonas Bonn * management hardware is updated to the second process's state.
10489d02a428SJonas Bonn * Finally, we can return to the second process, via the 'return'.
10499d02a428SJonas Bonn *
10509d02a428SJonas Bonn * Note: there are two ways to get to the "going out" portion
10519d02a428SJonas Bonn * of this code; either by coming in via the entry (_switch)
10529d02a428SJonas Bonn * or via "fork" which must set up an environment equivalent
10539d02a428SJonas Bonn * to the "_switch" path.  If you change this (or in particular, the
10549d02a428SJonas Bonn * SAVE_REGS macro), you'll have to change the fork code also.
10559d02a428SJonas Bonn */
10569d02a428SJonas Bonn
10579d02a428SJonas Bonn
10589d02a428SJonas Bonn/* _switch MUST never lay on page boundry, cause it runs from
10599d02a428SJonas Bonn * effective addresses and beeing interrupted by iTLB miss would kill it.
1060840b66c2SStafford Horne * dTLB miss seems to never accour in the bad place since data accesses
10619d02a428SJonas Bonn * are from task structures which are always page aligned.
10629d02a428SJonas Bonn *
1063840b66c2SStafford Horne * The problem happens in RESTORE_ALL where we first set the EPCR
10649d02a428SJonas Bonn * register, then load the previous register values and only at the end call
10659d02a428SJonas Bonn * the l.rfe instruction. If get TLB miss in beetwen the EPCR register gets
10669d02a428SJonas Bonn * garbled and we end up calling l.rfe with the wrong EPCR. (same probably
10679d02a428SJonas Bonn * holds for ESR)
10689d02a428SJonas Bonn *
10699d02a428SJonas Bonn * To avoid this problems it is sufficient to align _switch to
10709d02a428SJonas Bonn * some nice round number smaller than it's size...
10719d02a428SJonas Bonn */
10729d02a428SJonas Bonn
10739d02a428SJonas Bonn/* ABI rules apply here... we either enter _switch via schedule() or via
10749d02a428SJonas Bonn * an imaginary call to which we shall return at return_from_fork.  Either
10759d02a428SJonas Bonn * way, we are a function call and only need to preserve the callee-saved
10769d02a428SJonas Bonn * registers when we return.  As such, we don't need to save the registers
10779d02a428SJonas Bonn * on the stack that we won't be returning as they were...
10789d02a428SJonas Bonn */
10799d02a428SJonas Bonn
10809d02a428SJonas Bonn	.align 0x400
10819d02a428SJonas BonnENTRY(_switch)
10829d02a428SJonas Bonn	/* We don't store SR as _switch only gets called in a context where
10839d02a428SJonas Bonn	 * the SR will be the same going in and coming out... */
10849d02a428SJonas Bonn
10859d02a428SJonas Bonn	/* Set up new pt_regs struct for saving task state */
10869d02a428SJonas Bonn	l.addi  r1,r1,-(INT_FRAME_SIZE)
10879d02a428SJonas Bonn
10889d02a428SJonas Bonn	/* No need to store r1/PT_SP as it goes into KSP below */
10899d02a428SJonas Bonn	l.sw    PT_GPR2(r1),r2
10909d02a428SJonas Bonn	l.sw    PT_GPR9(r1),r9
1091840b66c2SStafford Horne
1092840b66c2SStafford Horne	/* Save callee-saved registers to the new pt_regs */
10939d02a428SJonas Bonn	l.sw    PT_GPR14(r1),r14
10949d02a428SJonas Bonn	l.sw    PT_GPR16(r1),r16
10959d02a428SJonas Bonn	l.sw    PT_GPR18(r1),r18
10969d02a428SJonas Bonn	l.sw    PT_GPR20(r1),r20
10979d02a428SJonas Bonn	l.sw    PT_GPR22(r1),r22
10989d02a428SJonas Bonn	l.sw    PT_GPR24(r1),r24
10999d02a428SJonas Bonn	l.sw    PT_GPR26(r1),r26
11009d02a428SJonas Bonn	l.sw    PT_GPR28(r1),r28
11019d02a428SJonas Bonn	l.sw    PT_GPR30(r1),r30
11029d02a428SJonas Bonn
110363d7f9f1SStafford Horne	/* Store the old FPU state to new pt_regs */
110463d7f9f1SStafford Horne	l.mfspr	r29,r0,SPR_FPCSR
110563d7f9f1SStafford Horne	l.sw	PT_FPCSR(r1),r29
110663d7f9f1SStafford Horne
11079d02a428SJonas Bonn	l.addi	r11,r10,0			/* Save old 'current' to 'last' return value*/
11089d02a428SJonas Bonn
11099d02a428SJonas Bonn	/* We use thread_info->ksp for storing the address of the above
11109d02a428SJonas Bonn	 * structure so that we can get back to it later... we don't want
11119d02a428SJonas Bonn	 * to lose the value of thread_info->ksp, though, so store it as
11129d02a428SJonas Bonn	 * pt_regs->sp so that we can easily restore it when we are made
11139d02a428SJonas Bonn	 * live again...
11149d02a428SJonas Bonn	 */
11159d02a428SJonas Bonn
11169d02a428SJonas Bonn	/* Save the old value of thread_info->ksp as pt_regs->sp */
11179d02a428SJonas Bonn	l.lwz	r29,TI_KSP(r10)
11189d02a428SJonas Bonn	l.sw	PT_SP(r1),r29
11199d02a428SJonas Bonn
11209d02a428SJonas Bonn	/* Swap kernel stack pointers */
11219d02a428SJonas Bonn	l.sw    TI_KSP(r10),r1			/* Save old stack pointer */
11229d02a428SJonas Bonn	l.or	r10,r4,r0			/* Set up new current_thread_info */
11239d02a428SJonas Bonn	l.lwz   r1,TI_KSP(r10)			/* Load new stack pointer */
11249d02a428SJonas Bonn
11259d02a428SJonas Bonn	/* Restore the old value of thread_info->ksp */
11269d02a428SJonas Bonn	l.lwz	r29,PT_SP(r1)
11279d02a428SJonas Bonn	l.sw	TI_KSP(r10),r29
11289d02a428SJonas Bonn
112963d7f9f1SStafford Horne	/* Restore the old value of FPCSR */
113063d7f9f1SStafford Horne	l.lwz	r29,PT_FPCSR(r1)
113163d7f9f1SStafford Horne	l.mtspr	r0,r29,SPR_FPCSR
113263d7f9f1SStafford Horne
11339d02a428SJonas Bonn	/* ...and restore the registers, except r11 because the return value
11349d02a428SJonas Bonn	 * has already been set above.
11359d02a428SJonas Bonn	 */
11369d02a428SJonas Bonn	l.lwz   r2,PT_GPR2(r1)
11379d02a428SJonas Bonn	l.lwz   r9,PT_GPR9(r1)
11389d02a428SJonas Bonn	/* No need to restore r10 */
11399d02a428SJonas Bonn	/* ...and do not restore r11 */
11409d02a428SJonas Bonn
1141840b66c2SStafford Horne	/* Restore callee-saved registers */
11429d02a428SJonas Bonn	l.lwz   r14,PT_GPR14(r1)
11439d02a428SJonas Bonn	l.lwz   r16,PT_GPR16(r1)
11449d02a428SJonas Bonn	l.lwz   r18,PT_GPR18(r1)
11459d02a428SJonas Bonn	l.lwz   r20,PT_GPR20(r1)
11469d02a428SJonas Bonn	l.lwz   r22,PT_GPR22(r1)
11479d02a428SJonas Bonn	l.lwz   r24,PT_GPR24(r1)
11489d02a428SJonas Bonn	l.lwz   r26,PT_GPR26(r1)
11499d02a428SJonas Bonn	l.lwz   r28,PT_GPR28(r1)
11509d02a428SJonas Bonn	l.lwz   r30,PT_GPR30(r1)
11519d02a428SJonas Bonn
11529d02a428SJonas Bonn	/* Unwind stack to pre-switch state */
11539d02a428SJonas Bonn	l.addi  r1,r1,(INT_FRAME_SIZE)
11549d02a428SJonas Bonn
1155287ad220SJonas Bonn	/* Return via the link-register back to where we 'came from', where
1156287ad220SJonas Bonn	 * that may be either schedule(), ret_from_fork(), or
1157287ad220SJonas Bonn	 * ret_from_kernel_thread().  If we are returning to a new thread,
1158287ad220SJonas Bonn	 * we are expected to have set up the arg to schedule_tail already,
1159287ad220SJonas Bonn	 * hence we do so here unconditionally:
1160287ad220SJonas Bonn	 */
1161ae6fef17SJonas Bonn	l.lwz   r3,TI_TASK(r3)		/* Load 'prev' as schedule_tail arg */
11629d02a428SJonas Bonn	l.jr	r9
11639d02a428SJonas Bonn	 l.nop
11649d02a428SJonas Bonn
11659d02a428SJonas Bonn/* ==================================================================== */
11669d02a428SJonas Bonn
11679d02a428SJonas Bonn/* These all use the delay slot for setting the argument register, so the
11689d02a428SJonas Bonn * jump is always happening after the l.addi instruction.
11699d02a428SJonas Bonn *
11709d02a428SJonas Bonn * These are all just wrappers that don't touch the link-register r9, so the
11719d02a428SJonas Bonn * return from the "real" syscall function will return back to the syscall
11729d02a428SJonas Bonn * code that did the l.jal that brought us here.
11739d02a428SJonas Bonn */
11749d02a428SJonas Bonn
11759d02a428SJonas Bonn/* fork requires that we save all the callee-saved registers because they
11769d02a428SJonas Bonn * are all effectively clobbered by the call to _switch.  Here we store
11779d02a428SJonas Bonn * all the registers that aren't touched by the syscall fast path and thus
11789d02a428SJonas Bonn * weren't saved there.
11799d02a428SJonas Bonn */
11809d02a428SJonas Bonn
11819d02a428SJonas Bonn_fork_save_extra_regs_and_call:
11829d02a428SJonas Bonn	l.sw    PT_GPR14(r1),r14
11839d02a428SJonas Bonn	l.sw    PT_GPR16(r1),r16
11849d02a428SJonas Bonn	l.sw    PT_GPR18(r1),r18
11859d02a428SJonas Bonn	l.sw    PT_GPR20(r1),r20
11869d02a428SJonas Bonn	l.sw    PT_GPR22(r1),r22
11879d02a428SJonas Bonn	l.sw    PT_GPR24(r1),r24
11889d02a428SJonas Bonn	l.sw    PT_GPR26(r1),r26
11899d02a428SJonas Bonn	l.jr	r29
11909d02a428SJonas Bonn	 l.sw    PT_GPR28(r1),r28
11919d02a428SJonas Bonn
119239d91a9eSAl ViroENTRY(__sys_clone)
119339d91a9eSAl Viro	l.movhi	r29,hi(sys_clone)
11949d02a428SJonas Bonn	l.j	_fork_save_extra_regs_and_call
119507baf50aSStafford Horne	 l.ori	r29,r29,lo(sys_clone)
11969d02a428SJonas Bonn
1197433fe39fSStafford HorneENTRY(__sys_clone3)
1198433fe39fSStafford Horne	l.movhi	r29,hi(sys_clone3)
1199433fe39fSStafford Horne	l.j	_fork_save_extra_regs_and_call
1200433fe39fSStafford Horne	 l.ori	r29,r29,lo(sys_clone3)
1201433fe39fSStafford Horne
120239d91a9eSAl ViroENTRY(__sys_fork)
120339d91a9eSAl Viro	l.movhi	r29,hi(sys_fork)
12049d02a428SJonas Bonn	l.j	_fork_save_extra_regs_and_call
120507baf50aSStafford Horne	 l.ori	r29,r29,lo(sys_fork)
12069d02a428SJonas Bonn
12079d02a428SJonas BonnENTRY(sys_rt_sigreturn)
1208c7990219SJonas Bonn	l.jal	_sys_rt_sigreturn
12099d02a428SJonas Bonn	 l.addi	r3,r1,0
1210c7990219SJonas Bonn	l.sfne	r30,r0
1211c7990219SJonas Bonn	l.bnf	_no_syscall_trace
1212c7990219SJonas Bonn	 l.nop
1213c7990219SJonas Bonn	l.jal	do_syscall_trace_leave
1214c7990219SJonas Bonn	 l.addi	r3,r1,0
1215c7990219SJonas Bonn_no_syscall_trace:
1216c7990219SJonas Bonn	l.j	_resume_userspace
1217c7990219SJonas Bonn	 l.nop
12189d02a428SJonas Bonn
12199d02a428SJonas Bonn/* This is a catch-all syscall for atomic instructions for the OpenRISC 1000.
12209d02a428SJonas Bonn * The functions takes a variable number of parameters depending on which
12219d02a428SJonas Bonn * particular flavour of atomic you want... parameter 1 is a flag identifying
12229d02a428SJonas Bonn * the atomic in question.  Currently, this function implements the
12239d02a428SJonas Bonn * following variants:
12249d02a428SJonas Bonn *
12259d02a428SJonas Bonn * XCHG:
12269d02a428SJonas Bonn *  @flag: 1
12279d02a428SJonas Bonn *  @ptr1:
12289d02a428SJonas Bonn *  @ptr2:
12299d02a428SJonas Bonn * Atomically exchange the values in pointers 1 and 2.
12309d02a428SJonas Bonn *
12319d02a428SJonas Bonn */
12329d02a428SJonas Bonn
12339d02a428SJonas BonnENTRY(sys_or1k_atomic)
12349d02a428SJonas Bonn	/* FIXME: This ignores r3 and always does an XCHG */
12359d02a428SJonas Bonn	DISABLE_INTERRUPTS(r17,r19)
1236207e715fSJonas Bonn	l.lwz	r29,0(r4)
1237207e715fSJonas Bonn	l.lwz	r27,0(r5)
1238207e715fSJonas Bonn	l.sw	0(r4),r27
1239207e715fSJonas Bonn	l.sw	0(r5),r29
12409d02a428SJonas Bonn	ENABLE_INTERRUPTS(r17)
12419d02a428SJonas Bonn	l.jr	r9
12429d02a428SJonas Bonn	 l.or	r11,r0,r0
12439d02a428SJonas Bonn
12449d02a428SJonas Bonn/* ============================================================[ EOF ]=== */
1245