xref: /openbmc/linux/arch/openrisc/kernel/entry.S (revision 65fddcfc)
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				;\
1099d02a428SJonas Bonn	l.lwz   r2,PT_GPR2(r1)					;\
1109d02a428SJonas Bonn	l.lwz   r3,PT_GPR3(r1)					;\
1119d02a428SJonas Bonn	l.lwz   r4,PT_GPR4(r1)					;\
1129d02a428SJonas Bonn	l.lwz   r5,PT_GPR5(r1)					;\
1139d02a428SJonas Bonn	l.lwz   r6,PT_GPR6(r1)					;\
1149d02a428SJonas Bonn	l.lwz   r7,PT_GPR7(r1)					;\
1159d02a428SJonas Bonn	l.lwz   r8,PT_GPR8(r1)					;\
1169d02a428SJonas Bonn	l.lwz   r9,PT_GPR9(r1)					;\
1179d02a428SJonas Bonn	l.lwz   r10,PT_GPR10(r1)					;\
1189d02a428SJonas Bonn	l.lwz   r11,PT_GPR11(r1)					;\
1199d02a428SJonas Bonn	l.lwz   r12,PT_GPR12(r1)					;\
1209d02a428SJonas Bonn	l.lwz   r13,PT_GPR13(r1)					;\
1219d02a428SJonas Bonn	l.lwz   r14,PT_GPR14(r1)					;\
1229d02a428SJonas Bonn	l.lwz   r15,PT_GPR15(r1)					;\
1239d02a428SJonas Bonn	l.lwz   r16,PT_GPR16(r1)					;\
1249d02a428SJonas Bonn	l.lwz   r17,PT_GPR17(r1)					;\
1259d02a428SJonas Bonn	l.lwz   r18,PT_GPR18(r1)					;\
1269d02a428SJonas Bonn	l.lwz   r19,PT_GPR19(r1)					;\
1279d02a428SJonas Bonn	l.lwz   r20,PT_GPR20(r1)					;\
1289d02a428SJonas Bonn	l.lwz   r21,PT_GPR21(r1)					;\
1299d02a428SJonas Bonn	l.lwz   r22,PT_GPR22(r1)					;\
1309d02a428SJonas Bonn	l.lwz   r23,PT_GPR23(r1)					;\
1319d02a428SJonas Bonn	l.lwz   r24,PT_GPR24(r1)					;\
1329d02a428SJonas Bonn	l.lwz   r25,PT_GPR25(r1)					;\
1339d02a428SJonas Bonn	l.lwz   r26,PT_GPR26(r1)					;\
1349d02a428SJonas Bonn	l.lwz   r27,PT_GPR27(r1)					;\
1359d02a428SJonas Bonn	l.lwz   r28,PT_GPR28(r1)					;\
1369d02a428SJonas Bonn	l.lwz   r29,PT_GPR29(r1)					;\
1379d02a428SJonas Bonn	l.lwz   r30,PT_GPR30(r1)					;\
1389d02a428SJonas Bonn	l.lwz   r31,PT_GPR31(r1)					;\
1399d02a428SJonas Bonn	l.lwz   r1,PT_SP(r1)					;\
1409d02a428SJonas Bonn	l.rfe
1419d02a428SJonas Bonn
1429d02a428SJonas Bonn
1439d02a428SJonas Bonn#define EXCEPTION_ENTRY(handler)				\
1449d02a428SJonas Bonn	.global	handler						;\
1459d02a428SJonas Bonnhandler:							;\
1469d02a428SJonas Bonn	/* r1, EPCR, ESR a already saved */			;\
1479d02a428SJonas Bonn	l.sw	PT_GPR2(r1),r2					;\
1489d02a428SJonas Bonn	l.sw    PT_GPR3(r1),r3					;\
1499d02a428SJonas Bonn	/* r4 already save */					;\
1509d02a428SJonas Bonn	l.sw    PT_GPR5(r1),r5					;\
1519d02a428SJonas Bonn	l.sw    PT_GPR6(r1),r6					;\
1529d02a428SJonas Bonn	l.sw    PT_GPR7(r1),r7					;\
1539d02a428SJonas Bonn	l.sw    PT_GPR8(r1),r8					;\
1549d02a428SJonas Bonn	l.sw    PT_GPR9(r1),r9					;\
1559d02a428SJonas Bonn	/* r10 already saved */					;\
1569d02a428SJonas Bonn	l.sw    PT_GPR11(r1),r11					;\
1579d02a428SJonas Bonn	/* r12 already saved */					;\
1589d02a428SJonas Bonn	l.sw    PT_GPR13(r1),r13					;\
1599d02a428SJonas Bonn	l.sw    PT_GPR14(r1),r14					;\
1609d02a428SJonas Bonn	l.sw    PT_GPR15(r1),r15					;\
1619d02a428SJonas Bonn	l.sw    PT_GPR16(r1),r16					;\
1629d02a428SJonas Bonn	l.sw    PT_GPR17(r1),r17					;\
1639d02a428SJonas Bonn	l.sw    PT_GPR18(r1),r18					;\
1649d02a428SJonas Bonn	l.sw    PT_GPR19(r1),r19					;\
1659d02a428SJonas Bonn	l.sw    PT_GPR20(r1),r20					;\
1669d02a428SJonas Bonn	l.sw    PT_GPR21(r1),r21					;\
1679d02a428SJonas Bonn	l.sw    PT_GPR22(r1),r22					;\
1689d02a428SJonas Bonn	l.sw    PT_GPR23(r1),r23					;\
1699d02a428SJonas Bonn	l.sw    PT_GPR24(r1),r24					;\
1709d02a428SJonas Bonn	l.sw    PT_GPR25(r1),r25					;\
1719d02a428SJonas Bonn	l.sw    PT_GPR26(r1),r26					;\
1729d02a428SJonas Bonn	l.sw    PT_GPR27(r1),r27					;\
1739d02a428SJonas Bonn	l.sw    PT_GPR28(r1),r28					;\
1749d02a428SJonas Bonn	l.sw    PT_GPR29(r1),r29					;\
1759d02a428SJonas Bonn	/* r30 already save */					;\
1769d02a428SJonas Bonn/*        l.sw    PT_GPR30(r1),r30*/					;\
1779d02a428SJonas Bonn	l.sw    PT_GPR31(r1),r31					;\
17878cdfb5cSStafford Horne	TRACE_IRQS_OFF_ENTRY						;\
1796cbe5e95SJonas Bonn	/* Store -1 in orig_gpr11 for non-syscall exceptions */	;\
1806cbe5e95SJonas Bonn	l.addi	r30,r0,-1					;\
1816cbe5e95SJonas Bonn	l.sw	PT_ORIG_GPR11(r1),r30
1829d02a428SJonas Bonn
1839d02a428SJonas Bonn#define UNHANDLED_EXCEPTION(handler,vector)			\
1849d02a428SJonas Bonn	.global	handler						;\
1859d02a428SJonas Bonnhandler:							;\
1869d02a428SJonas Bonn	/* r1, EPCR, ESR already saved */			;\
1879d02a428SJonas Bonn	l.sw    PT_GPR2(r1),r2					;\
1889d02a428SJonas Bonn	l.sw    PT_GPR3(r1),r3					;\
1899d02a428SJonas Bonn	l.sw    PT_GPR5(r1),r5					;\
1909d02a428SJonas Bonn	l.sw    PT_GPR6(r1),r6					;\
1919d02a428SJonas Bonn	l.sw    PT_GPR7(r1),r7					;\
1929d02a428SJonas Bonn	l.sw    PT_GPR8(r1),r8					;\
1939d02a428SJonas Bonn	l.sw    PT_GPR9(r1),r9					;\
1949d02a428SJonas Bonn	/* r10 already saved */					;\
1959d02a428SJonas Bonn	l.sw    PT_GPR11(r1),r11					;\
1969d02a428SJonas Bonn	/* r12 already saved */					;\
1979d02a428SJonas Bonn	l.sw    PT_GPR13(r1),r13					;\
1989d02a428SJonas Bonn	l.sw    PT_GPR14(r1),r14					;\
1999d02a428SJonas Bonn	l.sw    PT_GPR15(r1),r15					;\
2009d02a428SJonas Bonn	l.sw    PT_GPR16(r1),r16					;\
2019d02a428SJonas Bonn	l.sw    PT_GPR17(r1),r17					;\
2029d02a428SJonas Bonn	l.sw    PT_GPR18(r1),r18					;\
2039d02a428SJonas Bonn	l.sw    PT_GPR19(r1),r19					;\
2049d02a428SJonas Bonn	l.sw    PT_GPR20(r1),r20					;\
2059d02a428SJonas Bonn	l.sw    PT_GPR21(r1),r21					;\
2069d02a428SJonas Bonn	l.sw    PT_GPR22(r1),r22					;\
2079d02a428SJonas Bonn	l.sw    PT_GPR23(r1),r23					;\
2089d02a428SJonas Bonn	l.sw    PT_GPR24(r1),r24					;\
2099d02a428SJonas Bonn	l.sw    PT_GPR25(r1),r25					;\
2109d02a428SJonas Bonn	l.sw    PT_GPR26(r1),r26					;\
2119d02a428SJonas Bonn	l.sw    PT_GPR27(r1),r27					;\
2129d02a428SJonas Bonn	l.sw    PT_GPR28(r1),r28					;\
2139d02a428SJonas Bonn	l.sw    PT_GPR29(r1),r29					;\
2149d02a428SJonas Bonn	/* r31 already saved */					;\
2159d02a428SJonas Bonn	l.sw    PT_GPR30(r1),r30					;\
2169d02a428SJonas Bonn/*        l.sw    PT_GPR31(r1),r31	*/				;\
2176cbe5e95SJonas Bonn	/* Store -1 in orig_gpr11 for non-syscall exceptions */	;\
2186cbe5e95SJonas Bonn	l.addi	r30,r0,-1					;\
2196cbe5e95SJonas Bonn	l.sw	PT_ORIG_GPR11(r1),r30				;\
2209d02a428SJonas Bonn	l.addi	r3,r1,0						;\
2219d02a428SJonas Bonn	/* r4 is exception EA */				;\
2229d02a428SJonas Bonn	l.addi	r5,r0,vector					;\
2239d02a428SJonas Bonn	l.jal	unhandled_exception				;\
2249d02a428SJonas Bonn	 l.nop							;\
2259d02a428SJonas Bonn	l.j	_ret_from_exception				;\
2269d02a428SJonas Bonn	 l.nop
2279d02a428SJonas Bonn
22863104c06SStefan Kristiansson/* clobbers 'reg' */
22963104c06SStefan Kristiansson#define CLEAR_LWA_FLAG(reg)		\
23063104c06SStefan Kristiansson	l.movhi	reg,hi(lwa_flag)	;\
23163104c06SStefan Kristiansson	l.ori	reg,reg,lo(lwa_flag)	;\
23263104c06SStefan Kristiansson	l.sw	0(reg),r0
2339d02a428SJonas Bonn/*
2349d02a428SJonas Bonn * NOTE: one should never assume that SPR_EPC, SPR_ESR, SPR_EEAR
2359d02a428SJonas Bonn *       contain the same values as when exception we're handling
2369d02a428SJonas Bonn *	 occured. in fact they never do. if you need them use
2379d02a428SJonas Bonn *	 values saved on stack (for SPR_EPC, SPR_ESR) or content
2389d02a428SJonas Bonn *       of r4 (for SPR_EEAR). for details look at EXCEPTION_HANDLE()
23957ce8ba0SGeert Uytterhoeven *       in 'arch/openrisc/kernel/head.S'
2409d02a428SJonas Bonn */
2419d02a428SJonas Bonn
2429d02a428SJonas Bonn/* =====================================================[ exceptions] === */
2439d02a428SJonas Bonn
2449d02a428SJonas Bonn/* ---[ 0x100: RESET exception ]----------------------------------------- */
2459d02a428SJonas Bonn
2469d02a428SJonas BonnEXCEPTION_ENTRY(_tng_kernel_start)
2479d02a428SJonas Bonn	l.jal	_start
2489d02a428SJonas Bonn	 l.andi r0,r0,0
2499d02a428SJonas Bonn
2509d02a428SJonas Bonn/* ---[ 0x200: BUS exception ]------------------------------------------- */
2519d02a428SJonas Bonn
2529d02a428SJonas BonnEXCEPTION_ENTRY(_bus_fault_handler)
25363104c06SStefan Kristiansson	CLEAR_LWA_FLAG(r3)
2549d02a428SJonas Bonn	/* r4: EA of fault (set by EXCEPTION_HANDLE) */
2559d02a428SJonas Bonn	l.jal   do_bus_fault
2569d02a428SJonas Bonn	 l.addi  r3,r1,0 /* pt_regs */
2579d02a428SJonas Bonn
2589d02a428SJonas Bonn	l.j     _ret_from_exception
2599d02a428SJonas Bonn	 l.nop
2609d02a428SJonas Bonn
2619d02a428SJonas Bonn/* ---[ 0x300: Data Page Fault exception ]------------------------------- */
262a81252d7SJonas BonnEXCEPTION_ENTRY(_dtlb_miss_page_fault_handler)
26363104c06SStefan Kristiansson	CLEAR_LWA_FLAG(r3)
264a81252d7SJonas Bonn	l.and	r5,r5,r0
265a81252d7SJonas Bonn	l.j	1f
266a81252d7SJonas Bonn	 l.nop
2679d02a428SJonas Bonn
2689d02a428SJonas BonnEXCEPTION_ENTRY(_data_page_fault_handler)
26963104c06SStefan Kristiansson	CLEAR_LWA_FLAG(r3)
2709d02a428SJonas Bonn	/* set up parameters for do_page_fault */
271a81252d7SJonas Bonn	l.ori	r5,r0,0x300		   // exception vector
272a81252d7SJonas Bonn1:
2739d02a428SJonas Bonn	l.addi  r3,r1,0                    // pt_regs
2749d02a428SJonas Bonn	/* r4 set be EXCEPTION_HANDLE */   // effective address of fault
2759d02a428SJonas Bonn
2769d02a428SJonas Bonn#ifdef CONFIG_OPENRISC_NO_SPR_SR_DSX
2779d02a428SJonas Bonn	l.lwz   r6,PT_PC(r3)               // address of an offending insn
2789d02a428SJonas Bonn	l.lwz   r6,0(r6)                   // instruction that caused pf
2799d02a428SJonas Bonn
2809d02a428SJonas Bonn	l.srli  r6,r6,26                   // check opcode for jump insn
2819d02a428SJonas Bonn	l.sfeqi r6,0                       // l.j
2829d02a428SJonas Bonn	l.bf    8f
2839d02a428SJonas Bonn	l.sfeqi r6,1                       // l.jal
2849d02a428SJonas Bonn	l.bf    8f
2859d02a428SJonas Bonn	l.sfeqi r6,3                       // l.bnf
2869d02a428SJonas Bonn	l.bf    8f
2879d02a428SJonas Bonn	l.sfeqi r6,4                       // l.bf
2889d02a428SJonas Bonn	l.bf    8f
2899d02a428SJonas Bonn	l.sfeqi r6,0x11                    // l.jr
2909d02a428SJonas Bonn	l.bf    8f
2919d02a428SJonas Bonn	l.sfeqi r6,0x12                    // l.jalr
2929d02a428SJonas Bonn	l.bf    8f
2939d02a428SJonas Bonn	 l.nop
2949d02a428SJonas Bonn
2959d02a428SJonas Bonn	l.j     9f
2969d02a428SJonas Bonn	 l.nop
2979d02a428SJonas Bonn
2982ead7abaSStafford Horne8: // offending insn is in delay slot
2999d02a428SJonas Bonn	l.lwz   r6,PT_PC(r3)               // address of an offending insn
3009d02a428SJonas Bonn	l.addi  r6,r6,4
3019d02a428SJonas Bonn	l.lwz   r6,0(r6)                   // instruction that caused pf
3029d02a428SJonas Bonn	l.srli  r6,r6,26                   // get opcode
3032ead7abaSStafford Horne9: // offending instruction opcode loaded in r6
3049d02a428SJonas Bonn
3059d02a428SJonas Bonn#else
3069d02a428SJonas Bonn
307ae15a41aSStafford Horne	l.mfspr r6,r0,SPR_SR               // SR
3089d02a428SJonas Bonn	l.andi  r6,r6,SPR_SR_DSX           // check for delay slot exception
309e6d20c55SStafford Horne	l.sfne  r6,r0                      // exception happened in delay slot
3109d02a428SJonas Bonn	l.bnf   7f
3119d02a428SJonas Bonn	 l.lwz  r6,PT_PC(r3)               // address of an offending insn
3129d02a428SJonas Bonn
3139d02a428SJonas Bonn	l.addi	r6,r6,4                    // offending insn is in delay slot
3149d02a428SJonas Bonn7:
3159d02a428SJonas Bonn	l.lwz   r6,0(r6)                   // instruction that caused pf
3169d02a428SJonas Bonn	l.srli  r6,r6,26                   // check opcode for write access
3179d02a428SJonas Bonn#endif
3189d02a428SJonas Bonn
319cdb75442SStefan Kristiansson	l.sfgeui r6,0x33                   // check opcode for write access
3209d02a428SJonas Bonn	l.bnf   1f
3219d02a428SJonas Bonn	l.sfleui r6,0x37
3229d02a428SJonas Bonn	l.bnf   1f
3239d02a428SJonas Bonn	l.ori   r6,r0,0x1                  // write access
3249d02a428SJonas Bonn	l.j     2f
3259d02a428SJonas Bonn	 l.nop
3269d02a428SJonas Bonn1:	l.ori   r6,r0,0x0                  // !write access
3279d02a428SJonas Bonn2:
3289d02a428SJonas Bonn
3299d02a428SJonas Bonn	/* call fault.c handler in or32/mm/fault.c */
3309d02a428SJonas Bonn	l.jal   do_page_fault
3319d02a428SJonas Bonn	 l.nop
3329d02a428SJonas Bonn	l.j     _ret_from_exception
3339d02a428SJonas Bonn	 l.nop
3349d02a428SJonas Bonn
3359d02a428SJonas Bonn/* ---[ 0x400: Insn Page Fault exception ]------------------------------- */
336a81252d7SJonas BonnEXCEPTION_ENTRY(_itlb_miss_page_fault_handler)
33763104c06SStefan Kristiansson	CLEAR_LWA_FLAG(r3)
338a81252d7SJonas Bonn	l.and	r5,r5,r0
339a81252d7SJonas Bonn	l.j	1f
340a81252d7SJonas Bonn	 l.nop
3419d02a428SJonas Bonn
3429d02a428SJonas BonnEXCEPTION_ENTRY(_insn_page_fault_handler)
34363104c06SStefan Kristiansson	CLEAR_LWA_FLAG(r3)
3449d02a428SJonas Bonn	/* set up parameters for do_page_fault */
345a81252d7SJonas Bonn	l.ori	r5,r0,0x400		   // exception vector
346a81252d7SJonas Bonn1:
3479d02a428SJonas Bonn	l.addi  r3,r1,0                    // pt_regs
3489d02a428SJonas Bonn	/* r4 set be EXCEPTION_HANDLE */   // effective address of fault
3499d02a428SJonas Bonn	l.ori	r6,r0,0x0		   // !write access
3509d02a428SJonas Bonn
3519d02a428SJonas Bonn	/* call fault.c handler in or32/mm/fault.c */
3529d02a428SJonas Bonn	l.jal   do_page_fault
3539d02a428SJonas Bonn	 l.nop
3549d02a428SJonas Bonn	l.j     _ret_from_exception
3559d02a428SJonas Bonn	 l.nop
3569d02a428SJonas Bonn
3579d02a428SJonas Bonn
3589d02a428SJonas Bonn/* ---[ 0x500: Timer exception ]----------------------------------------- */
3599d02a428SJonas Bonn
3609d02a428SJonas BonnEXCEPTION_ENTRY(_timer_handler)
36163104c06SStefan Kristiansson	CLEAR_LWA_FLAG(r3)
3629d02a428SJonas Bonn	l.jal	timer_interrupt
3639d02a428SJonas Bonn	 l.addi r3,r1,0 /* pt_regs */
3649d02a428SJonas Bonn
3659d02a428SJonas Bonn	l.j    _ret_from_intr
3669d02a428SJonas Bonn	 l.nop
3679d02a428SJonas Bonn
368550116d2SMasahiro Yamada/* ---[ 0x600: Alignment exception ]-------------------------------------- */
3699d02a428SJonas Bonn
3709d02a428SJonas BonnEXCEPTION_ENTRY(_alignment_handler)
37163104c06SStefan Kristiansson	CLEAR_LWA_FLAG(r3)
3729d02a428SJonas Bonn	/* r4: EA of fault (set by EXCEPTION_HANDLE) */
3739d02a428SJonas Bonn	l.jal   do_unaligned_access
3749d02a428SJonas Bonn	 l.addi  r3,r1,0 /* pt_regs */
3759d02a428SJonas Bonn
3769d02a428SJonas Bonn	l.j     _ret_from_exception
3779d02a428SJonas Bonn	 l.nop
3789d02a428SJonas Bonn
3799d02a428SJonas Bonn#if 0
380550116d2SMasahiro YamadaEXCEPTION_ENTRY(_alignment_handler)
3814e0385ddSMasahiro Yamada//        l.mfspr r2,r0,SPR_EEAR_BASE     /* Load the effective address */
3829d02a428SJonas Bonn	l.addi	r2,r4,0
3839d02a428SJonas Bonn//        l.mfspr r5,r0,SPR_EPCR_BASE     /* Load the insn address */
3849d02a428SJonas Bonn	l.lwz   r5,PT_PC(r1)
3859d02a428SJonas Bonn
3869d02a428SJonas Bonn	l.lwz   r3,0(r5)                /* Load insn */
3879d02a428SJonas Bonn	l.srli  r4,r3,26                /* Shift left to get the insn opcode */
3889d02a428SJonas Bonn
3899d02a428SJonas Bonn	l.sfeqi r4,0x00                 /* Check if the load/store insn is in delay slot */
3909d02a428SJonas Bonn	l.bf    jmp
3919d02a428SJonas Bonn	l.sfeqi r4,0x01
3929d02a428SJonas Bonn	l.bf    jmp
3939d02a428SJonas Bonn	l.sfeqi r4,0x03
3949d02a428SJonas Bonn	l.bf    jmp
3959d02a428SJonas Bonn	l.sfeqi r4,0x04
3969d02a428SJonas Bonn	l.bf    jmp
3979d02a428SJonas Bonn	l.sfeqi r4,0x11
3989d02a428SJonas Bonn	l.bf    jr
3999d02a428SJonas Bonn	l.sfeqi r4,0x12
4009d02a428SJonas Bonn	l.bf    jr
4019d02a428SJonas Bonn	l.nop
4029d02a428SJonas Bonn	l.j     1f
4039d02a428SJonas Bonn	l.addi  r5,r5,4                 /* Increment PC to get return insn address */
4049d02a428SJonas Bonn
4059d02a428SJonas Bonnjmp:
4069d02a428SJonas Bonn	l.slli  r4,r3,6                 /* Get the signed extended jump length */
4079d02a428SJonas Bonn	l.srai  r4,r4,4
4089d02a428SJonas Bonn
4099d02a428SJonas Bonn	l.lwz   r3,4(r5)                /* Load the real load/store insn */
4109d02a428SJonas Bonn
4119d02a428SJonas Bonn	l.add   r5,r5,r4                /* Calculate jump target address */
4129d02a428SJonas Bonn
4139d02a428SJonas Bonn	l.j     1f
4149d02a428SJonas Bonn	l.srli  r4,r3,26                /* Shift left to get the insn opcode */
4159d02a428SJonas Bonn
4169d02a428SJonas Bonnjr:
4179d02a428SJonas Bonn	l.slli  r4,r3,9                 /* Shift to get the reg nb */
4189d02a428SJonas Bonn	l.andi  r4,r4,0x7c
4199d02a428SJonas Bonn
4209d02a428SJonas Bonn	l.lwz   r3,4(r5)                /* Load the real load/store insn */
4219d02a428SJonas Bonn
4229d02a428SJonas Bonn	l.add   r4,r4,r1                /* Load the jump register value from the stack */
4239d02a428SJonas Bonn	l.lwz   r5,0(r4)
4249d02a428SJonas Bonn
4259d02a428SJonas Bonn	l.srli  r4,r3,26                /* Shift left to get the insn opcode */
4269d02a428SJonas Bonn
4279d02a428SJonas Bonn
4289d02a428SJonas Bonn1:
4299d02a428SJonas Bonn//	  l.mtspr r0,r5,SPR_EPCR_BASE
4309d02a428SJonas Bonn	l.sw	PT_PC(r1),r5
4319d02a428SJonas Bonn
4329d02a428SJonas Bonn	l.sfeqi r4,0x26
4339d02a428SJonas Bonn	l.bf    lhs
4349d02a428SJonas Bonn	l.sfeqi r4,0x25
4359d02a428SJonas Bonn	l.bf    lhz
4369d02a428SJonas Bonn	l.sfeqi r4,0x22
4379d02a428SJonas Bonn	l.bf    lws
4389d02a428SJonas Bonn	l.sfeqi r4,0x21
4399d02a428SJonas Bonn	l.bf    lwz
4409d02a428SJonas Bonn	l.sfeqi r4,0x37
4419d02a428SJonas Bonn	l.bf    sh
4429d02a428SJonas Bonn	l.sfeqi r4,0x35
4439d02a428SJonas Bonn	l.bf    sw
4449d02a428SJonas Bonn	l.nop
4459d02a428SJonas Bonn
4469d02a428SJonas Bonn1:      l.j     1b                      /* I don't know what to do */
4479d02a428SJonas Bonn	l.nop
4489d02a428SJonas Bonn
4499d02a428SJonas Bonnlhs:    l.lbs   r5,0(r2)
4509d02a428SJonas Bonn	l.slli  r5,r5,8
4519d02a428SJonas Bonn	l.lbz   r6,1(r2)
4529d02a428SJonas Bonn	l.or    r5,r5,r6
4539d02a428SJonas Bonn	l.srli  r4,r3,19
4549d02a428SJonas Bonn	l.andi  r4,r4,0x7c
4559d02a428SJonas Bonn	l.add   r4,r4,r1
4569d02a428SJonas Bonn	l.j     align_end
4579d02a428SJonas Bonn	l.sw    0(r4),r5
4589d02a428SJonas Bonn
4599d02a428SJonas Bonnlhz:    l.lbz   r5,0(r2)
4609d02a428SJonas Bonn	l.slli  r5,r5,8
4619d02a428SJonas Bonn	l.lbz   r6,1(r2)
4629d02a428SJonas Bonn	l.or    r5,r5,r6
4639d02a428SJonas Bonn	l.srli  r4,r3,19
4649d02a428SJonas Bonn	l.andi  r4,r4,0x7c
4659d02a428SJonas Bonn	l.add   r4,r4,r1
4669d02a428SJonas Bonn	l.j     align_end
4679d02a428SJonas Bonn	l.sw    0(r4),r5
4689d02a428SJonas Bonn
4699d02a428SJonas Bonnlws:    l.lbs   r5,0(r2)
4709d02a428SJonas Bonn	l.slli  r5,r5,24
4719d02a428SJonas Bonn	l.lbz   r6,1(r2)
4729d02a428SJonas Bonn	l.slli  r6,r6,16
4739d02a428SJonas Bonn	l.or    r5,r5,r6
4749d02a428SJonas Bonn	l.lbz   r6,2(r2)
4759d02a428SJonas Bonn	l.slli  r6,r6,8
4769d02a428SJonas Bonn	l.or    r5,r5,r6
4779d02a428SJonas Bonn	l.lbz   r6,3(r2)
4789d02a428SJonas Bonn	l.or    r5,r5,r6
4799d02a428SJonas Bonn	l.srli  r4,r3,19
4809d02a428SJonas Bonn	l.andi  r4,r4,0x7c
4819d02a428SJonas Bonn	l.add   r4,r4,r1
4829d02a428SJonas Bonn	l.j     align_end
4839d02a428SJonas Bonn	l.sw    0(r4),r5
4849d02a428SJonas Bonn
4859d02a428SJonas Bonnlwz:    l.lbz   r5,0(r2)
4869d02a428SJonas Bonn	l.slli  r5,r5,24
4879d02a428SJonas Bonn	l.lbz   r6,1(r2)
4889d02a428SJonas Bonn	l.slli  r6,r6,16
4899d02a428SJonas Bonn	l.or    r5,r5,r6
4909d02a428SJonas Bonn	l.lbz   r6,2(r2)
4919d02a428SJonas Bonn	l.slli  r6,r6,8
4929d02a428SJonas Bonn	l.or    r5,r5,r6
4939d02a428SJonas Bonn	l.lbz   r6,3(r2)
4949d02a428SJonas Bonn	l.or    r5,r5,r6
4959d02a428SJonas Bonn	l.srli  r4,r3,19
4969d02a428SJonas Bonn	l.andi  r4,r4,0x7c
4979d02a428SJonas Bonn	l.add   r4,r4,r1
4989d02a428SJonas Bonn	l.j     align_end
4999d02a428SJonas Bonn	l.sw    0(r4),r5
5009d02a428SJonas Bonn
5019d02a428SJonas Bonnsh:
5029d02a428SJonas Bonn	l.srli  r4,r3,9
5039d02a428SJonas Bonn	l.andi  r4,r4,0x7c
5049d02a428SJonas Bonn	l.add   r4,r4,r1
5059d02a428SJonas Bonn	l.lwz   r5,0(r4)
5069d02a428SJonas Bonn	l.sb    1(r2),r5
5079d02a428SJonas Bonn	l.srli  r5,r5,8
5089d02a428SJonas Bonn	l.j     align_end
5099d02a428SJonas Bonn	l.sb    0(r2),r5
5109d02a428SJonas Bonn
5119d02a428SJonas Bonnsw:
5129d02a428SJonas Bonn	l.srli  r4,r3,9
5139d02a428SJonas Bonn	l.andi  r4,r4,0x7c
5149d02a428SJonas Bonn	l.add   r4,r4,r1
5159d02a428SJonas Bonn	l.lwz   r5,0(r4)
5169d02a428SJonas Bonn	l.sb    3(r2),r5
5179d02a428SJonas Bonn	l.srli  r5,r5,8
5189d02a428SJonas Bonn	l.sb    2(r2),r5
5199d02a428SJonas Bonn	l.srli  r5,r5,8
5209d02a428SJonas Bonn	l.sb    1(r2),r5
5219d02a428SJonas Bonn	l.srli  r5,r5,8
5229d02a428SJonas Bonn	l.j     align_end
5239d02a428SJonas Bonn	l.sb    0(r2),r5
5249d02a428SJonas Bonn
5259d02a428SJonas Bonnalign_end:
5269d02a428SJonas Bonn	l.j    _ret_from_intr
5279d02a428SJonas Bonn	l.nop
5289d02a428SJonas Bonn#endif
5299d02a428SJonas Bonn
5309d02a428SJonas Bonn/* ---[ 0x700: Illegal insn exception ]---------------------------------- */
5319d02a428SJonas Bonn
5329d02a428SJonas BonnEXCEPTION_ENTRY(_illegal_instruction_handler)
5339d02a428SJonas Bonn	/* r4: EA of fault (set by EXCEPTION_HANDLE) */
5349d02a428SJonas Bonn	l.jal   do_illegal_instruction
5359d02a428SJonas Bonn	 l.addi  r3,r1,0 /* pt_regs */
5369d02a428SJonas Bonn
5379d02a428SJonas Bonn	l.j     _ret_from_exception
5389d02a428SJonas Bonn	 l.nop
5399d02a428SJonas Bonn
5409d02a428SJonas Bonn/* ---[ 0x800: External interrupt exception ]---------------------------- */
5419d02a428SJonas Bonn
5429d02a428SJonas BonnEXCEPTION_ENTRY(_external_irq_handler)
5439d02a428SJonas Bonn#ifdef CONFIG_OPENRISC_ESR_EXCEPTION_BUG_CHECK
5449d02a428SJonas Bonn	l.lwz	r4,PT_SR(r1)		// were interrupts enabled ?
5459d02a428SJonas Bonn	l.andi	r4,r4,SPR_SR_IEE
5469d02a428SJonas Bonn	l.sfeqi	r4,0
5479d02a428SJonas Bonn	l.bnf	1f			// ext irq enabled, all ok.
5489d02a428SJonas Bonn	l.nop
5499d02a428SJonas Bonn
5509d02a428SJonas Bonn	l.addi  r1,r1,-0x8
5519d02a428SJonas Bonn	l.movhi r3,hi(42f)
5529d02a428SJonas Bonn	l.ori	r3,r3,lo(42f)
5539d02a428SJonas Bonn	l.sw    0x0(r1),r3
5549d02a428SJonas Bonn	l.jal   printk
5559d02a428SJonas Bonn	l.sw    0x4(r1),r4
5569d02a428SJonas Bonn	l.addi  r1,r1,0x8
5579d02a428SJonas Bonn
5589d02a428SJonas Bonn	.section .rodata, "a"
5599d02a428SJonas Bonn42:
5609d02a428SJonas Bonn		.string "\n\rESR interrupt bug: in _external_irq_handler (ESR %x)\n\r"
5619d02a428SJonas Bonn		.align 4
5629d02a428SJonas Bonn	.previous
5639d02a428SJonas Bonn
5649d02a428SJonas Bonn	l.ori	r4,r4,SPR_SR_IEE	// fix the bug
5659d02a428SJonas Bonn//	l.sw	PT_SR(r1),r4
5669d02a428SJonas Bonn1:
5679d02a428SJonas Bonn#endif
56863104c06SStefan Kristiansson	CLEAR_LWA_FLAG(r3)
5699d02a428SJonas Bonn	l.addi	r3,r1,0
5709d02a428SJonas Bonn	l.movhi	r8,hi(do_IRQ)
5719d02a428SJonas Bonn	l.ori	r8,r8,lo(do_IRQ)
5729d02a428SJonas Bonn	l.jalr r8
5739d02a428SJonas Bonn	l.nop
5749d02a428SJonas Bonn	l.j    _ret_from_intr
5759d02a428SJonas Bonn	l.nop
5769d02a428SJonas Bonn
5779d02a428SJonas Bonn/* ---[ 0x900: DTLB miss exception ]------------------------------------- */
5789d02a428SJonas Bonn
5799d02a428SJonas Bonn
5809d02a428SJonas Bonn/* ---[ 0xa00: ITLB miss exception ]------------------------------------- */
5819d02a428SJonas Bonn
5829d02a428SJonas Bonn
5839d02a428SJonas Bonn/* ---[ 0xb00: Range exception ]----------------------------------------- */
5849d02a428SJonas Bonn
5859d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0xb00,0xb00)
5869d02a428SJonas Bonn
5879d02a428SJonas Bonn/* ---[ 0xc00: Syscall exception ]--------------------------------------- */
5889d02a428SJonas Bonn
5899d02a428SJonas Bonn/*
5909d02a428SJonas Bonn * Syscalls are a special type of exception in that they are
5919d02a428SJonas Bonn * _explicitly_ invoked by userspace and can therefore be
5929d02a428SJonas Bonn * held to conform to the same ABI as normal functions with
5939d02a428SJonas Bonn * respect to whether registers are preserved across the call
5949d02a428SJonas Bonn * or not.
5959d02a428SJonas Bonn */
5969d02a428SJonas Bonn
5979d02a428SJonas Bonn/* Upon syscall entry we just save the callee-saved registers
5989d02a428SJonas Bonn * and not the call-clobbered ones.
5999d02a428SJonas Bonn */
6009d02a428SJonas Bonn
6019d02a428SJonas Bonn_string_syscall_return:
6029d02a428SJonas Bonn	.string "syscall return %ld \n\r\0"
6039d02a428SJonas Bonn	.align 4
6049d02a428SJonas Bonn
6059d02a428SJonas BonnENTRY(_sys_call_handler)
6069d02a428SJonas Bonn	/* r1, EPCR, ESR a already saved */
6079d02a428SJonas Bonn	l.sw	PT_GPR2(r1),r2
6089d02a428SJonas Bonn	/* r3-r8 must be saved because syscall restart relies
6099d02a428SJonas Bonn	 * on us being able to restart the syscall args... technically
6109d02a428SJonas Bonn	 * they should be clobbered, otherwise
6119d02a428SJonas Bonn	 */
6129d02a428SJonas Bonn	l.sw    PT_GPR3(r1),r3
61363104c06SStefan Kristiansson	/*
61463104c06SStefan Kristiansson	 * r4 already saved
61563104c06SStefan Kristiansson	 * r4 holds the EEAR address of the fault, use it as screatch reg and
61663104c06SStefan Kristiansson	 * then load the original r4
61763104c06SStefan Kristiansson	 */
61863104c06SStefan Kristiansson	CLEAR_LWA_FLAG(r4)
6199d02a428SJonas Bonn	l.lwz	r4,PT_GPR4(r1)
6209d02a428SJonas Bonn	l.sw    PT_GPR5(r1),r5
6219d02a428SJonas Bonn	l.sw    PT_GPR6(r1),r6
6229d02a428SJonas Bonn	l.sw    PT_GPR7(r1),r7
6239d02a428SJonas Bonn	l.sw    PT_GPR8(r1),r8
6249d02a428SJonas Bonn	l.sw    PT_GPR9(r1),r9
6259d02a428SJonas Bonn	/* r10 already saved */
6269d02a428SJonas Bonn	l.sw    PT_GPR11(r1),r11
6276cbe5e95SJonas Bonn	/* orig_gpr11 must be set for syscalls */
6289d02a428SJonas Bonn	l.sw    PT_ORIG_GPR11(r1),r11
6299d02a428SJonas Bonn	/* r12,r13 already saved */
6309d02a428SJonas Bonn
6319d02a428SJonas Bonn	/* r14-r28 (even) aren't touched by the syscall fast path below
6329d02a428SJonas Bonn	 * so we don't need to save them.  However, the functions that return
6339d02a428SJonas Bonn	 * to userspace via a call to switch() DO need to save these because
6349d02a428SJonas Bonn	 * switch() effectively clobbers them... saving these registers for
6359d02a428SJonas Bonn	 * such functions is handled in their syscall wrappers (see fork, vfork,
6369d02a428SJonas Bonn	 * and clone, below).
6379d02a428SJonas Bonn
6389d02a428SJonas Bonn	/* r30 is the only register we clobber in the fast path */
6399d02a428SJonas Bonn	/* r30 already saved */
6409d02a428SJonas Bonn/*	l.sw    PT_GPR30(r1),r30 */
6419d02a428SJonas Bonn
6429d02a428SJonas Bonn_syscall_check_trace_enter:
64378cdfb5cSStafford Horne	/* syscalls run with interrupts enabled */
64478cdfb5cSStafford Horne	TRACE_IRQS_ON_SYSCALL
64578cdfb5cSStafford Horne	ENABLE_INTERRUPTS(r29)		// enable interrupts, r29 is temp
64678cdfb5cSStafford Horne
6479d02a428SJonas Bonn	/* If TIF_SYSCALL_TRACE is set, then we want to do syscall tracing */
6489d02a428SJonas Bonn	l.lwz	r30,TI_FLAGS(r10)
6499d02a428SJonas Bonn	l.andi	r30,r30,_TIF_SYSCALL_TRACE
6509d02a428SJonas Bonn	l.sfne	r30,r0
6519d02a428SJonas Bonn	l.bf	_syscall_trace_enter
6529d02a428SJonas Bonn	 l.nop
6539d02a428SJonas Bonn
6549d02a428SJonas Bonn_syscall_check:
6559d02a428SJonas Bonn	/* Ensure that the syscall number is reasonable */
6569d02a428SJonas Bonn	l.sfgeui r11,__NR_syscalls
6579d02a428SJonas Bonn	l.bf	_syscall_badsys
6589d02a428SJonas Bonn	 l.nop
6599d02a428SJonas Bonn
6609d02a428SJonas Bonn_syscall_call:
6619d02a428SJonas Bonn	l.movhi r29,hi(sys_call_table)
6629d02a428SJonas Bonn	l.ori   r29,r29,lo(sys_call_table)
6639d02a428SJonas Bonn	l.slli  r11,r11,2
6649d02a428SJonas Bonn	l.add   r29,r29,r11
6659d02a428SJonas Bonn	l.lwz   r29,0(r29)
6669d02a428SJonas Bonn
6679d02a428SJonas Bonn	l.jalr  r29
6689d02a428SJonas Bonn	 l.nop
6699d02a428SJonas Bonn
6709d02a428SJonas Bonn_syscall_return:
6719d02a428SJonas Bonn	/* All syscalls return here... just pay attention to ret_from_fork
6729d02a428SJonas Bonn	 * which does it in a round-about way.
6739d02a428SJonas Bonn	 */
6749d02a428SJonas Bonn	l.sw    PT_GPR11(r1),r11           // save return value
6759d02a428SJonas Bonn
6769d02a428SJonas Bonn#if 0
6779d02a428SJonas Bonn_syscall_debug:
6789d02a428SJonas Bonn	l.movhi r3,hi(_string_syscall_return)
6799d02a428SJonas Bonn	l.ori   r3,r3,lo(_string_syscall_return)
6809d02a428SJonas Bonn	l.ori   r27,r0,1
6819d02a428SJonas Bonn	l.sw    -4(r1),r27
6829d02a428SJonas Bonn	l.sw    -8(r1),r11
6839d02a428SJonas Bonn	l.addi  r1,r1,-8
6849d02a428SJonas Bonn	l.movhi r27,hi(printk)
6859d02a428SJonas Bonn	l.ori   r27,r27,lo(printk)
6869d02a428SJonas Bonn	l.jalr  r27
6879d02a428SJonas Bonn	 l.nop
6889d02a428SJonas Bonn	l.addi  r1,r1,8
6899d02a428SJonas Bonn#endif
6909d02a428SJonas Bonn
6919d02a428SJonas Bonn_syscall_check_trace_leave:
6929d02a428SJonas Bonn	/* r30 is a callee-saved register so this should still hold the
6939d02a428SJonas Bonn	 * _TIF_SYSCALL_TRACE flag from _syscall_check_trace_enter above...
6949d02a428SJonas Bonn	 * _syscall_trace_leave expects syscall result to be in pt_regs->r11.
6959d02a428SJonas Bonn	 */
6969d02a428SJonas Bonn	l.sfne	r30,r0
6979d02a428SJonas Bonn	l.bf	_syscall_trace_leave
6989d02a428SJonas Bonn	 l.nop
6999d02a428SJonas Bonn
7009d02a428SJonas Bonn/* This is where the exception-return code begins... interrupts need to be
7019d02a428SJonas Bonn * disabled the rest of the way here because we can't afford to miss any
7029d02a428SJonas Bonn * interrupts that set NEED_RESCHED or SIGNALPENDING... really true? */
7039d02a428SJonas Bonn
7049d02a428SJonas Bonn_syscall_check_work:
7059d02a428SJonas Bonn	/* Here we need to disable interrupts */
7069d02a428SJonas Bonn	DISABLE_INTERRUPTS(r27,r29)
70778cdfb5cSStafford Horne	TRACE_IRQS_OFF
7089d02a428SJonas Bonn	l.lwz	r30,TI_FLAGS(r10)
7099d02a428SJonas Bonn	l.andi	r30,r30,_TIF_WORK_MASK
7109d02a428SJonas Bonn	l.sfne	r30,r0
7119d02a428SJonas Bonn
7129d02a428SJonas Bonn	l.bnf	_syscall_resume_userspace
7139d02a428SJonas Bonn	 l.nop
7149d02a428SJonas Bonn
7159d02a428SJonas Bonn	/* Work pending follows a different return path, so we need to
7169d02a428SJonas Bonn	 * make sure that all the call-saved registers get into pt_regs
7179d02a428SJonas Bonn	 * before branching...
7189d02a428SJonas Bonn	 */
7199d02a428SJonas Bonn	l.sw    PT_GPR14(r1),r14
7209d02a428SJonas Bonn	l.sw    PT_GPR16(r1),r16
7219d02a428SJonas Bonn	l.sw    PT_GPR18(r1),r18
7229d02a428SJonas Bonn	l.sw    PT_GPR20(r1),r20
7239d02a428SJonas Bonn	l.sw    PT_GPR22(r1),r22
7249d02a428SJonas Bonn	l.sw    PT_GPR24(r1),r24
7259d02a428SJonas Bonn	l.sw    PT_GPR26(r1),r26
7269d02a428SJonas Bonn	l.sw    PT_GPR28(r1),r28
7279d02a428SJonas Bonn
7289d02a428SJonas Bonn	/* _work_pending needs to be called with interrupts disabled */
7299d02a428SJonas Bonn	l.j	_work_pending
7309d02a428SJonas Bonn	 l.nop
7319d02a428SJonas Bonn
7329d02a428SJonas Bonn_syscall_resume_userspace:
7339d02a428SJonas Bonn//	ENABLE_INTERRUPTS(r29)
7349d02a428SJonas Bonn
7359d02a428SJonas Bonn
7369d02a428SJonas Bonn/* This is the hot path for returning to userspace from a syscall.  If there's
7379d02a428SJonas Bonn * work to be done and the branch to _work_pending was taken above, then the
7389d02a428SJonas Bonn * return to userspace will be done via the normal exception return path...
7399d02a428SJonas Bonn * that path restores _all_ registers and will overwrite the "clobbered"
7409d02a428SJonas Bonn * registers with whatever garbage is in pt_regs -- that's OK because those
7419d02a428SJonas Bonn * registers are clobbered anyway and because the extra work is insignificant
7429d02a428SJonas Bonn * in the context of the extra work that _work_pending is doing.
7439d02a428SJonas Bonn
7449d02a428SJonas Bonn/* Once again, syscalls are special and only guarantee to preserve the
7459d02a428SJonas Bonn * same registers as a normal function call */
7469d02a428SJonas Bonn
7479d02a428SJonas Bonn/* The assumption here is that the registers r14-r28 (even) are untouched and
7489d02a428SJonas Bonn * don't need to be restored... be sure that that's really the case!
7499d02a428SJonas Bonn */
7509d02a428SJonas Bonn
7519d02a428SJonas Bonn/* This is still too much... we should only be restoring what we actually
7529d02a428SJonas Bonn * clobbered... we should even be using 'scratch' (odd) regs above so that
7539d02a428SJonas Bonn * we don't need to restore anything, hardly...
7549d02a428SJonas Bonn */
7559d02a428SJonas Bonn
7569d02a428SJonas Bonn	l.lwz	r2,PT_GPR2(r1)
7579d02a428SJonas Bonn
7589d02a428SJonas Bonn	/* Restore args */
7599d02a428SJonas Bonn	/* r3-r8 are technically clobbered, but syscall restart needs these
7609d02a428SJonas Bonn	 * to be restored...
7619d02a428SJonas Bonn	 */
7629d02a428SJonas Bonn	l.lwz	r3,PT_GPR3(r1)
7639d02a428SJonas Bonn	l.lwz	r4,PT_GPR4(r1)
7649d02a428SJonas Bonn	l.lwz	r5,PT_GPR5(r1)
7659d02a428SJonas Bonn	l.lwz	r6,PT_GPR6(r1)
7669d02a428SJonas Bonn	l.lwz	r7,PT_GPR7(r1)
7679d02a428SJonas Bonn	l.lwz	r8,PT_GPR8(r1)
7689d02a428SJonas Bonn
7699d02a428SJonas Bonn	l.lwz	r9,PT_GPR9(r1)
7709d02a428SJonas Bonn	l.lwz	r10,PT_GPR10(r1)
7719d02a428SJonas Bonn	l.lwz	r11,PT_GPR11(r1)
7729d02a428SJonas Bonn
7739d02a428SJonas Bonn	/* r30 is the only register we clobber in the fast path */
7749d02a428SJonas Bonn	l.lwz	r30,PT_GPR30(r1)
7759d02a428SJonas Bonn
7769d02a428SJonas Bonn	/* Here we use r13-r19 (odd) as scratch regs */
7779d02a428SJonas Bonn	l.lwz   r13,PT_PC(r1)
7789d02a428SJonas Bonn	l.lwz   r15,PT_SR(r1)
7799d02a428SJonas Bonn	l.lwz	r1,PT_SP(r1)
7809d02a428SJonas Bonn	/* Interrupts need to be disabled for setting EPCR and ESR
7819d02a428SJonas Bonn	 * so that another interrupt doesn't come in here and clobber
7829d02a428SJonas Bonn	 * them before we can use them for our l.rfe */
7839d02a428SJonas Bonn	DISABLE_INTERRUPTS(r17,r19)
7849d02a428SJonas Bonn	l.mtspr r0,r13,SPR_EPCR_BASE
7859d02a428SJonas Bonn	l.mtspr r0,r15,SPR_ESR_BASE
7869d02a428SJonas Bonn	l.rfe
7879d02a428SJonas Bonn
7889d02a428SJonas Bonn/* End of hot path!
7899d02a428SJonas Bonn * Keep the below tracing and error handling out of the hot path...
7909d02a428SJonas Bonn*/
7919d02a428SJonas Bonn
7929d02a428SJonas Bonn_syscall_trace_enter:
7939d02a428SJonas Bonn	/* Here we pass pt_regs to do_syscall_trace_enter.  Make sure
7949d02a428SJonas Bonn	 * that function is really getting all the info it needs as
7959d02a428SJonas Bonn	 * pt_regs isn't a complete set of userspace regs, just the
7969d02a428SJonas Bonn	 * ones relevant to the syscall...
7979d02a428SJonas Bonn	 *
7989d02a428SJonas Bonn	 * Note use of delay slot for setting argument.
7999d02a428SJonas Bonn	 */
8009d02a428SJonas Bonn	l.jal	do_syscall_trace_enter
8019d02a428SJonas Bonn	 l.addi	r3,r1,0
8029d02a428SJonas Bonn
8039d02a428SJonas Bonn	/* Restore arguments (not preserved across do_syscall_trace_enter)
8049d02a428SJonas Bonn	 * so that we can do the syscall for real and return to the syscall
8059d02a428SJonas Bonn	 * hot path.
8069d02a428SJonas Bonn	 */
8076cbe5e95SJonas Bonn	l.lwz	r11,PT_GPR11(r1)
8089d02a428SJonas Bonn	l.lwz	r3,PT_GPR3(r1)
8099d02a428SJonas Bonn	l.lwz	r4,PT_GPR4(r1)
8109d02a428SJonas Bonn	l.lwz	r5,PT_GPR5(r1)
8119d02a428SJonas Bonn	l.lwz	r6,PT_GPR6(r1)
8129d02a428SJonas Bonn	l.lwz	r7,PT_GPR7(r1)
8139d02a428SJonas Bonn
8149d02a428SJonas Bonn	l.j	_syscall_check
8159d02a428SJonas Bonn	 l.lwz	r8,PT_GPR8(r1)
8169d02a428SJonas Bonn
8179d02a428SJonas Bonn_syscall_trace_leave:
8189d02a428SJonas Bonn	l.jal	do_syscall_trace_leave
8199d02a428SJonas Bonn	 l.addi	r3,r1,0
8209d02a428SJonas Bonn
8219d02a428SJonas Bonn	l.j	_syscall_check_work
8229d02a428SJonas Bonn	 l.nop
8239d02a428SJonas Bonn
8249d02a428SJonas Bonn_syscall_badsys:
8259d02a428SJonas Bonn	/* Here we effectively pretend to have executed an imaginary
8269d02a428SJonas Bonn	 * syscall that returns -ENOSYS and then return to the regular
8279d02a428SJonas Bonn	 * syscall hot path.
8289d02a428SJonas Bonn	 * Note that "return value" is set in the delay slot...
8299d02a428SJonas Bonn	 */
8309d02a428SJonas Bonn	l.j	_syscall_return
8319d02a428SJonas Bonn	 l.addi	r11,r0,-ENOSYS
8329d02a428SJonas Bonn
8339d02a428SJonas Bonn/******* END SYSCALL HANDLING *******/
8349d02a428SJonas Bonn
8359d02a428SJonas Bonn/* ---[ 0xd00: Trap exception ]------------------------------------------ */
8369d02a428SJonas Bonn
8379d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0xd00,0xd00)
8389d02a428SJonas Bonn
8399d02a428SJonas Bonn/* ---[ 0xe00: Trap exception ]------------------------------------------ */
8409d02a428SJonas Bonn
8419d02a428SJonas BonnEXCEPTION_ENTRY(_trap_handler)
84263104c06SStefan Kristiansson	CLEAR_LWA_FLAG(r3)
8439d02a428SJonas Bonn	/* r4: EA of fault (set by EXCEPTION_HANDLE) */
8449d02a428SJonas Bonn	l.jal   do_trap
8459d02a428SJonas Bonn	 l.addi  r3,r1,0 /* pt_regs */
8469d02a428SJonas Bonn
8479d02a428SJonas Bonn	l.j     _ret_from_exception
8489d02a428SJonas Bonn	 l.nop
8499d02a428SJonas Bonn
8509d02a428SJonas Bonn/* ---[ 0xf00: Reserved exception ]-------------------------------------- */
8519d02a428SJonas Bonn
8529d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0xf00,0xf00)
8539d02a428SJonas Bonn
8549d02a428SJonas Bonn/* ---[ 0x1000: Reserved exception ]------------------------------------- */
8559d02a428SJonas Bonn
8569d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1000,0x1000)
8579d02a428SJonas Bonn
8589d02a428SJonas Bonn/* ---[ 0x1100: Reserved exception ]------------------------------------- */
8599d02a428SJonas Bonn
8609d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1100,0x1100)
8619d02a428SJonas Bonn
8629d02a428SJonas Bonn/* ---[ 0x1200: Reserved exception ]------------------------------------- */
8639d02a428SJonas Bonn
8649d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1200,0x1200)
8659d02a428SJonas Bonn
8669d02a428SJonas Bonn/* ---[ 0x1300: Reserved exception ]------------------------------------- */
8679d02a428SJonas Bonn
8689d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1300,0x1300)
8699d02a428SJonas Bonn
8709d02a428SJonas Bonn/* ---[ 0x1400: Reserved exception ]------------------------------------- */
8719d02a428SJonas Bonn
8729d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1400,0x1400)
8739d02a428SJonas Bonn
8749d02a428SJonas Bonn/* ---[ 0x1500: Reserved exception ]------------------------------------- */
8759d02a428SJonas Bonn
8769d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1500,0x1500)
8779d02a428SJonas Bonn
8789d02a428SJonas Bonn/* ---[ 0x1600: Reserved exception ]------------------------------------- */
8799d02a428SJonas Bonn
8809d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1600,0x1600)
8819d02a428SJonas Bonn
8829d02a428SJonas Bonn/* ---[ 0x1700: Reserved exception ]------------------------------------- */
8839d02a428SJonas Bonn
8849d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1700,0x1700)
8859d02a428SJonas Bonn
8869d02a428SJonas Bonn/* ---[ 0x1800: Reserved exception ]------------------------------------- */
8879d02a428SJonas Bonn
8889d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1800,0x1800)
8899d02a428SJonas Bonn
8909d02a428SJonas Bonn/* ---[ 0x1900: Reserved exception ]------------------------------------- */
8919d02a428SJonas Bonn
8929d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1900,0x1900)
8939d02a428SJonas Bonn
8949d02a428SJonas Bonn/* ---[ 0x1a00: Reserved exception ]------------------------------------- */
8959d02a428SJonas Bonn
8969d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1a00,0x1a00)
8979d02a428SJonas Bonn
8989d02a428SJonas Bonn/* ---[ 0x1b00: Reserved exception ]------------------------------------- */
8999d02a428SJonas Bonn
9009d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1b00,0x1b00)
9019d02a428SJonas Bonn
9029d02a428SJonas Bonn/* ---[ 0x1c00: Reserved exception ]------------------------------------- */
9039d02a428SJonas Bonn
9049d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1c00,0x1c00)
9059d02a428SJonas Bonn
9069d02a428SJonas Bonn/* ---[ 0x1d00: Reserved exception ]------------------------------------- */
9079d02a428SJonas Bonn
9089d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1d00,0x1d00)
9099d02a428SJonas Bonn
9109d02a428SJonas Bonn/* ---[ 0x1e00: Reserved exception ]------------------------------------- */
9119d02a428SJonas Bonn
9129d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1e00,0x1e00)
9139d02a428SJonas Bonn
9149d02a428SJonas Bonn/* ---[ 0x1f00: Reserved exception ]------------------------------------- */
9159d02a428SJonas Bonn
9169d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1f00,0x1f00)
9179d02a428SJonas Bonn
9189d02a428SJonas Bonn/* ========================================================[ return ] === */
9199d02a428SJonas Bonn
9209d02a428SJonas Bonn_resume_userspace:
9219d02a428SJonas Bonn	DISABLE_INTERRUPTS(r3,r4)
92278cdfb5cSStafford Horne	TRACE_IRQS_OFF
92310f67dbfSJonas Bonn	l.lwz	r4,TI_FLAGS(r10)
92410f67dbfSJonas Bonn	l.andi	r13,r4,_TIF_WORK_MASK
92510f67dbfSJonas Bonn	l.sfeqi	r13,0
92610f67dbfSJonas Bonn	l.bf	_restore_all
9279d02a428SJonas Bonn	 l.nop
9289d02a428SJonas Bonn
92910f67dbfSJonas Bonn_work_pending:
93010f67dbfSJonas Bonn	l.lwz	r5,PT_ORIG_GPR11(r1)
93110f67dbfSJonas Bonn	l.sfltsi r5,0
93210f67dbfSJonas Bonn	l.bnf	1f
93310f67dbfSJonas Bonn	 l.nop
93410f67dbfSJonas Bonn	l.andi	r5,r5,0
93510f67dbfSJonas Bonn1:
93610f67dbfSJonas Bonn	l.jal	do_work_pending
93710f67dbfSJonas Bonn	 l.ori	r3,r1,0			/* pt_regs */
93810f67dbfSJonas Bonn
93910f67dbfSJonas Bonn	l.sfeqi	r11,0
94010f67dbfSJonas Bonn	l.bf	_restore_all
94110f67dbfSJonas Bonn	 l.nop
94210f67dbfSJonas Bonn	l.sfltsi r11,0
94310f67dbfSJonas Bonn	l.bnf	1f
94410f67dbfSJonas Bonn	 l.nop
94510f67dbfSJonas Bonn	l.and	r11,r11,r0
94610f67dbfSJonas Bonn	l.ori	r11,r11,__NR_restart_syscall
94710f67dbfSJonas Bonn	l.j	_syscall_check_trace_enter
94810f67dbfSJonas Bonn	 l.nop
94910f67dbfSJonas Bonn1:
95010f67dbfSJonas Bonn	l.lwz	r11,PT_ORIG_GPR11(r1)
95110f67dbfSJonas Bonn	/* Restore arg registers */
95210f67dbfSJonas Bonn	l.lwz	r3,PT_GPR3(r1)
95310f67dbfSJonas Bonn	l.lwz	r4,PT_GPR4(r1)
95410f67dbfSJonas Bonn	l.lwz	r5,PT_GPR5(r1)
95510f67dbfSJonas Bonn	l.lwz	r6,PT_GPR6(r1)
95610f67dbfSJonas Bonn	l.lwz	r7,PT_GPR7(r1)
95710f67dbfSJonas Bonn	l.j	_syscall_check_trace_enter
95810f67dbfSJonas Bonn	 l.lwz	r8,PT_GPR8(r1)
95910f67dbfSJonas Bonn
9609d02a428SJonas Bonn_restore_all:
96178cdfb5cSStafford Horne#ifdef CONFIG_TRACE_IRQFLAGS
96278cdfb5cSStafford Horne	l.lwz	r4,PT_SR(r1)
96378cdfb5cSStafford Horne	l.andi	r3,r4,(SPR_SR_IEE|SPR_SR_TEE)
96478cdfb5cSStafford Horne	l.sfeq	r3,r0		/* skip trace if irqs were off */
96578cdfb5cSStafford Horne	l.bf	skip_hardirqs_on
96678cdfb5cSStafford Horne	 l.nop
96778cdfb5cSStafford Horne	TRACE_IRQS_ON
96878cdfb5cSStafford Horneskip_hardirqs_on:
96978cdfb5cSStafford Horne#endif
9709d02a428SJonas Bonn	RESTORE_ALL
9719d02a428SJonas Bonn	/* This returns to userspace code */
9729d02a428SJonas Bonn
9739d02a428SJonas Bonn
9749d02a428SJonas BonnENTRY(_ret_from_intr)
9759d02a428SJonas BonnENTRY(_ret_from_exception)
9769d02a428SJonas Bonn	l.lwz	r4,PT_SR(r1)
9779d02a428SJonas Bonn	l.andi	r3,r4,SPR_SR_SM
9789d02a428SJonas Bonn	l.sfeqi	r3,0
9799d02a428SJonas Bonn	l.bnf	_restore_all
9809d02a428SJonas Bonn	 l.nop
9819d02a428SJonas Bonn	l.j	_resume_userspace
9829d02a428SJonas Bonn	 l.nop
9839d02a428SJonas Bonn
9849d02a428SJonas BonnENTRY(ret_from_fork)
9859d02a428SJonas Bonn	l.jal	schedule_tail
9869d02a428SJonas Bonn	 l.nop
9879d02a428SJonas Bonn
988cbf23cf1SJonas Bonn	/* Check if we are a kernel thread */
989cbf23cf1SJonas Bonn	l.sfeqi	r20,0
990cbf23cf1SJonas Bonn	l.bf	1f
991cbf23cf1SJonas Bonn	 l.nop
992cbf23cf1SJonas Bonn
993cbf23cf1SJonas Bonn	/* ...we are a kernel thread so invoke the requested callback */
994cbf23cf1SJonas Bonn	l.jalr	r20
995cbf23cf1SJonas Bonn	 l.or	r3,r22,r0
996cbf23cf1SJonas Bonn
997cbf23cf1SJonas Bonn1:
9989d02a428SJonas Bonn	/* _syscall_returns expect r11 to contain return value */
9999d02a428SJonas Bonn	l.lwz	r11,PT_GPR11(r1)
10009d02a428SJonas Bonn
10019d02a428SJonas Bonn	/* The syscall fast path return expects call-saved registers
10029d02a428SJonas Bonn	 * r12-r28 to be untouched, so we restore them here as they
10039d02a428SJonas Bonn	 * will have been effectively clobbered when arriving here
10049d02a428SJonas Bonn	 * via the call to switch()
10059d02a428SJonas Bonn	 */
10069d02a428SJonas Bonn	l.lwz	r12,PT_GPR12(r1)
10079d02a428SJonas Bonn	l.lwz	r14,PT_GPR14(r1)
10089d02a428SJonas Bonn	l.lwz	r16,PT_GPR16(r1)
10099d02a428SJonas Bonn	l.lwz	r18,PT_GPR18(r1)
10109d02a428SJonas Bonn	l.lwz	r20,PT_GPR20(r1)
10119d02a428SJonas Bonn	l.lwz	r22,PT_GPR22(r1)
10129d02a428SJonas Bonn	l.lwz	r24,PT_GPR24(r1)
10139d02a428SJonas Bonn	l.lwz	r26,PT_GPR26(r1)
10149d02a428SJonas Bonn	l.lwz	r28,PT_GPR28(r1)
10159d02a428SJonas Bonn
10169d02a428SJonas Bonn	l.j	_syscall_return
10179d02a428SJonas Bonn	 l.nop
10189d02a428SJonas Bonn
10199d02a428SJonas Bonn/* ========================================================[ switch ] === */
10209d02a428SJonas Bonn
10219d02a428SJonas Bonn/*
10229d02a428SJonas Bonn * This routine switches between two different tasks.  The process
10239d02a428SJonas Bonn * state of one is saved on its kernel stack.  Then the state
10249d02a428SJonas Bonn * of the other is restored from its kernel stack.  The memory
10259d02a428SJonas Bonn * management hardware is updated to the second process's state.
10269d02a428SJonas Bonn * Finally, we can return to the second process, via the 'return'.
10279d02a428SJonas Bonn *
10289d02a428SJonas Bonn * Note: there are two ways to get to the "going out" portion
10299d02a428SJonas Bonn * of this code; either by coming in via the entry (_switch)
10309d02a428SJonas Bonn * or via "fork" which must set up an environment equivalent
10319d02a428SJonas Bonn * to the "_switch" path.  If you change this (or in particular, the
10329d02a428SJonas Bonn * SAVE_REGS macro), you'll have to change the fork code also.
10339d02a428SJonas Bonn */
10349d02a428SJonas Bonn
10359d02a428SJonas Bonn
10369d02a428SJonas Bonn/* _switch MUST never lay on page boundry, cause it runs from
10379d02a428SJonas Bonn * effective addresses and beeing interrupted by iTLB miss would kill it.
10389d02a428SJonas Bonn * dTLB miss seams to never accour in the bad place since data accesses
10399d02a428SJonas Bonn * are from task structures which are always page aligned.
10409d02a428SJonas Bonn *
10419d02a428SJonas Bonn * The problem happens in RESTORE_ALL_NO_R11 where we first set the EPCR
10429d02a428SJonas Bonn * register, then load the previous register values and only at the end call
10439d02a428SJonas Bonn * the l.rfe instruction. If get TLB miss in beetwen the EPCR register gets
10449d02a428SJonas Bonn * garbled and we end up calling l.rfe with the wrong EPCR. (same probably
10459d02a428SJonas Bonn * holds for ESR)
10469d02a428SJonas Bonn *
10479d02a428SJonas Bonn * To avoid this problems it is sufficient to align _switch to
10489d02a428SJonas Bonn * some nice round number smaller than it's size...
10499d02a428SJonas Bonn */
10509d02a428SJonas Bonn
10519d02a428SJonas Bonn/* ABI rules apply here... we either enter _switch via schedule() or via
10529d02a428SJonas Bonn * an imaginary call to which we shall return at return_from_fork.  Either
10539d02a428SJonas Bonn * way, we are a function call and only need to preserve the callee-saved
10549d02a428SJonas Bonn * registers when we return.  As such, we don't need to save the registers
10559d02a428SJonas Bonn * on the stack that we won't be returning as they were...
10569d02a428SJonas Bonn */
10579d02a428SJonas Bonn
10589d02a428SJonas Bonn	.align 0x400
10599d02a428SJonas BonnENTRY(_switch)
10609d02a428SJonas Bonn	/* We don't store SR as _switch only gets called in a context where
10619d02a428SJonas Bonn	 * the SR will be the same going in and coming out... */
10629d02a428SJonas Bonn
10639d02a428SJonas Bonn	/* Set up new pt_regs struct for saving task state */
10649d02a428SJonas Bonn	l.addi  r1,r1,-(INT_FRAME_SIZE)
10659d02a428SJonas Bonn
10669d02a428SJonas Bonn	/* No need to store r1/PT_SP as it goes into KSP below */
10679d02a428SJonas Bonn	l.sw    PT_GPR2(r1),r2
10689d02a428SJonas Bonn	l.sw    PT_GPR9(r1),r9
10699d02a428SJonas Bonn	/* This is wrong, r12 shouldn't be here... but GCC is broken for the time being
10709d02a428SJonas Bonn	 * and expects r12 to be callee-saved... */
10719d02a428SJonas Bonn	l.sw    PT_GPR12(r1),r12
10729d02a428SJonas Bonn	l.sw    PT_GPR14(r1),r14
10739d02a428SJonas Bonn	l.sw    PT_GPR16(r1),r16
10749d02a428SJonas Bonn	l.sw    PT_GPR18(r1),r18
10759d02a428SJonas Bonn	l.sw    PT_GPR20(r1),r20
10769d02a428SJonas Bonn	l.sw    PT_GPR22(r1),r22
10779d02a428SJonas Bonn	l.sw    PT_GPR24(r1),r24
10789d02a428SJonas Bonn	l.sw    PT_GPR26(r1),r26
10799d02a428SJonas Bonn	l.sw    PT_GPR28(r1),r28
10809d02a428SJonas Bonn	l.sw    PT_GPR30(r1),r30
10819d02a428SJonas Bonn
10829d02a428SJonas Bonn	l.addi	r11,r10,0			/* Save old 'current' to 'last' return value*/
10839d02a428SJonas Bonn
10849d02a428SJonas Bonn	/* We use thread_info->ksp for storing the address of the above
10859d02a428SJonas Bonn	 * structure so that we can get back to it later... we don't want
10869d02a428SJonas Bonn	 * to lose the value of thread_info->ksp, though, so store it as
10879d02a428SJonas Bonn	 * pt_regs->sp so that we can easily restore it when we are made
10889d02a428SJonas Bonn	 * live again...
10899d02a428SJonas Bonn	 */
10909d02a428SJonas Bonn
10919d02a428SJonas Bonn	/* Save the old value of thread_info->ksp as pt_regs->sp */
10929d02a428SJonas Bonn	l.lwz	r29,TI_KSP(r10)
10939d02a428SJonas Bonn	l.sw	PT_SP(r1),r29
10949d02a428SJonas Bonn
10959d02a428SJonas Bonn	/* Swap kernel stack pointers */
10969d02a428SJonas Bonn	l.sw    TI_KSP(r10),r1			/* Save old stack pointer */
10979d02a428SJonas Bonn	l.or	r10,r4,r0			/* Set up new current_thread_info */
10989d02a428SJonas Bonn	l.lwz   r1,TI_KSP(r10)			/* Load new stack pointer */
10999d02a428SJonas Bonn
11009d02a428SJonas Bonn	/* Restore the old value of thread_info->ksp */
11019d02a428SJonas Bonn	l.lwz	r29,PT_SP(r1)
11029d02a428SJonas Bonn	l.sw	TI_KSP(r10),r29
11039d02a428SJonas Bonn
11049d02a428SJonas Bonn	/* ...and restore the registers, except r11 because the return value
11059d02a428SJonas Bonn	 * has already been set above.
11069d02a428SJonas Bonn	 */
11079d02a428SJonas Bonn	l.lwz   r2,PT_GPR2(r1)
11089d02a428SJonas Bonn	l.lwz   r9,PT_GPR9(r1)
11099d02a428SJonas Bonn	/* No need to restore r10 */
11109d02a428SJonas Bonn	/* ...and do not restore r11 */
11119d02a428SJonas Bonn
11129d02a428SJonas Bonn	/* This is wrong, r12 shouldn't be here... but GCC is broken for the time being
11139d02a428SJonas Bonn	 * and expects r12 to be callee-saved... */
11149d02a428SJonas Bonn	l.lwz   r12,PT_GPR12(r1)
11159d02a428SJonas Bonn	l.lwz   r14,PT_GPR14(r1)
11169d02a428SJonas Bonn	l.lwz   r16,PT_GPR16(r1)
11179d02a428SJonas Bonn	l.lwz   r18,PT_GPR18(r1)
11189d02a428SJonas Bonn	l.lwz   r20,PT_GPR20(r1)
11199d02a428SJonas Bonn	l.lwz   r22,PT_GPR22(r1)
11209d02a428SJonas Bonn	l.lwz   r24,PT_GPR24(r1)
11219d02a428SJonas Bonn	l.lwz   r26,PT_GPR26(r1)
11229d02a428SJonas Bonn	l.lwz   r28,PT_GPR28(r1)
11239d02a428SJonas Bonn	l.lwz   r30,PT_GPR30(r1)
11249d02a428SJonas Bonn
11259d02a428SJonas Bonn	/* Unwind stack to pre-switch state */
11269d02a428SJonas Bonn	l.addi  r1,r1,(INT_FRAME_SIZE)
11279d02a428SJonas Bonn
1128287ad220SJonas Bonn	/* Return via the link-register back to where we 'came from', where
1129287ad220SJonas Bonn	 * that may be either schedule(), ret_from_fork(), or
1130287ad220SJonas Bonn	 * ret_from_kernel_thread().  If we are returning to a new thread,
1131287ad220SJonas Bonn	 * we are expected to have set up the arg to schedule_tail already,
1132287ad220SJonas Bonn	 * hence we do so here unconditionally:
1133287ad220SJonas Bonn	 */
1134ae6fef17SJonas Bonn	l.lwz   r3,TI_TASK(r3)		/* Load 'prev' as schedule_tail arg */
11359d02a428SJonas Bonn	l.jr	r9
11369d02a428SJonas Bonn	 l.nop
11379d02a428SJonas Bonn
11389d02a428SJonas Bonn/* ==================================================================== */
11399d02a428SJonas Bonn
11409d02a428SJonas Bonn/* These all use the delay slot for setting the argument register, so the
11419d02a428SJonas Bonn * jump is always happening after the l.addi instruction.
11429d02a428SJonas Bonn *
11439d02a428SJonas Bonn * These are all just wrappers that don't touch the link-register r9, so the
11449d02a428SJonas Bonn * return from the "real" syscall function will return back to the syscall
11459d02a428SJonas Bonn * code that did the l.jal that brought us here.
11469d02a428SJonas Bonn */
11479d02a428SJonas Bonn
11489d02a428SJonas Bonn/* fork requires that we save all the callee-saved registers because they
11499d02a428SJonas Bonn * are all effectively clobbered by the call to _switch.  Here we store
11509d02a428SJonas Bonn * all the registers that aren't touched by the syscall fast path and thus
11519d02a428SJonas Bonn * weren't saved there.
11529d02a428SJonas Bonn */
11539d02a428SJonas Bonn
11549d02a428SJonas Bonn_fork_save_extra_regs_and_call:
11559d02a428SJonas Bonn	l.sw    PT_GPR14(r1),r14
11569d02a428SJonas Bonn	l.sw    PT_GPR16(r1),r16
11579d02a428SJonas Bonn	l.sw    PT_GPR18(r1),r18
11589d02a428SJonas Bonn	l.sw    PT_GPR20(r1),r20
11599d02a428SJonas Bonn	l.sw    PT_GPR22(r1),r22
11609d02a428SJonas Bonn	l.sw    PT_GPR24(r1),r24
11619d02a428SJonas Bonn	l.sw    PT_GPR26(r1),r26
11629d02a428SJonas Bonn	l.jr	r29
11639d02a428SJonas Bonn	 l.sw    PT_GPR28(r1),r28
11649d02a428SJonas Bonn
116539d91a9eSAl ViroENTRY(__sys_clone)
116639d91a9eSAl Viro	l.movhi	r29,hi(sys_clone)
116739d91a9eSAl Viro	l.ori	r29,r29,lo(sys_clone)
11689d02a428SJonas Bonn	l.j	_fork_save_extra_regs_and_call
11699d02a428SJonas Bonn	 l.addi	r7,r1,0
11709d02a428SJonas Bonn
117139d91a9eSAl ViroENTRY(__sys_fork)
117239d91a9eSAl Viro	l.movhi	r29,hi(sys_fork)
117339d91a9eSAl Viro	l.ori	r29,r29,lo(sys_fork)
11749d02a428SJonas Bonn	l.j	_fork_save_extra_regs_and_call
11759d02a428SJonas Bonn	 l.addi	r3,r1,0
11769d02a428SJonas Bonn
11779d02a428SJonas BonnENTRY(sys_rt_sigreturn)
1178c7990219SJonas Bonn	l.jal	_sys_rt_sigreturn
11799d02a428SJonas Bonn	 l.addi	r3,r1,0
1180c7990219SJonas Bonn	l.sfne	r30,r0
1181c7990219SJonas Bonn	l.bnf	_no_syscall_trace
1182c7990219SJonas Bonn	 l.nop
1183c7990219SJonas Bonn	l.jal	do_syscall_trace_leave
1184c7990219SJonas Bonn	 l.addi	r3,r1,0
1185c7990219SJonas Bonn_no_syscall_trace:
1186c7990219SJonas Bonn	l.j	_resume_userspace
1187c7990219SJonas Bonn	 l.nop
11889d02a428SJonas Bonn
11899d02a428SJonas Bonn/* This is a catch-all syscall for atomic instructions for the OpenRISC 1000.
11909d02a428SJonas Bonn * The functions takes a variable number of parameters depending on which
11919d02a428SJonas Bonn * particular flavour of atomic you want... parameter 1 is a flag identifying
11929d02a428SJonas Bonn * the atomic in question.  Currently, this function implements the
11939d02a428SJonas Bonn * following variants:
11949d02a428SJonas Bonn *
11959d02a428SJonas Bonn * XCHG:
11969d02a428SJonas Bonn *  @flag: 1
11979d02a428SJonas Bonn *  @ptr1:
11989d02a428SJonas Bonn *  @ptr2:
11999d02a428SJonas Bonn * Atomically exchange the values in pointers 1 and 2.
12009d02a428SJonas Bonn *
12019d02a428SJonas Bonn */
12029d02a428SJonas Bonn
12039d02a428SJonas BonnENTRY(sys_or1k_atomic)
12049d02a428SJonas Bonn	/* FIXME: This ignores r3 and always does an XCHG */
12059d02a428SJonas Bonn	DISABLE_INTERRUPTS(r17,r19)
1206207e715fSJonas Bonn	l.lwz	r29,0(r4)
1207207e715fSJonas Bonn	l.lwz	r27,0(r5)
1208207e715fSJonas Bonn	l.sw	0(r4),r27
1209207e715fSJonas Bonn	l.sw	0(r5),r29
12109d02a428SJonas Bonn	ENABLE_INTERRUPTS(r17)
12119d02a428SJonas Bonn	l.jr	r9
12129d02a428SJonas Bonn	 l.or	r11,r0,r0
12139d02a428SJonas Bonn
12149d02a428SJonas Bonn/* ============================================================[ EOF ]=== */
1215