xref: /openbmc/linux/arch/openrisc/kernel/entry.S (revision a0a94bc9)
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
32911648cbbSRandy Dunlap	/* call fault.c handler in openrisc/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
35111648cbbSRandy Dunlap	/* call fault.c handler in openrisc/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
550946e1052SRandy Dunlap#ifdef CONFIG_PRINTK
5519d02a428SJonas Bonn	l.addi  r1,r1,-0x8
5529d02a428SJonas Bonn	l.movhi r3,hi(42f)
5539d02a428SJonas Bonn	l.ori	r3,r3,lo(42f)
5549d02a428SJonas Bonn	l.sw    0x0(r1),r3
55533701557SChris Down	l.jal   _printk
5569d02a428SJonas Bonn	l.sw    0x4(r1),r4
5579d02a428SJonas Bonn	l.addi  r1,r1,0x8
5589d02a428SJonas Bonn
5599d02a428SJonas Bonn	.section .rodata, "a"
5609d02a428SJonas Bonn42:
5619d02a428SJonas Bonn		.string "\n\rESR interrupt bug: in _external_irq_handler (ESR %x)\n\r"
5629d02a428SJonas Bonn		.align 4
5639d02a428SJonas Bonn	.previous
564946e1052SRandy Dunlap#endif
5659d02a428SJonas Bonn
5669d02a428SJonas Bonn	l.ori	r4,r4,SPR_SR_IEE	// fix the bug
5679d02a428SJonas Bonn//	l.sw	PT_SR(r1),r4
5689d02a428SJonas Bonn1:
5699d02a428SJonas Bonn#endif
57063104c06SStefan Kristiansson	CLEAR_LWA_FLAG(r3)
5719d02a428SJonas Bonn	l.addi	r3,r1,0
572418360b2SMark Rutland	l.movhi	r8,hi(generic_handle_arch_irq)
573418360b2SMark Rutland	l.ori	r8,r8,lo(generic_handle_arch_irq)
5749d02a428SJonas Bonn	l.jalr r8
5759d02a428SJonas Bonn	l.nop
5769d02a428SJonas Bonn	l.j    _ret_from_intr
5779d02a428SJonas Bonn	l.nop
5789d02a428SJonas Bonn
5799d02a428SJonas Bonn/* ---[ 0x900: DTLB miss exception ]------------------------------------- */
5809d02a428SJonas Bonn
5819d02a428SJonas Bonn
5829d02a428SJonas Bonn/* ---[ 0xa00: ITLB miss exception ]------------------------------------- */
5839d02a428SJonas Bonn
5849d02a428SJonas Bonn
5859d02a428SJonas Bonn/* ---[ 0xb00: Range exception ]----------------------------------------- */
5869d02a428SJonas Bonn
5879d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0xb00,0xb00)
5889d02a428SJonas Bonn
5899d02a428SJonas Bonn/* ---[ 0xc00: Syscall exception ]--------------------------------------- */
5909d02a428SJonas Bonn
5919d02a428SJonas Bonn/*
5929d02a428SJonas Bonn * Syscalls are a special type of exception in that they are
5939d02a428SJonas Bonn * _explicitly_ invoked by userspace and can therefore be
5949d02a428SJonas Bonn * held to conform to the same ABI as normal functions with
5959d02a428SJonas Bonn * respect to whether registers are preserved across the call
5969d02a428SJonas Bonn * or not.
5979d02a428SJonas Bonn */
5989d02a428SJonas Bonn
5999d02a428SJonas Bonn/* Upon syscall entry we just save the callee-saved registers
6009d02a428SJonas Bonn * and not the call-clobbered ones.
6019d02a428SJonas Bonn */
6029d02a428SJonas Bonn
6039d02a428SJonas Bonn_string_syscall_return:
604*a0a94bc9SStafford Horne	.string "syscall r9:0x%08x -> syscall(%ld) return %ld\0"
6059d02a428SJonas Bonn	.align 4
6069d02a428SJonas Bonn
6079d02a428SJonas BonnENTRY(_sys_call_handler)
6089d02a428SJonas Bonn	/* r1, EPCR, ESR a already saved */
6099d02a428SJonas Bonn	l.sw	PT_GPR2(r1),r2
6109d02a428SJonas Bonn	/* r3-r8 must be saved because syscall restart relies
6119d02a428SJonas Bonn	 * on us being able to restart the syscall args... technically
6129d02a428SJonas Bonn	 * they should be clobbered, otherwise
6139d02a428SJonas Bonn	 */
6149d02a428SJonas Bonn	l.sw    PT_GPR3(r1),r3
61563104c06SStefan Kristiansson	/*
61663104c06SStefan Kristiansson	 * r4 already saved
61763104c06SStefan Kristiansson	 * r4 holds the EEAR address of the fault, use it as screatch reg and
61863104c06SStefan Kristiansson	 * then load the original r4
61963104c06SStefan Kristiansson	 */
62063104c06SStefan Kristiansson	CLEAR_LWA_FLAG(r4)
6219d02a428SJonas Bonn	l.lwz	r4,PT_GPR4(r1)
6229d02a428SJonas Bonn	l.sw    PT_GPR5(r1),r5
6239d02a428SJonas Bonn	l.sw    PT_GPR6(r1),r6
6249d02a428SJonas Bonn	l.sw    PT_GPR7(r1),r7
6259d02a428SJonas Bonn	l.sw    PT_GPR8(r1),r8
6269d02a428SJonas Bonn	l.sw    PT_GPR9(r1),r9
6279d02a428SJonas Bonn	/* r10 already saved */
6289d02a428SJonas Bonn	l.sw    PT_GPR11(r1),r11
6296cbe5e95SJonas Bonn	/* orig_gpr11 must be set for syscalls */
6309d02a428SJonas Bonn	l.sw    PT_ORIG_GPR11(r1),r11
6319d02a428SJonas Bonn	/* r12,r13 already saved */
6329d02a428SJonas Bonn
6339d02a428SJonas Bonn	/* r14-r28 (even) aren't touched by the syscall fast path below
6349d02a428SJonas Bonn	 * so we don't need to save them.  However, the functions that return
6359d02a428SJonas Bonn	 * to userspace via a call to switch() DO need to save these because
6369d02a428SJonas Bonn	 * switch() effectively clobbers them... saving these registers for
6379d02a428SJonas Bonn	 * such functions is handled in their syscall wrappers (see fork, vfork,
6389d02a428SJonas Bonn	 * and clone, below).
6399d02a428SJonas Bonn
6409d02a428SJonas Bonn	/* r30 is the only register we clobber in the fast path */
6419d02a428SJonas Bonn	/* r30 already saved */
6429d02a428SJonas Bonn/*	l.sw    PT_GPR30(r1),r30 */
6439d02a428SJonas Bonn
6449d02a428SJonas Bonn_syscall_check_trace_enter:
64578cdfb5cSStafford Horne	/* syscalls run with interrupts enabled */
64678cdfb5cSStafford Horne	TRACE_IRQS_ON_SYSCALL
64778cdfb5cSStafford Horne	ENABLE_INTERRUPTS(r29)		// enable interrupts, r29 is temp
64878cdfb5cSStafford Horne
6499d02a428SJonas Bonn	/* If TIF_SYSCALL_TRACE is set, then we want to do syscall tracing */
6509d02a428SJonas Bonn	l.lwz	r30,TI_FLAGS(r10)
6519d02a428SJonas Bonn	l.andi	r30,r30,_TIF_SYSCALL_TRACE
6529d02a428SJonas Bonn	l.sfne	r30,r0
6539d02a428SJonas Bonn	l.bf	_syscall_trace_enter
6549d02a428SJonas Bonn	 l.nop
6559d02a428SJonas Bonn
6569d02a428SJonas Bonn_syscall_check:
6579d02a428SJonas Bonn	/* Ensure that the syscall number is reasonable */
6589d02a428SJonas Bonn	l.sfgeui r11,__NR_syscalls
6599d02a428SJonas Bonn	l.bf	_syscall_badsys
6609d02a428SJonas Bonn	 l.nop
6619d02a428SJonas Bonn
6629d02a428SJonas Bonn_syscall_call:
6639d02a428SJonas Bonn	l.movhi r29,hi(sys_call_table)
6649d02a428SJonas Bonn	l.ori   r29,r29,lo(sys_call_table)
6659d02a428SJonas Bonn	l.slli  r11,r11,2
6669d02a428SJonas Bonn	l.add   r29,r29,r11
6679d02a428SJonas Bonn	l.lwz   r29,0(r29)
6689d02a428SJonas Bonn
6699d02a428SJonas Bonn	l.jalr  r29
6709d02a428SJonas Bonn	 l.nop
6719d02a428SJonas Bonn
6729d02a428SJonas Bonn_syscall_return:
6739d02a428SJonas Bonn	/* All syscalls return here... just pay attention to ret_from_fork
6749d02a428SJonas Bonn	 * which does it in a round-about way.
6759d02a428SJonas Bonn	 */
6769d02a428SJonas Bonn	l.sw    PT_GPR11(r1),r11           // save return value
6779d02a428SJonas Bonn
6789d02a428SJonas Bonn#if 0
6799d02a428SJonas Bonn_syscall_debug:
6809d02a428SJonas Bonn	l.movhi r3,hi(_string_syscall_return)
6819d02a428SJonas Bonn	l.ori   r3,r3,lo(_string_syscall_return)
682*a0a94bc9SStafford Horne	l.ori   r27,r0,2
6839d02a428SJonas Bonn	l.sw    -4(r1),r27
6849d02a428SJonas Bonn	l.sw    -8(r1),r11
685*a0a94bc9SStafford Horne	l.lwz	r29,PT_ORIG_GPR11(r1)
686*a0a94bc9SStafford Horne	l.sw    -12(r1),r29
687*a0a94bc9SStafford Horne	l.lwz	r29,PT_GPR9(r1)
688*a0a94bc9SStafford Horne	l.sw    -16(r1),r29
68933701557SChris Down	l.movhi r27,hi(_printk)
69033701557SChris Down	l.ori   r27,r27,lo(_printk)
6919d02a428SJonas Bonn	l.jalr  r27
692*a0a94bc9SStafford Horne	 l.addi  r1,r1,-16
693*a0a94bc9SStafford Horne	l.addi  r1,r1,16
694*a0a94bc9SStafford Horne#endif
695*a0a94bc9SStafford Horne#if 0
696*a0a94bc9SStafford Horne_syscall_show_regs:
697*a0a94bc9SStafford Horne	l.movhi r27,hi(show_registers)
698*a0a94bc9SStafford Horne	l.ori   r27,r27,lo(show_registers)
699*a0a94bc9SStafford Horne	l.jalr  r27
700*a0a94bc9SStafford Horne	 l.or	r3,r1,r1
7019d02a428SJonas Bonn#endif
7029d02a428SJonas Bonn
7039d02a428SJonas Bonn_syscall_check_trace_leave:
7049d02a428SJonas Bonn	/* r30 is a callee-saved register so this should still hold the
7059d02a428SJonas Bonn	 * _TIF_SYSCALL_TRACE flag from _syscall_check_trace_enter above...
7069d02a428SJonas Bonn	 * _syscall_trace_leave expects syscall result to be in pt_regs->r11.
7079d02a428SJonas Bonn	 */
7089d02a428SJonas Bonn	l.sfne	r30,r0
7099d02a428SJonas Bonn	l.bf	_syscall_trace_leave
7109d02a428SJonas Bonn	 l.nop
7119d02a428SJonas Bonn
7129d02a428SJonas Bonn/* This is where the exception-return code begins... interrupts need to be
7139d02a428SJonas Bonn * disabled the rest of the way here because we can't afford to miss any
7149d02a428SJonas Bonn * interrupts that set NEED_RESCHED or SIGNALPENDING... really true? */
7159d02a428SJonas Bonn
7169d02a428SJonas Bonn_syscall_check_work:
7179d02a428SJonas Bonn	/* Here we need to disable interrupts */
7189d02a428SJonas Bonn	DISABLE_INTERRUPTS(r27,r29)
71978cdfb5cSStafford Horne	TRACE_IRQS_OFF
7209d02a428SJonas Bonn	l.lwz	r30,TI_FLAGS(r10)
7219d02a428SJonas Bonn	l.andi	r30,r30,_TIF_WORK_MASK
7229d02a428SJonas Bonn	l.sfne	r30,r0
7239d02a428SJonas Bonn
7249d02a428SJonas Bonn	l.bnf	_syscall_resume_userspace
7259d02a428SJonas Bonn	 l.nop
7269d02a428SJonas Bonn
7279d02a428SJonas Bonn	/* Work pending follows a different return path, so we need to
7289d02a428SJonas Bonn	 * make sure that all the call-saved registers get into pt_regs
7299d02a428SJonas Bonn	 * before branching...
7309d02a428SJonas Bonn	 */
7319d02a428SJonas Bonn	l.sw    PT_GPR14(r1),r14
7329d02a428SJonas Bonn	l.sw    PT_GPR16(r1),r16
7339d02a428SJonas Bonn	l.sw    PT_GPR18(r1),r18
7349d02a428SJonas Bonn	l.sw    PT_GPR20(r1),r20
7359d02a428SJonas Bonn	l.sw    PT_GPR22(r1),r22
7369d02a428SJonas Bonn	l.sw    PT_GPR24(r1),r24
7379d02a428SJonas Bonn	l.sw    PT_GPR26(r1),r26
7389d02a428SJonas Bonn	l.sw    PT_GPR28(r1),r28
7399d02a428SJonas Bonn
7409d02a428SJonas Bonn	/* _work_pending needs to be called with interrupts disabled */
7419d02a428SJonas Bonn	l.j	_work_pending
7429d02a428SJonas Bonn	 l.nop
7439d02a428SJonas Bonn
7449d02a428SJonas Bonn_syscall_resume_userspace:
7459d02a428SJonas Bonn//	ENABLE_INTERRUPTS(r29)
7469d02a428SJonas Bonn
7479d02a428SJonas Bonn
7489d02a428SJonas Bonn/* This is the hot path for returning to userspace from a syscall.  If there's
7499d02a428SJonas Bonn * work to be done and the branch to _work_pending was taken above, then the
7509d02a428SJonas Bonn * return to userspace will be done via the normal exception return path...
7519d02a428SJonas Bonn * that path restores _all_ registers and will overwrite the "clobbered"
7529d02a428SJonas Bonn * registers with whatever garbage is in pt_regs -- that's OK because those
7539d02a428SJonas Bonn * registers are clobbered anyway and because the extra work is insignificant
7549d02a428SJonas Bonn * in the context of the extra work that _work_pending is doing.
7559d02a428SJonas Bonn
7569d02a428SJonas Bonn/* Once again, syscalls are special and only guarantee to preserve the
7579d02a428SJonas Bonn * same registers as a normal function call */
7589d02a428SJonas Bonn
7599d02a428SJonas Bonn/* The assumption here is that the registers r14-r28 (even) are untouched and
7609d02a428SJonas Bonn * don't need to be restored... be sure that that's really the case!
7619d02a428SJonas Bonn */
7629d02a428SJonas Bonn
7639d02a428SJonas Bonn/* This is still too much... we should only be restoring what we actually
7649d02a428SJonas Bonn * clobbered... we should even be using 'scratch' (odd) regs above so that
7659d02a428SJonas Bonn * we don't need to restore anything, hardly...
7669d02a428SJonas Bonn */
7679d02a428SJonas Bonn
7689d02a428SJonas Bonn	l.lwz	r2,PT_GPR2(r1)
7699d02a428SJonas Bonn
7709d02a428SJonas Bonn	/* Restore args */
7719d02a428SJonas Bonn	/* r3-r8 are technically clobbered, but syscall restart needs these
7729d02a428SJonas Bonn	 * to be restored...
7739d02a428SJonas Bonn	 */
7749d02a428SJonas Bonn	l.lwz	r3,PT_GPR3(r1)
7759d02a428SJonas Bonn	l.lwz	r4,PT_GPR4(r1)
7769d02a428SJonas Bonn	l.lwz	r5,PT_GPR5(r1)
7779d02a428SJonas Bonn	l.lwz	r6,PT_GPR6(r1)
7789d02a428SJonas Bonn	l.lwz	r7,PT_GPR7(r1)
7799d02a428SJonas Bonn	l.lwz	r8,PT_GPR8(r1)
7809d02a428SJonas Bonn
7819d02a428SJonas Bonn	l.lwz	r9,PT_GPR9(r1)
7829d02a428SJonas Bonn	l.lwz	r10,PT_GPR10(r1)
7839d02a428SJonas Bonn	l.lwz	r11,PT_GPR11(r1)
7849d02a428SJonas Bonn
7859d02a428SJonas Bonn	/* r30 is the only register we clobber in the fast path */
7869d02a428SJonas Bonn	l.lwz	r30,PT_GPR30(r1)
7879d02a428SJonas Bonn
7889d02a428SJonas Bonn	/* Here we use r13-r19 (odd) as scratch regs */
7899d02a428SJonas Bonn	l.lwz   r13,PT_PC(r1)
7909d02a428SJonas Bonn	l.lwz   r15,PT_SR(r1)
7919d02a428SJonas Bonn	l.lwz	r1,PT_SP(r1)
7929d02a428SJonas Bonn	/* Interrupts need to be disabled for setting EPCR and ESR
7939d02a428SJonas Bonn	 * so that another interrupt doesn't come in here and clobber
7949d02a428SJonas Bonn	 * them before we can use them for our l.rfe */
7959d02a428SJonas Bonn	DISABLE_INTERRUPTS(r17,r19)
7969d02a428SJonas Bonn	l.mtspr r0,r13,SPR_EPCR_BASE
7979d02a428SJonas Bonn	l.mtspr r0,r15,SPR_ESR_BASE
7989d02a428SJonas Bonn	l.rfe
7999d02a428SJonas Bonn
8009d02a428SJonas Bonn/* End of hot path!
8019d02a428SJonas Bonn * Keep the below tracing and error handling out of the hot path...
8029d02a428SJonas Bonn*/
8039d02a428SJonas Bonn
8049d02a428SJonas Bonn_syscall_trace_enter:
8059d02a428SJonas Bonn	/* Here we pass pt_regs to do_syscall_trace_enter.  Make sure
8069d02a428SJonas Bonn	 * that function is really getting all the info it needs as
8079d02a428SJonas Bonn	 * pt_regs isn't a complete set of userspace regs, just the
8089d02a428SJonas Bonn	 * ones relevant to the syscall...
8099d02a428SJonas Bonn	 *
8109d02a428SJonas Bonn	 * Note use of delay slot for setting argument.
8119d02a428SJonas Bonn	 */
8129d02a428SJonas Bonn	l.jal	do_syscall_trace_enter
8139d02a428SJonas Bonn	 l.addi	r3,r1,0
8149d02a428SJonas Bonn
8159d02a428SJonas Bonn	/* Restore arguments (not preserved across do_syscall_trace_enter)
8169d02a428SJonas Bonn	 * so that we can do the syscall for real and return to the syscall
8179d02a428SJonas Bonn	 * hot path.
8189d02a428SJonas Bonn	 */
8196cbe5e95SJonas Bonn	l.lwz	r11,PT_GPR11(r1)
8209d02a428SJonas Bonn	l.lwz	r3,PT_GPR3(r1)
8219d02a428SJonas Bonn	l.lwz	r4,PT_GPR4(r1)
8229d02a428SJonas Bonn	l.lwz	r5,PT_GPR5(r1)
8239d02a428SJonas Bonn	l.lwz	r6,PT_GPR6(r1)
8249d02a428SJonas Bonn	l.lwz	r7,PT_GPR7(r1)
8259d02a428SJonas Bonn
8269d02a428SJonas Bonn	l.j	_syscall_check
8279d02a428SJonas Bonn	 l.lwz	r8,PT_GPR8(r1)
8289d02a428SJonas Bonn
8299d02a428SJonas Bonn_syscall_trace_leave:
8309d02a428SJonas Bonn	l.jal	do_syscall_trace_leave
8319d02a428SJonas Bonn	 l.addi	r3,r1,0
8329d02a428SJonas Bonn
8339d02a428SJonas Bonn	l.j	_syscall_check_work
8349d02a428SJonas Bonn	 l.nop
8359d02a428SJonas Bonn
8369d02a428SJonas Bonn_syscall_badsys:
8379d02a428SJonas Bonn	/* Here we effectively pretend to have executed an imaginary
8389d02a428SJonas Bonn	 * syscall that returns -ENOSYS and then return to the regular
8399d02a428SJonas Bonn	 * syscall hot path.
8409d02a428SJonas Bonn	 * Note that "return value" is set in the delay slot...
8419d02a428SJonas Bonn	 */
8429d02a428SJonas Bonn	l.j	_syscall_return
8439d02a428SJonas Bonn	 l.addi	r11,r0,-ENOSYS
8449d02a428SJonas Bonn
8459d02a428SJonas Bonn/******* END SYSCALL HANDLING *******/
8469d02a428SJonas Bonn
8479d02a428SJonas Bonn/* ---[ 0xd00: Trap exception ]------------------------------------------ */
8489d02a428SJonas Bonn
8499d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0xd00,0xd00)
8509d02a428SJonas Bonn
8519d02a428SJonas Bonn/* ---[ 0xe00: Trap exception ]------------------------------------------ */
8529d02a428SJonas Bonn
8539d02a428SJonas BonnEXCEPTION_ENTRY(_trap_handler)
85463104c06SStefan Kristiansson	CLEAR_LWA_FLAG(r3)
8559d02a428SJonas Bonn	/* r4: EA of fault (set by EXCEPTION_HANDLE) */
8569d02a428SJonas Bonn	l.jal   do_trap
8579d02a428SJonas Bonn	 l.addi  r3,r1,0 /* pt_regs */
8589d02a428SJonas Bonn
8599d02a428SJonas Bonn	l.j     _ret_from_exception
8609d02a428SJonas Bonn	 l.nop
8619d02a428SJonas Bonn
8629d02a428SJonas Bonn/* ---[ 0xf00: Reserved exception ]-------------------------------------- */
8639d02a428SJonas Bonn
8649d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0xf00,0xf00)
8659d02a428SJonas Bonn
8669d02a428SJonas Bonn/* ---[ 0x1000: Reserved exception ]------------------------------------- */
8679d02a428SJonas Bonn
8689d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1000,0x1000)
8699d02a428SJonas Bonn
8709d02a428SJonas Bonn/* ---[ 0x1100: Reserved exception ]------------------------------------- */
8719d02a428SJonas Bonn
8729d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1100,0x1100)
8739d02a428SJonas Bonn
8749d02a428SJonas Bonn/* ---[ 0x1200: Reserved exception ]------------------------------------- */
8759d02a428SJonas Bonn
8769d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1200,0x1200)
8779d02a428SJonas Bonn
8789d02a428SJonas Bonn/* ---[ 0x1300: Reserved exception ]------------------------------------- */
8799d02a428SJonas Bonn
8809d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1300,0x1300)
8819d02a428SJonas Bonn
8829d02a428SJonas Bonn/* ---[ 0x1400: Reserved exception ]------------------------------------- */
8839d02a428SJonas Bonn
8849d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1400,0x1400)
8859d02a428SJonas Bonn
8869d02a428SJonas Bonn/* ---[ 0x1500: Reserved exception ]------------------------------------- */
8879d02a428SJonas Bonn
8889d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1500,0x1500)
8899d02a428SJonas Bonn
8909d02a428SJonas Bonn/* ---[ 0x1600: Reserved exception ]------------------------------------- */
8919d02a428SJonas Bonn
8929d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1600,0x1600)
8939d02a428SJonas Bonn
8949d02a428SJonas Bonn/* ---[ 0x1700: Reserved exception ]------------------------------------- */
8959d02a428SJonas Bonn
8969d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1700,0x1700)
8979d02a428SJonas Bonn
8989d02a428SJonas Bonn/* ---[ 0x1800: Reserved exception ]------------------------------------- */
8999d02a428SJonas Bonn
9009d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1800,0x1800)
9019d02a428SJonas Bonn
9029d02a428SJonas Bonn/* ---[ 0x1900: Reserved exception ]------------------------------------- */
9039d02a428SJonas Bonn
9049d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1900,0x1900)
9059d02a428SJonas Bonn
9069d02a428SJonas Bonn/* ---[ 0x1a00: Reserved exception ]------------------------------------- */
9079d02a428SJonas Bonn
9089d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1a00,0x1a00)
9099d02a428SJonas Bonn
9109d02a428SJonas Bonn/* ---[ 0x1b00: Reserved exception ]------------------------------------- */
9119d02a428SJonas Bonn
9129d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1b00,0x1b00)
9139d02a428SJonas Bonn
9149d02a428SJonas Bonn/* ---[ 0x1c00: Reserved exception ]------------------------------------- */
9159d02a428SJonas Bonn
9169d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1c00,0x1c00)
9179d02a428SJonas Bonn
9189d02a428SJonas Bonn/* ---[ 0x1d00: Reserved exception ]------------------------------------- */
9199d02a428SJonas Bonn
9209d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1d00,0x1d00)
9219d02a428SJonas Bonn
9229d02a428SJonas Bonn/* ---[ 0x1e00: Reserved exception ]------------------------------------- */
9239d02a428SJonas Bonn
9249d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1e00,0x1e00)
9259d02a428SJonas Bonn
9269d02a428SJonas Bonn/* ---[ 0x1f00: Reserved exception ]------------------------------------- */
9279d02a428SJonas Bonn
9289d02a428SJonas BonnUNHANDLED_EXCEPTION(_vector_0x1f00,0x1f00)
9299d02a428SJonas Bonn
9309d02a428SJonas Bonn/* ========================================================[ return ] === */
9319d02a428SJonas Bonn
9329d02a428SJonas Bonn_resume_userspace:
9339d02a428SJonas Bonn	DISABLE_INTERRUPTS(r3,r4)
93478cdfb5cSStafford Horne	TRACE_IRQS_OFF
93510f67dbfSJonas Bonn	l.lwz	r4,TI_FLAGS(r10)
93610f67dbfSJonas Bonn	l.andi	r13,r4,_TIF_WORK_MASK
93710f67dbfSJonas Bonn	l.sfeqi	r13,0
93810f67dbfSJonas Bonn	l.bf	_restore_all
9399d02a428SJonas Bonn	 l.nop
9409d02a428SJonas Bonn
94110f67dbfSJonas Bonn_work_pending:
94210f67dbfSJonas Bonn	l.lwz	r5,PT_ORIG_GPR11(r1)
94310f67dbfSJonas Bonn	l.sfltsi r5,0
94410f67dbfSJonas Bonn	l.bnf	1f
94510f67dbfSJonas Bonn	 l.nop
94610f67dbfSJonas Bonn	l.andi	r5,r5,0
94710f67dbfSJonas Bonn1:
94810f67dbfSJonas Bonn	l.jal	do_work_pending
94910f67dbfSJonas Bonn	 l.ori	r3,r1,0			/* pt_regs */
95010f67dbfSJonas Bonn
95110f67dbfSJonas Bonn	l.sfeqi	r11,0
95210f67dbfSJonas Bonn	l.bf	_restore_all
95310f67dbfSJonas Bonn	 l.nop
95410f67dbfSJonas Bonn	l.sfltsi r11,0
95510f67dbfSJonas Bonn	l.bnf	1f
95610f67dbfSJonas Bonn	 l.nop
95710f67dbfSJonas Bonn	l.and	r11,r11,r0
95810f67dbfSJonas Bonn	l.ori	r11,r11,__NR_restart_syscall
95910f67dbfSJonas Bonn	l.j	_syscall_check_trace_enter
96010f67dbfSJonas Bonn	 l.nop
96110f67dbfSJonas Bonn1:
96210f67dbfSJonas Bonn	l.lwz	r11,PT_ORIG_GPR11(r1)
96310f67dbfSJonas Bonn	/* Restore arg registers */
96410f67dbfSJonas Bonn	l.lwz	r3,PT_GPR3(r1)
96510f67dbfSJonas Bonn	l.lwz	r4,PT_GPR4(r1)
96610f67dbfSJonas Bonn	l.lwz	r5,PT_GPR5(r1)
96710f67dbfSJonas Bonn	l.lwz	r6,PT_GPR6(r1)
96810f67dbfSJonas Bonn	l.lwz	r7,PT_GPR7(r1)
96910f67dbfSJonas Bonn	l.j	_syscall_check_trace_enter
97010f67dbfSJonas Bonn	 l.lwz	r8,PT_GPR8(r1)
97110f67dbfSJonas Bonn
9729d02a428SJonas Bonn_restore_all:
97378cdfb5cSStafford Horne#ifdef CONFIG_TRACE_IRQFLAGS
97478cdfb5cSStafford Horne	l.lwz	r4,PT_SR(r1)
97578cdfb5cSStafford Horne	l.andi	r3,r4,(SPR_SR_IEE|SPR_SR_TEE)
97678cdfb5cSStafford Horne	l.sfeq	r3,r0		/* skip trace if irqs were off */
97778cdfb5cSStafford Horne	l.bf	skip_hardirqs_on
97878cdfb5cSStafford Horne	 l.nop
97978cdfb5cSStafford Horne	TRACE_IRQS_ON
98078cdfb5cSStafford Horneskip_hardirqs_on:
98178cdfb5cSStafford Horne#endif
9829d02a428SJonas Bonn	RESTORE_ALL
9839d02a428SJonas Bonn	/* This returns to userspace code */
9849d02a428SJonas Bonn
9859d02a428SJonas Bonn
9869d02a428SJonas BonnENTRY(_ret_from_intr)
9879d02a428SJonas BonnENTRY(_ret_from_exception)
9889d02a428SJonas Bonn	l.lwz	r4,PT_SR(r1)
9899d02a428SJonas Bonn	l.andi	r3,r4,SPR_SR_SM
9909d02a428SJonas Bonn	l.sfeqi	r3,0
9919d02a428SJonas Bonn	l.bnf	_restore_all
9929d02a428SJonas Bonn	 l.nop
9939d02a428SJonas Bonn	l.j	_resume_userspace
9949d02a428SJonas Bonn	 l.nop
9959d02a428SJonas Bonn
9969d02a428SJonas BonnENTRY(ret_from_fork)
9979d02a428SJonas Bonn	l.jal	schedule_tail
9989d02a428SJonas Bonn	 l.nop
9999d02a428SJonas Bonn
1000cbf23cf1SJonas Bonn	/* Check if we are a kernel thread */
1001cbf23cf1SJonas Bonn	l.sfeqi	r20,0
1002cbf23cf1SJonas Bonn	l.bf	1f
1003cbf23cf1SJonas Bonn	 l.nop
1004cbf23cf1SJonas Bonn
1005cbf23cf1SJonas Bonn	/* ...we are a kernel thread so invoke the requested callback */
1006cbf23cf1SJonas Bonn	l.jalr	r20
1007cbf23cf1SJonas Bonn	 l.or	r3,r22,r0
1008cbf23cf1SJonas Bonn
1009cbf23cf1SJonas Bonn1:
10109d02a428SJonas Bonn	/* _syscall_returns expect r11 to contain return value */
10119d02a428SJonas Bonn	l.lwz	r11,PT_GPR11(r1)
10129d02a428SJonas Bonn
10139d02a428SJonas Bonn	/* The syscall fast path return expects call-saved registers
1014840b66c2SStafford Horne	 * r14-r28 to be untouched, so we restore them here as they
10159d02a428SJonas Bonn	 * will have been effectively clobbered when arriving here
10169d02a428SJonas Bonn	 * via the call to switch()
10179d02a428SJonas Bonn	 */
10189d02a428SJonas Bonn	l.lwz	r14,PT_GPR14(r1)
10199d02a428SJonas Bonn	l.lwz	r16,PT_GPR16(r1)
10209d02a428SJonas Bonn	l.lwz	r18,PT_GPR18(r1)
10219d02a428SJonas Bonn	l.lwz	r20,PT_GPR20(r1)
10229d02a428SJonas Bonn	l.lwz	r22,PT_GPR22(r1)
10239d02a428SJonas Bonn	l.lwz	r24,PT_GPR24(r1)
10249d02a428SJonas Bonn	l.lwz	r26,PT_GPR26(r1)
10259d02a428SJonas Bonn	l.lwz	r28,PT_GPR28(r1)
10269d02a428SJonas Bonn
10279d02a428SJonas Bonn	l.j	_syscall_return
10289d02a428SJonas Bonn	 l.nop
10299d02a428SJonas Bonn
10309d02a428SJonas Bonn/* ========================================================[ switch ] === */
10319d02a428SJonas Bonn
10329d02a428SJonas Bonn/*
10339d02a428SJonas Bonn * This routine switches between two different tasks.  The process
10349d02a428SJonas Bonn * state of one is saved on its kernel stack.  Then the state
10359d02a428SJonas Bonn * of the other is restored from its kernel stack.  The memory
10369d02a428SJonas Bonn * management hardware is updated to the second process's state.
10379d02a428SJonas Bonn * Finally, we can return to the second process, via the 'return'.
10389d02a428SJonas Bonn *
10399d02a428SJonas Bonn * Note: there are two ways to get to the "going out" portion
10409d02a428SJonas Bonn * of this code; either by coming in via the entry (_switch)
10419d02a428SJonas Bonn * or via "fork" which must set up an environment equivalent
10429d02a428SJonas Bonn * to the "_switch" path.  If you change this (or in particular, the
10439d02a428SJonas Bonn * SAVE_REGS macro), you'll have to change the fork code also.
10449d02a428SJonas Bonn */
10459d02a428SJonas Bonn
10469d02a428SJonas Bonn
10479d02a428SJonas Bonn/* _switch MUST never lay on page boundry, cause it runs from
10489d02a428SJonas Bonn * effective addresses and beeing interrupted by iTLB miss would kill it.
1049840b66c2SStafford Horne * dTLB miss seems to never accour in the bad place since data accesses
10509d02a428SJonas Bonn * are from task structures which are always page aligned.
10519d02a428SJonas Bonn *
1052840b66c2SStafford Horne * The problem happens in RESTORE_ALL where we first set the EPCR
10539d02a428SJonas Bonn * register, then load the previous register values and only at the end call
10549d02a428SJonas Bonn * the l.rfe instruction. If get TLB miss in beetwen the EPCR register gets
10559d02a428SJonas Bonn * garbled and we end up calling l.rfe with the wrong EPCR. (same probably
10569d02a428SJonas Bonn * holds for ESR)
10579d02a428SJonas Bonn *
10589d02a428SJonas Bonn * To avoid this problems it is sufficient to align _switch to
10599d02a428SJonas Bonn * some nice round number smaller than it's size...
10609d02a428SJonas Bonn */
10619d02a428SJonas Bonn
10629d02a428SJonas Bonn/* ABI rules apply here... we either enter _switch via schedule() or via
10639d02a428SJonas Bonn * an imaginary call to which we shall return at return_from_fork.  Either
10649d02a428SJonas Bonn * way, we are a function call and only need to preserve the callee-saved
10659d02a428SJonas Bonn * registers when we return.  As such, we don't need to save the registers
10669d02a428SJonas Bonn * on the stack that we won't be returning as they were...
10679d02a428SJonas Bonn */
10689d02a428SJonas Bonn
10699d02a428SJonas Bonn	.align 0x400
10709d02a428SJonas BonnENTRY(_switch)
10719d02a428SJonas Bonn	/* We don't store SR as _switch only gets called in a context where
10729d02a428SJonas Bonn	 * the SR will be the same going in and coming out... */
10739d02a428SJonas Bonn
10749d02a428SJonas Bonn	/* Set up new pt_regs struct for saving task state */
10759d02a428SJonas Bonn	l.addi  r1,r1,-(INT_FRAME_SIZE)
10769d02a428SJonas Bonn
10779d02a428SJonas Bonn	/* No need to store r1/PT_SP as it goes into KSP below */
10789d02a428SJonas Bonn	l.sw    PT_GPR2(r1),r2
10799d02a428SJonas Bonn	l.sw    PT_GPR9(r1),r9
1080840b66c2SStafford Horne
1081840b66c2SStafford Horne	/* Save callee-saved registers to the new pt_regs */
10829d02a428SJonas Bonn	l.sw    PT_GPR14(r1),r14
10839d02a428SJonas Bonn	l.sw    PT_GPR16(r1),r16
10849d02a428SJonas Bonn	l.sw    PT_GPR18(r1),r18
10859d02a428SJonas Bonn	l.sw    PT_GPR20(r1),r20
10869d02a428SJonas Bonn	l.sw    PT_GPR22(r1),r22
10879d02a428SJonas Bonn	l.sw    PT_GPR24(r1),r24
10889d02a428SJonas Bonn	l.sw    PT_GPR26(r1),r26
10899d02a428SJonas Bonn	l.sw    PT_GPR28(r1),r28
10909d02a428SJonas Bonn	l.sw    PT_GPR30(r1),r30
10919d02a428SJonas Bonn
10929d02a428SJonas Bonn	l.addi	r11,r10,0			/* Save old 'current' to 'last' return value*/
10939d02a428SJonas Bonn
10949d02a428SJonas Bonn	/* We use thread_info->ksp for storing the address of the above
10959d02a428SJonas Bonn	 * structure so that we can get back to it later... we don't want
10969d02a428SJonas Bonn	 * to lose the value of thread_info->ksp, though, so store it as
10979d02a428SJonas Bonn	 * pt_regs->sp so that we can easily restore it when we are made
10989d02a428SJonas Bonn	 * live again...
10999d02a428SJonas Bonn	 */
11009d02a428SJonas Bonn
11019d02a428SJonas Bonn	/* Save the old value of thread_info->ksp as pt_regs->sp */
11029d02a428SJonas Bonn	l.lwz	r29,TI_KSP(r10)
11039d02a428SJonas Bonn	l.sw	PT_SP(r1),r29
11049d02a428SJonas Bonn
11059d02a428SJonas Bonn	/* Swap kernel stack pointers */
11069d02a428SJonas Bonn	l.sw    TI_KSP(r10),r1			/* Save old stack pointer */
11079d02a428SJonas Bonn	l.or	r10,r4,r0			/* Set up new current_thread_info */
11089d02a428SJonas Bonn	l.lwz   r1,TI_KSP(r10)			/* Load new stack pointer */
11099d02a428SJonas Bonn
11109d02a428SJonas Bonn	/* Restore the old value of thread_info->ksp */
11119d02a428SJonas Bonn	l.lwz	r29,PT_SP(r1)
11129d02a428SJonas Bonn	l.sw	TI_KSP(r10),r29
11139d02a428SJonas Bonn
11149d02a428SJonas Bonn	/* ...and restore the registers, except r11 because the return value
11159d02a428SJonas Bonn	 * has already been set above.
11169d02a428SJonas Bonn	 */
11179d02a428SJonas Bonn	l.lwz   r2,PT_GPR2(r1)
11189d02a428SJonas Bonn	l.lwz   r9,PT_GPR9(r1)
11199d02a428SJonas Bonn	/* No need to restore r10 */
11209d02a428SJonas Bonn	/* ...and do not restore r11 */
11219d02a428SJonas Bonn
1122840b66c2SStafford Horne	/* Restore callee-saved registers */
11239d02a428SJonas Bonn	l.lwz   r14,PT_GPR14(r1)
11249d02a428SJonas Bonn	l.lwz   r16,PT_GPR16(r1)
11259d02a428SJonas Bonn	l.lwz   r18,PT_GPR18(r1)
11269d02a428SJonas Bonn	l.lwz   r20,PT_GPR20(r1)
11279d02a428SJonas Bonn	l.lwz   r22,PT_GPR22(r1)
11289d02a428SJonas Bonn	l.lwz   r24,PT_GPR24(r1)
11299d02a428SJonas Bonn	l.lwz   r26,PT_GPR26(r1)
11309d02a428SJonas Bonn	l.lwz   r28,PT_GPR28(r1)
11319d02a428SJonas Bonn	l.lwz   r30,PT_GPR30(r1)
11329d02a428SJonas Bonn
11339d02a428SJonas Bonn	/* Unwind stack to pre-switch state */
11349d02a428SJonas Bonn	l.addi  r1,r1,(INT_FRAME_SIZE)
11359d02a428SJonas Bonn
1136287ad220SJonas Bonn	/* Return via the link-register back to where we 'came from', where
1137287ad220SJonas Bonn	 * that may be either schedule(), ret_from_fork(), or
1138287ad220SJonas Bonn	 * ret_from_kernel_thread().  If we are returning to a new thread,
1139287ad220SJonas Bonn	 * we are expected to have set up the arg to schedule_tail already,
1140287ad220SJonas Bonn	 * hence we do so here unconditionally:
1141287ad220SJonas Bonn	 */
1142ae6fef17SJonas Bonn	l.lwz   r3,TI_TASK(r3)		/* Load 'prev' as schedule_tail arg */
11439d02a428SJonas Bonn	l.jr	r9
11449d02a428SJonas Bonn	 l.nop
11459d02a428SJonas Bonn
11469d02a428SJonas Bonn/* ==================================================================== */
11479d02a428SJonas Bonn
11489d02a428SJonas Bonn/* These all use the delay slot for setting the argument register, so the
11499d02a428SJonas Bonn * jump is always happening after the l.addi instruction.
11509d02a428SJonas Bonn *
11519d02a428SJonas Bonn * These are all just wrappers that don't touch the link-register r9, so the
11529d02a428SJonas Bonn * return from the "real" syscall function will return back to the syscall
11539d02a428SJonas Bonn * code that did the l.jal that brought us here.
11549d02a428SJonas Bonn */
11559d02a428SJonas Bonn
11569d02a428SJonas Bonn/* fork requires that we save all the callee-saved registers because they
11579d02a428SJonas Bonn * are all effectively clobbered by the call to _switch.  Here we store
11589d02a428SJonas Bonn * all the registers that aren't touched by the syscall fast path and thus
11599d02a428SJonas Bonn * weren't saved there.
11609d02a428SJonas Bonn */
11619d02a428SJonas Bonn
11629d02a428SJonas Bonn_fork_save_extra_regs_and_call:
11639d02a428SJonas Bonn	l.sw    PT_GPR14(r1),r14
11649d02a428SJonas Bonn	l.sw    PT_GPR16(r1),r16
11659d02a428SJonas Bonn	l.sw    PT_GPR18(r1),r18
11669d02a428SJonas Bonn	l.sw    PT_GPR20(r1),r20
11679d02a428SJonas Bonn	l.sw    PT_GPR22(r1),r22
11689d02a428SJonas Bonn	l.sw    PT_GPR24(r1),r24
11699d02a428SJonas Bonn	l.sw    PT_GPR26(r1),r26
11709d02a428SJonas Bonn	l.jr	r29
11719d02a428SJonas Bonn	 l.sw    PT_GPR28(r1),r28
11729d02a428SJonas Bonn
117339d91a9eSAl ViroENTRY(__sys_clone)
117439d91a9eSAl Viro	l.movhi	r29,hi(sys_clone)
11759d02a428SJonas Bonn	l.j	_fork_save_extra_regs_and_call
117607baf50aSStafford Horne	 l.ori	r29,r29,lo(sys_clone)
11779d02a428SJonas Bonn
1178433fe39fSStafford HorneENTRY(__sys_clone3)
1179433fe39fSStafford Horne	l.movhi	r29,hi(sys_clone3)
1180433fe39fSStafford Horne	l.j	_fork_save_extra_regs_and_call
1181433fe39fSStafford Horne	 l.ori	r29,r29,lo(sys_clone3)
1182433fe39fSStafford Horne
118339d91a9eSAl ViroENTRY(__sys_fork)
118439d91a9eSAl Viro	l.movhi	r29,hi(sys_fork)
11859d02a428SJonas Bonn	l.j	_fork_save_extra_regs_and_call
118607baf50aSStafford Horne	 l.ori	r29,r29,lo(sys_fork)
11879d02a428SJonas Bonn
11889d02a428SJonas BonnENTRY(sys_rt_sigreturn)
1189c7990219SJonas Bonn	l.jal	_sys_rt_sigreturn
11909d02a428SJonas Bonn	 l.addi	r3,r1,0
1191c7990219SJonas Bonn	l.sfne	r30,r0
1192c7990219SJonas Bonn	l.bnf	_no_syscall_trace
1193c7990219SJonas Bonn	 l.nop
1194c7990219SJonas Bonn	l.jal	do_syscall_trace_leave
1195c7990219SJonas Bonn	 l.addi	r3,r1,0
1196c7990219SJonas Bonn_no_syscall_trace:
1197c7990219SJonas Bonn	l.j	_resume_userspace
1198c7990219SJonas Bonn	 l.nop
11999d02a428SJonas Bonn
12009d02a428SJonas Bonn/* This is a catch-all syscall for atomic instructions for the OpenRISC 1000.
12019d02a428SJonas Bonn * The functions takes a variable number of parameters depending on which
12029d02a428SJonas Bonn * particular flavour of atomic you want... parameter 1 is a flag identifying
12039d02a428SJonas Bonn * the atomic in question.  Currently, this function implements the
12049d02a428SJonas Bonn * following variants:
12059d02a428SJonas Bonn *
12069d02a428SJonas Bonn * XCHG:
12079d02a428SJonas Bonn *  @flag: 1
12089d02a428SJonas Bonn *  @ptr1:
12099d02a428SJonas Bonn *  @ptr2:
12109d02a428SJonas Bonn * Atomically exchange the values in pointers 1 and 2.
12119d02a428SJonas Bonn *
12129d02a428SJonas Bonn */
12139d02a428SJonas Bonn
12149d02a428SJonas BonnENTRY(sys_or1k_atomic)
12159d02a428SJonas Bonn	/* FIXME: This ignores r3 and always does an XCHG */
12169d02a428SJonas Bonn	DISABLE_INTERRUPTS(r17,r19)
1217207e715fSJonas Bonn	l.lwz	r29,0(r4)
1218207e715fSJonas Bonn	l.lwz	r27,0(r5)
1219207e715fSJonas Bonn	l.sw	0(r4),r27
1220207e715fSJonas Bonn	l.sw	0(r5),r29
12219d02a428SJonas Bonn	ENABLE_INTERRUPTS(r17)
12229d02a428SJonas Bonn	l.jr	r9
12239d02a428SJonas Bonn	 l.or	r11,r0,r0
12249d02a428SJonas Bonn
12259d02a428SJonas Bonn/* ============================================================[ EOF ]=== */
1226