xref: /openbmc/linux/arch/microblaze/kernel/entry.S (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
1ca54502bSMichal Simek/*
2ca54502bSMichal Simek * Low-level system-call handling, trap handlers and context-switching
3ca54502bSMichal Simek *
4ca54502bSMichal Simek * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
5ca54502bSMichal Simek * Copyright (C) 2008-2009 PetaLogix
6ca54502bSMichal Simek * Copyright (C) 2003		John Williams <jwilliams@itee.uq.edu.au>
7ca54502bSMichal Simek * Copyright (C) 2001,2002	NEC Corporation
8ca54502bSMichal Simek * Copyright (C) 2001,2002	Miles Bader <miles@gnu.org>
9ca54502bSMichal Simek *
10ca54502bSMichal Simek * This file is subject to the terms and conditions of the GNU General
11ca54502bSMichal Simek * Public License. See the file COPYING in the main directory of this
12ca54502bSMichal Simek * archive for more details.
13ca54502bSMichal Simek *
14ca54502bSMichal Simek * Written by Miles Bader <miles@gnu.org>
15ca54502bSMichal Simek * Heavily modified by John Williams for Microblaze
16ca54502bSMichal Simek */
17ca54502bSMichal Simek
18ca54502bSMichal Simek#include <linux/sys.h>
19ca54502bSMichal Simek#include <linux/linkage.h>
20ca54502bSMichal Simek
21ca54502bSMichal Simek#include <asm/entry.h>
22ca54502bSMichal Simek#include <asm/current.h>
23ca54502bSMichal Simek#include <asm/processor.h>
24ca54502bSMichal Simek#include <asm/exceptions.h>
25ca54502bSMichal Simek#include <asm/asm-offsets.h>
26ca54502bSMichal Simek#include <asm/thread_info.h>
27ca54502bSMichal Simek
28ca54502bSMichal Simek#include <asm/page.h>
29ca54502bSMichal Simek#include <asm/unistd.h>
30*adc4cefaSAppana Durga Kedareswara rao#include <asm/xilinx_mb_manager.h>
31ca54502bSMichal Simek
32ca54502bSMichal Simek#include <linux/errno.h>
33ca54502bSMichal Simek#include <asm/signal.h>
3488707ebeSAppana Durga Kedareswara rao#include <asm/mmu.h>
35ca54502bSMichal Simek
3611d51360SMichal Simek#undef DEBUG
3711d51360SMichal Simek
38d8748e73SMichal Simek#ifdef DEBUG
39d8748e73SMichal Simek/* Create space for syscalls counting. */
40d8748e73SMichal Simek.section .data
41d8748e73SMichal Simek.global syscall_debug_table
42d8748e73SMichal Simek.align 4
43d8748e73SMichal Simeksyscall_debug_table:
44d8748e73SMichal Simek	.space	(__NR_syscalls * 4)
45d8748e73SMichal Simek#endif /* DEBUG */
46d8748e73SMichal Simek
47ca54502bSMichal Simek#define C_ENTRY(name)	.globl name; .align 4; name
48ca54502bSMichal Simek
49ca54502bSMichal Simek/*
50ca54502bSMichal Simek * Various ways of setting and clearing BIP in flags reg.
51ca54502bSMichal Simek * This is mucky, but necessary using microblaze version that
52ca54502bSMichal Simek * allows msr ops to write to BIP
53ca54502bSMichal Simek */
54ca54502bSMichal Simek#if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
55ca54502bSMichal Simek	.macro	clear_bip
5666f7de86SMichal Simek	msrclr	r0, MSR_BIP
57ca54502bSMichal Simek	.endm
58ca54502bSMichal Simek
59ca54502bSMichal Simek	.macro	set_bip
6066f7de86SMichal Simek	msrset	r0, MSR_BIP
61ca54502bSMichal Simek	.endm
62ca54502bSMichal Simek
63ca54502bSMichal Simek	.macro	clear_eip
6466f7de86SMichal Simek	msrclr	r0, MSR_EIP
65ca54502bSMichal Simek	.endm
66ca54502bSMichal Simek
67ca54502bSMichal Simek	.macro	set_ee
6866f7de86SMichal Simek	msrset	r0, MSR_EE
69ca54502bSMichal Simek	.endm
70ca54502bSMichal Simek
71ca54502bSMichal Simek	.macro	disable_irq
7266f7de86SMichal Simek	msrclr	r0, MSR_IE
73ca54502bSMichal Simek	.endm
74ca54502bSMichal Simek
75ca54502bSMichal Simek	.macro	enable_irq
7666f7de86SMichal Simek	msrset	r0, MSR_IE
77ca54502bSMichal Simek	.endm
78ca54502bSMichal Simek
79ca54502bSMichal Simek	.macro	set_ums
8066f7de86SMichal Simek	msrset	r0, MSR_UMS
8166f7de86SMichal Simek	msrclr	r0, MSR_VMS
82ca54502bSMichal Simek	.endm
83ca54502bSMichal Simek
84ca54502bSMichal Simek	.macro	set_vms
8566f7de86SMichal Simek	msrclr	r0, MSR_UMS
8666f7de86SMichal Simek	msrset	r0, MSR_VMS
87ca54502bSMichal Simek	.endm
88ca54502bSMichal Simek
89b318067eSMichal Simek	.macro	clear_ums
9066f7de86SMichal Simek	msrclr	r0, MSR_UMS
91b318067eSMichal Simek	.endm
92b318067eSMichal Simek
93ca54502bSMichal Simek	.macro	clear_vms_ums
9466f7de86SMichal Simek	msrclr	r0, MSR_VMS | MSR_UMS
95ca54502bSMichal Simek	.endm
96ca54502bSMichal Simek#else
97ca54502bSMichal Simek	.macro	clear_bip
98ca54502bSMichal Simek	mfs	r11, rmsr
99ca54502bSMichal Simek	andi	r11, r11, ~MSR_BIP
100ca54502bSMichal Simek	mts	rmsr, r11
101ca54502bSMichal Simek	.endm
102ca54502bSMichal Simek
103ca54502bSMichal Simek	.macro	set_bip
104ca54502bSMichal Simek	mfs	r11, rmsr
105ca54502bSMichal Simek	ori	r11, r11, MSR_BIP
106ca54502bSMichal Simek	mts	rmsr, r11
107ca54502bSMichal Simek	.endm
108ca54502bSMichal Simek
109ca54502bSMichal Simek	.macro	clear_eip
110ca54502bSMichal Simek	mfs	r11, rmsr
111ca54502bSMichal Simek	andi	r11, r11, ~MSR_EIP
112ca54502bSMichal Simek	mts	rmsr, r11
113ca54502bSMichal Simek	.endm
114ca54502bSMichal Simek
115ca54502bSMichal Simek	.macro	set_ee
116ca54502bSMichal Simek	mfs	r11, rmsr
117ca54502bSMichal Simek	ori	r11, r11, MSR_EE
118ca54502bSMichal Simek	mts	rmsr, r11
119ca54502bSMichal Simek	.endm
120ca54502bSMichal Simek
121ca54502bSMichal Simek	.macro	disable_irq
122ca54502bSMichal Simek	mfs	r11, rmsr
123ca54502bSMichal Simek	andi	r11, r11, ~MSR_IE
124ca54502bSMichal Simek	mts	rmsr, r11
125ca54502bSMichal Simek	.endm
126ca54502bSMichal Simek
127ca54502bSMichal Simek	.macro	enable_irq
128ca54502bSMichal Simek	mfs	r11, rmsr
129ca54502bSMichal Simek	ori	r11, r11, MSR_IE
130ca54502bSMichal Simek	mts	rmsr, r11
131ca54502bSMichal Simek	.endm
132ca54502bSMichal Simek
133ca54502bSMichal Simek	.macro set_ums
134ca54502bSMichal Simek	mfs	r11, rmsr
135ca54502bSMichal Simek	ori	r11, r11, MSR_VMS
136ca54502bSMichal Simek	andni	r11, r11, MSR_UMS
137ca54502bSMichal Simek	mts	rmsr, r11
138ca54502bSMichal Simek	.endm
139ca54502bSMichal Simek
140ca54502bSMichal Simek	.macro	set_vms
141ca54502bSMichal Simek	mfs	r11, rmsr
142ca54502bSMichal Simek	ori	r11, r11, MSR_VMS
143ca54502bSMichal Simek	andni	r11, r11, MSR_UMS
144ca54502bSMichal Simek	mts	rmsr, r11
145ca54502bSMichal Simek	.endm
146ca54502bSMichal Simek
147b318067eSMichal Simek	.macro	clear_ums
148b318067eSMichal Simek	mfs	r11, rmsr
149b318067eSMichal Simek	andni	r11, r11, MSR_UMS
150b318067eSMichal Simek	mts	rmsr,r11
151b318067eSMichal Simek	.endm
152b318067eSMichal Simek
153ca54502bSMichal Simek	.macro	clear_vms_ums
154ca54502bSMichal Simek	mfs	r11, rmsr
155ca54502bSMichal Simek	andni	r11, r11, (MSR_VMS|MSR_UMS)
156ca54502bSMichal Simek	mts	rmsr,r11
157ca54502bSMichal Simek	.endm
158ca54502bSMichal Simek#endif
159ca54502bSMichal Simek
160ca54502bSMichal Simek/* Define how to call high-level functions. With MMU, virtual mode must be
161ca54502bSMichal Simek * enabled when calling the high-level function. Clobbers R11.
162ca54502bSMichal Simek * VM_ON, VM_OFF, DO_JUMP_BIPCLR, DO_CALL
163ca54502bSMichal Simek */
164ca54502bSMichal Simek
165ca54502bSMichal Simek/* turn on virtual protected mode save */
166ca54502bSMichal Simek#define VM_ON		\
167ca54502bSMichal Simek	set_ums;	\
168ca54502bSMichal Simek	rted	r0, 2f;	\
169a4a94dbfSMichal Simek	nop; \
170a4a94dbfSMichal Simek2:
171ca54502bSMichal Simek
172ca54502bSMichal Simek/* turn off virtual protected mode save and user mode save*/
173ca54502bSMichal Simek#define VM_OFF			\
174ca54502bSMichal Simek	clear_vms_ums;		\
175ca54502bSMichal Simek	rted	r0, TOPHYS(1f);	\
176a4a94dbfSMichal Simek	nop; \
177a4a94dbfSMichal Simek1:
178ca54502bSMichal Simek
179ca54502bSMichal Simek#define SAVE_REGS \
1806e83557cSMichal Simek	swi	r2, r1, PT_R2;	/* Save SDA */			\
1816e83557cSMichal Simek	swi	r3, r1, PT_R3;					\
1826e83557cSMichal Simek	swi	r4, r1, PT_R4;					\
1836e83557cSMichal Simek	swi	r5, r1, PT_R5;					\
1846e83557cSMichal Simek	swi	r6, r1, PT_R6;					\
1856e83557cSMichal Simek	swi	r7, r1, PT_R7;					\
1866e83557cSMichal Simek	swi	r8, r1, PT_R8;					\
1876e83557cSMichal Simek	swi	r9, r1, PT_R9;					\
1886e83557cSMichal Simek	swi	r10, r1, PT_R10;					\
1896e83557cSMichal Simek	swi	r11, r1, PT_R11;	/* save clobbered regs after rval */\
1906e83557cSMichal Simek	swi	r12, r1, PT_R12;					\
1916e83557cSMichal Simek	swi	r13, r1, PT_R13;	/* Save SDA2 */			\
1926e83557cSMichal Simek	swi	r14, r1, PT_PC;	/* PC, before IRQ/trap */	\
1936e83557cSMichal Simek	swi	r15, r1, PT_R15;	/* Save LP */			\
1946e83557cSMichal Simek	swi	r16, r1, PT_R16;					\
1956e83557cSMichal Simek	swi	r17, r1, PT_R17;					\
1966e83557cSMichal Simek	swi	r18, r1, PT_R18;	/* Save asm scratch reg */	\
1976e83557cSMichal Simek	swi	r19, r1, PT_R19;					\
1986e83557cSMichal Simek	swi	r20, r1, PT_R20;					\
1996e83557cSMichal Simek	swi	r21, r1, PT_R21;					\
2006e83557cSMichal Simek	swi	r22, r1, PT_R22;					\
2016e83557cSMichal Simek	swi	r23, r1, PT_R23;					\
2026e83557cSMichal Simek	swi	r24, r1, PT_R24;					\
2036e83557cSMichal Simek	swi	r25, r1, PT_R25;					\
2046e83557cSMichal Simek	swi	r26, r1, PT_R26;					\
2056e83557cSMichal Simek	swi	r27, r1, PT_R27;					\
2066e83557cSMichal Simek	swi	r28, r1, PT_R28;					\
2076e83557cSMichal Simek	swi	r29, r1, PT_R29;					\
2086e83557cSMichal Simek	swi	r30, r1, PT_R30;					\
2096e83557cSMichal Simek	swi	r31, r1, PT_R31;	/* Save current task reg */	\
210ca54502bSMichal Simek	mfs	r11, rmsr;		/* save MSR */			\
2116e83557cSMichal Simek	swi	r11, r1, PT_MSR;
212ca54502bSMichal Simek
213faf154cdSMichal Simek#define RESTORE_REGS_GP \
2146e83557cSMichal Simek	lwi	r2, r1, PT_R2;	/* restore SDA */		\
2156e83557cSMichal Simek	lwi	r3, r1, PT_R3;					\
2166e83557cSMichal Simek	lwi	r4, r1, PT_R4;					\
2176e83557cSMichal Simek	lwi	r5, r1, PT_R5;					\
2186e83557cSMichal Simek	lwi	r6, r1, PT_R6;					\
2196e83557cSMichal Simek	lwi	r7, r1, PT_R7;					\
2206e83557cSMichal Simek	lwi	r8, r1, PT_R8;					\
2216e83557cSMichal Simek	lwi	r9, r1, PT_R9;					\
2226e83557cSMichal Simek	lwi	r10, r1, PT_R10;					\
2236e83557cSMichal Simek	lwi	r11, r1, PT_R11;	/* restore clobbered regs after rval */\
2246e83557cSMichal Simek	lwi	r12, r1, PT_R12;					\
2256e83557cSMichal Simek	lwi	r13, r1, PT_R13;	/* restore SDA2 */		\
2266e83557cSMichal Simek	lwi	r14, r1, PT_PC;	/* RESTORE_LINK PC, before IRQ/trap */\
2276e83557cSMichal Simek	lwi	r15, r1, PT_R15;	/* restore LP */		\
2286e83557cSMichal Simek	lwi	r16, r1, PT_R16;					\
2296e83557cSMichal Simek	lwi	r17, r1, PT_R17;					\
2306e83557cSMichal Simek	lwi	r18, r1, PT_R18;	/* restore asm scratch reg */	\
2316e83557cSMichal Simek	lwi	r19, r1, PT_R19;					\
2326e83557cSMichal Simek	lwi	r20, r1, PT_R20;					\
2336e83557cSMichal Simek	lwi	r21, r1, PT_R21;					\
2346e83557cSMichal Simek	lwi	r22, r1, PT_R22;					\
2356e83557cSMichal Simek	lwi	r23, r1, PT_R23;					\
2366e83557cSMichal Simek	lwi	r24, r1, PT_R24;					\
2376e83557cSMichal Simek	lwi	r25, r1, PT_R25;					\
2386e83557cSMichal Simek	lwi	r26, r1, PT_R26;					\
2396e83557cSMichal Simek	lwi	r27, r1, PT_R27;					\
2406e83557cSMichal Simek	lwi	r28, r1, PT_R28;					\
2416e83557cSMichal Simek	lwi	r29, r1, PT_R29;					\
2426e83557cSMichal Simek	lwi	r30, r1, PT_R30;					\
2436e83557cSMichal Simek	lwi	r31, r1, PT_R31;	/* Restore cur task reg */
244ca54502bSMichal Simek
245faf154cdSMichal Simek#define RESTORE_REGS \
246faf154cdSMichal Simek	lwi	r11, r1, PT_MSR;					\
247faf154cdSMichal Simek	mts	rmsr , r11;						\
248faf154cdSMichal Simek	RESTORE_REGS_GP
249faf154cdSMichal Simek
25014ef905bSMichal Simek#define RESTORE_REGS_RTBD \
25114ef905bSMichal Simek	lwi	r11, r1, PT_MSR;					\
25214ef905bSMichal Simek	andni	r11, r11, MSR_EIP;          /* clear EIP */             \
25314ef905bSMichal Simek	ori	r11, r11, MSR_EE | MSR_BIP; /* set EE and BIP */        \
25414ef905bSMichal Simek	mts	rmsr , r11;						\
25514ef905bSMichal Simek	RESTORE_REGS_GP
25614ef905bSMichal Simek
257e5d2af2bSMichal Simek#define SAVE_STATE	\
258e5d2af2bSMichal Simek	swi	r1, r0, TOPHYS(PER_CPU(ENTRY_SP)); /* save stack */	\
259e5d2af2bSMichal Simek	/* See if already in kernel mode.*/				\
260e5d2af2bSMichal Simek	mfs	r1, rmsr;						\
261e5d2af2bSMichal Simek	andi	r1, r1, MSR_UMS;					\
262e5d2af2bSMichal Simek	bnei	r1, 1f;						\
263e5d2af2bSMichal Simek	/* Kernel-mode state save.  */					\
264e5d2af2bSMichal Simek	/* Reload kernel stack-ptr. */					\
265e5d2af2bSMichal Simek	lwi	r1, r0, TOPHYS(PER_CPU(ENTRY_SP));			\
266287503faSMichal Simek	/* FIXME: I can add these two lines to one */			\
267287503faSMichal Simek	/* tophys(r1,r1); */						\
2686e83557cSMichal Simek	/* addik	r1, r1, -PT_SIZE; */				\
2696e83557cSMichal Simek	addik	r1, r1, CONFIG_KERNEL_BASE_ADDR - CONFIG_KERNEL_START - PT_SIZE; \
270e5d2af2bSMichal Simek	SAVE_REGS							\
271e5d2af2bSMichal Simek	brid	2f;							\
2726e83557cSMichal Simek	swi	r1, r1, PT_MODE; 	 				\
273e5d2af2bSMichal Simek1:	/* User-mode state save.  */					\
274e5d2af2bSMichal Simek	lwi	r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */\
275e5d2af2bSMichal Simek	tophys(r1,r1);							\
276e5d2af2bSMichal Simek	lwi	r1, r1, TS_THREAD_INFO;	/* get the thread info */	\
277287503faSMichal Simek	/* MS these three instructions can be added to one */		\
278287503faSMichal Simek	/* addik	r1, r1, THREAD_SIZE; */				\
279287503faSMichal Simek	/* tophys(r1,r1); */						\
2806e83557cSMichal Simek	/* addik	r1, r1, -PT_SIZE; */			\
2816e83557cSMichal Simek	addik r1, r1, THREAD_SIZE + CONFIG_KERNEL_BASE_ADDR - CONFIG_KERNEL_START - PT_SIZE; \
282e5d2af2bSMichal Simek	SAVE_REGS							\
283e5d2af2bSMichal Simek	lwi	r11, r0, TOPHYS(PER_CPU(ENTRY_SP));			\
2846e83557cSMichal Simek	swi	r11, r1, PT_R1; /* Store user SP.  */		\
2856e83557cSMichal Simek	swi	r0, r1, PT_MODE; /* Was in user-mode.  */		\
286e5d2af2bSMichal Simek	/* MS: I am clearing UMS even in case when I come from kernel space */ \
287e5d2af2bSMichal Simek	clear_ums; 							\
288e5d2af2bSMichal Simek2:	lwi	CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE));
289e5d2af2bSMichal Simek
290ca54502bSMichal Simek.text
291ca54502bSMichal Simek
29288707ebeSAppana Durga Kedareswara rao.extern cpuinfo
29388707ebeSAppana Durga Kedareswara rao
29488707ebeSAppana Durga Kedareswara raoC_ENTRY(mb_flush_dcache):
29588707ebeSAppana Durga Kedareswara rao	addik	r1, r1, -PT_SIZE
29688707ebeSAppana Durga Kedareswara rao	SAVE_REGS
29788707ebeSAppana Durga Kedareswara rao
29888707ebeSAppana Durga Kedareswara rao	addik	r3, r0, cpuinfo
29988707ebeSAppana Durga Kedareswara rao	lwi	r7, r3, CI_DCS
30088707ebeSAppana Durga Kedareswara rao	lwi	r8, r3, CI_DCL
30188707ebeSAppana Durga Kedareswara rao	sub	r9, r7, r8
30288707ebeSAppana Durga Kedareswara rao1:
30388707ebeSAppana Durga Kedareswara rao	wdc.flush r9, r0
30488707ebeSAppana Durga Kedareswara rao	bgtid	r9, 1b
30588707ebeSAppana Durga Kedareswara rao	addk	r9, r9, r8
30688707ebeSAppana Durga Kedareswara rao
30788707ebeSAppana Durga Kedareswara rao	RESTORE_REGS
30888707ebeSAppana Durga Kedareswara rao	addik	r1, r1, PT_SIZE
30988707ebeSAppana Durga Kedareswara rao	rtsd	r15, 8
31088707ebeSAppana Durga Kedareswara rao	nop
31188707ebeSAppana Durga Kedareswara rao
31288707ebeSAppana Durga Kedareswara raoC_ENTRY(mb_invalidate_icache):
31388707ebeSAppana Durga Kedareswara rao	addik	r1, r1, -PT_SIZE
31488707ebeSAppana Durga Kedareswara rao	SAVE_REGS
31588707ebeSAppana Durga Kedareswara rao
31688707ebeSAppana Durga Kedareswara rao	addik	r3, r0, cpuinfo
31788707ebeSAppana Durga Kedareswara rao	lwi	r7, r3, CI_ICS
31888707ebeSAppana Durga Kedareswara rao	lwi	r8, r3, CI_ICL
31988707ebeSAppana Durga Kedareswara rao	sub	r9, r7, r8
32088707ebeSAppana Durga Kedareswara rao1:
32188707ebeSAppana Durga Kedareswara rao	wic 	r9, r0
32288707ebeSAppana Durga Kedareswara rao	bgtid	r9, 1b
32388707ebeSAppana Durga Kedareswara rao	addk	r9, r9, r8
32488707ebeSAppana Durga Kedareswara rao
32588707ebeSAppana Durga Kedareswara rao	RESTORE_REGS
32688707ebeSAppana Durga Kedareswara rao	addik	r1, r1, PT_SIZE
32788707ebeSAppana Durga Kedareswara rao	rtsd	r15, 8
32888707ebeSAppana Durga Kedareswara rao	nop
32988707ebeSAppana Durga Kedareswara rao
330ca54502bSMichal Simek/*
331ca54502bSMichal Simek * User trap.
332ca54502bSMichal Simek *
333ca54502bSMichal Simek * System calls are handled here.
334ca54502bSMichal Simek *
335ca54502bSMichal Simek * Syscall protocol:
336ca54502bSMichal Simek * Syscall number in r12, args in r5-r10
337ca54502bSMichal Simek * Return value in r3
338ca54502bSMichal Simek *
339ca54502bSMichal Simek * Trap entered via brki instruction, so BIP bit is set, and interrupts
340ca54502bSMichal Simek * are masked. This is nice, means we don't have to CLI before state save
341ca54502bSMichal Simek */
342ca54502bSMichal SimekC_ENTRY(_user_exception):
3430e41c909SMichal Simek	swi	r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) /* save stack */
3449da63458SMichal Simek	addi	r14, r14, 4	/* return address is 4 byte after call */
345ca54502bSMichal Simek
346ca54502bSMichal Simek	lwi	r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */
347ca54502bSMichal Simek	tophys(r1,r1);
348ca54502bSMichal Simek	lwi	r1, r1, TS_THREAD_INFO;	/* get stack from task_struct */
3499da63458SMichal Simek/* calculate kernel stack pointer from task struct 8k */
3509da63458SMichal Simek	addik	r1, r1, THREAD_SIZE;
3519da63458SMichal Simek	tophys(r1,r1);
3529da63458SMichal Simek
3536e83557cSMichal Simek	addik	r1, r1, -PT_SIZE; /* Make room on the stack.  */
354ca54502bSMichal Simek	SAVE_REGS
3556e83557cSMichal Simek	swi	r0, r1, PT_R3
3566e83557cSMichal Simek	swi	r0, r1, PT_R4
357ca54502bSMichal Simek
3586e83557cSMichal Simek	swi	r0, r1, PT_MODE;			/* Was in user-mode. */
359ca54502bSMichal Simek	lwi	r11, r0, TOPHYS(PER_CPU(ENTRY_SP));
3606e83557cSMichal Simek	swi	r11, r1, PT_R1;		/* Store user SP.  */
36125f6e596SMichal Simek	clear_ums;
3629da63458SMichal Simek2:	lwi	CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE));
363ca54502bSMichal Simek	/* Save away the syscall number.  */
3646e83557cSMichal Simek	swi	r12, r1, PT_R0;
365ca54502bSMichal Simek	tovirt(r1,r1)
366ca54502bSMichal Simek
367ca54502bSMichal Simek/* where the trap should return need -8 to adjust for rtsd r15, 8*/
368ca54502bSMichal Simek/* Jump to the appropriate function for the system call number in r12
369ca54502bSMichal Simek * (r12 is not preserved), or return an error if r12 is not valid. The LP
370ca54502bSMichal Simek * register should point to the location where
371ca54502bSMichal Simek * the called function should return.  [note that MAKE_SYS_CALL uses label 1] */
37223575483SMichal Simek
37325f6e596SMichal Simek	/* Step into virtual mode */
37425f6e596SMichal Simek	rtbd	r0, 3f
37523575483SMichal Simek	nop
37623575483SMichal Simek3:
377b1d70c62SMichal Simek	lwi	r11, CURRENT_TASK, TS_THREAD_INFO /* get thread info */
37823575483SMichal Simek	lwi	r11, r11, TI_FLAGS	 /* get flags in thread info */
37923575483SMichal Simek	andi	r11, r11, _TIF_WORK_SYSCALL_MASK
38023575483SMichal Simek	beqi	r11, 4f
38123575483SMichal Simek
38223575483SMichal Simek	addik	r3, r0, -ENOSYS
3836e83557cSMichal Simek	swi	r3, r1, PT_R3
38423575483SMichal Simek	brlid	r15, do_syscall_trace_enter
3856e83557cSMichal Simek	addik	r5, r1, PT_R0
38623575483SMichal Simek
38723575483SMichal Simek	# do_syscall_trace_enter returns the new syscall nr.
38823575483SMichal Simek	addk	r12, r0, r3
3896e83557cSMichal Simek	lwi	r5, r1, PT_R5;
3906e83557cSMichal Simek	lwi	r6, r1, PT_R6;
3916e83557cSMichal Simek	lwi	r7, r1, PT_R7;
3926e83557cSMichal Simek	lwi	r8, r1, PT_R8;
3936e83557cSMichal Simek	lwi	r9, r1, PT_R9;
3946e83557cSMichal Simek	lwi	r10, r1, PT_R10;
39523575483SMichal Simek4:
39623575483SMichal Simek/* Jump to the appropriate function for the system call number in r12
39723575483SMichal Simek * (r12 is not preserved), or return an error if r12 is not valid.
39823575483SMichal Simek * The LP register should point to the location where the called function
39923575483SMichal Simek * should return.  [note that MAKE_SYS_CALL uses label 1] */
40023575483SMichal Simek	/* See if the system call number is valid */
401c2219edaSJamie Garside	blti	r12, 5f
402ca54502bSMichal Simek	addi	r11, r12, -__NR_syscalls;
40323575483SMichal Simek	bgei	r11, 5f;
404ca54502bSMichal Simek	/* Figure out which function to use for this system call.  */
405ca54502bSMichal Simek	/* Note Microblaze barrel shift is optional, so don't rely on it */
406ca54502bSMichal Simek	add	r12, r12, r12;			/* convert num -> ptr */
407ca54502bSMichal Simek	add	r12, r12, r12;
4084de6ba68SMichal Simek	addi	r30, r0, 1			/* restarts allowed */
409ca54502bSMichal Simek
41011d51360SMichal Simek#ifdef DEBUG
411d8748e73SMichal Simek	/* Trac syscalls and stored them to syscall_debug_table */
412d8748e73SMichal Simek	/* The first syscall location stores total syscall number */
413d8748e73SMichal Simek	lwi	r3, r0, syscall_debug_table
414ca54502bSMichal Simek	addi	r3, r3, 1
415d8748e73SMichal Simek	swi	r3, r0, syscall_debug_table
416d8748e73SMichal Simek	lwi	r3, r12, syscall_debug_table
417d8748e73SMichal Simek	addi	r3, r3, 1
418d8748e73SMichal Simek	swi	r3, r12, syscall_debug_table
41911d51360SMichal Simek#endif
420ca54502bSMichal Simek
42123575483SMichal Simek	# Find and jump into the syscall handler.
42223575483SMichal Simek	lwi	r12, r12, sys_call_table
42323575483SMichal Simek	/* where the trap should return need -8 to adjust for rtsd r15, 8 */
424b9ea77e2SMichal Simek	addi	r15, r0, ret_from_trap-8
42523575483SMichal Simek	bra	r12
42623575483SMichal Simek
427ca54502bSMichal Simek	/* The syscall number is invalid, return an error.  */
42823575483SMichal Simek5:
429c2219edaSJamie Garside	braid	ret_from_trap
4309814cc11SMichal Simek	addi	r3, r0, -ENOSYS;
431ca54502bSMichal Simek
43223575483SMichal Simek/* Entry point used to return from a syscall/trap */
433ca54502bSMichal Simek/* We re-enable BIP bit before state restore */
434ca54502bSMichal SimekC_ENTRY(ret_from_trap):
4356e83557cSMichal Simek	swi	r3, r1, PT_R3
4366e83557cSMichal Simek	swi	r4, r1, PT_R4
437b1d70c62SMichal Simek
4386e83557cSMichal Simek	lwi	r11, r1, PT_MODE;
4399da63458SMichal Simek/* See if returning to kernel mode, if so, skip resched &c.  */
4409da63458SMichal Simek	bnei	r11, 2f;
441ca54502bSMichal Simek	/* We're returning to user mode, so check for various conditions that
442ca54502bSMichal Simek	 * trigger rescheduling. */
443b1d70c62SMichal Simek	/* FIXME: Restructure all these flag checks. */
444b1d70c62SMichal Simek	lwi	r11, CURRENT_TASK, TS_THREAD_INFO;	/* get thread info */
44523575483SMichal Simek	lwi	r11, r11, TI_FLAGS;		/* get flags in thread info */
44623575483SMichal Simek	andi	r11, r11, _TIF_WORK_SYSCALL_MASK
44723575483SMichal Simek	beqi	r11, 1f
44823575483SMichal Simek
44923575483SMichal Simek	brlid	r15, do_syscall_trace_leave
4506e83557cSMichal Simek	addik	r5, r1, PT_R0
45123575483SMichal Simek1:
45223575483SMichal Simek	/* We're returning to user mode, so check for various conditions that
45323575483SMichal Simek	 * trigger rescheduling. */
454b1d70c62SMichal Simek	/* get thread info from current task */
455b1d70c62SMichal Simek	lwi	r11, CURRENT_TASK, TS_THREAD_INFO;
456e9f92526SAl Viro	lwi	r19, r11, TI_FLAGS;		/* get flags in thread info */
457e9f92526SAl Viro	andi	r11, r19, _TIF_NEED_RESCHED;
458ca54502bSMichal Simek	beqi	r11, 5f;
459ca54502bSMichal Simek
460ca54502bSMichal Simek	bralid	r15, schedule;	/* Call scheduler */
461ca54502bSMichal Simek	nop;				/* delay slot */
462e9f92526SAl Viro	bri	1b
463ca54502bSMichal Simek
464ca54502bSMichal Simek	/* Maybe handle a signal */
465e9f92526SAl Viro5:
466e9f92526SAl Viro	andi	r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME;
467e9f92526SAl Viro	beqi	r11, 4f;		/* Signals to handle, handle them */
468ca54502bSMichal Simek
4696e83557cSMichal Simek	addik	r5, r1, 0;		/* Arg 1: struct pt_regs *regs */
470969a9616SAl Viro	bralid	r15, do_notify_resume;	/* Handle any signals */
47114203e19SAl Viro	add	r6, r30, r0;		/* Arg 2: int in_syscall */
472e9f92526SAl Viro	add	r30, r0, r0		/* no more restarts */
473e9f92526SAl Viro	bri	1b
474b1d70c62SMichal Simek
475b1d70c62SMichal Simek/* Finally, return to user state.  */
476e9f92526SAl Viro4:	set_bip;			/*  Ints masked for state restore */
4778633bebcSMichal Simek	swi	CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */
478ca54502bSMichal Simek	VM_OFF;
479ca54502bSMichal Simek	tophys(r1,r1);
48014ef905bSMichal Simek	RESTORE_REGS_RTBD;
4816e83557cSMichal Simek	addik	r1, r1, PT_SIZE		/* Clean up stack space.  */
482ca54502bSMichal Simek	lwi	r1, r1, PT_R1 - PT_SIZE;/* Restore user stack pointer. */
4839da63458SMichal Simek	bri	6f;
4849da63458SMichal Simek
4859da63458SMichal Simek/* Return to kernel state.  */
4869da63458SMichal Simek2:	set_bip;			/*  Ints masked for state restore */
4879da63458SMichal Simek	VM_OFF;
4889da63458SMichal Simek	tophys(r1,r1);
48914ef905bSMichal Simek	RESTORE_REGS_RTBD;
4906e83557cSMichal Simek	addik	r1, r1, PT_SIZE		/* Clean up stack space.  */
4919da63458SMichal Simek	tovirt(r1,r1);
4929da63458SMichal Simek6:
493ca54502bSMichal SimekTRAP_return:		/* Make global symbol for debugging */
494ca54502bSMichal Simek	rtbd	r14, 0;	/* Instructions to return from an IRQ */
495ca54502bSMichal Simek	nop;
496ca54502bSMichal Simek
497ca54502bSMichal Simek
498ca54502bSMichal Simek/* This the initial entry point for a new child thread, with an appropriate
4995b7d1d57SSlark Xiao   stack in place that makes it look like the child is in the middle of a
500ca54502bSMichal Simek   syscall.  This function is actually `returned to' from switch_thread
501ca54502bSMichal Simek   (copy_thread makes ret_from_fork the return address in each new thread's
502ca54502bSMichal Simek   saved context).  */
503ca54502bSMichal SimekC_ENTRY(ret_from_fork):
504ca54502bSMichal Simek	bralid	r15, schedule_tail; /* ...which is schedule_tail's arg */
505fd11ff73SMichal Simek	add	r5, r3, r0;	/* switch_thread returns the prev task */
506ca54502bSMichal Simek				/* ( in the delay slot ) */
507ca54502bSMichal Simek	brid	ret_from_trap;	/* Do normal trap return */
5089814cc11SMichal Simek	add	r3, r0, r0;	/* Child's fork call should return 0. */
509ca54502bSMichal Simek
5102319295dSAl ViroC_ENTRY(ret_from_kernel_thread):
5112319295dSAl Viro	bralid	r15, schedule_tail; /* ...which is schedule_tail's arg */
5122319295dSAl Viro	add	r5, r3, r0;	/* switch_thread returns the prev task */
5132319295dSAl Viro				/* ( in the delay slot ) */
5142319295dSAl Viro	brald	r15, r20	/* fn was left in r20 */
5152319295dSAl Viro	addk	r5, r0, r19	/* ... and argument - in r19 */
51699c59f60SAl Viro	brid	ret_from_trap
51799c59f60SAl Viro	add	r3, r0, r0
5182319295dSAl Viro
519ca54502bSMichal SimekC_ENTRY(sys_rt_sigreturn_wrapper):
52014203e19SAl Viro	addik	r30, r0, 0		/* no restarts */
521791d0a16SMichal Simek	brid	sys_rt_sigreturn	/* Do real work */
5226e83557cSMichal Simek	addik	r5, r1, 0;		/* add user context as 1st arg */
523ca54502bSMichal Simek
524ca54502bSMichal Simek/*
525ca54502bSMichal Simek * HW EXCEPTION rutine start
526ca54502bSMichal Simek */
527ca54502bSMichal SimekC_ENTRY(full_exception_trap):
528ca54502bSMichal Simek	/* adjust exception address for privileged instruction
529ca54502bSMichal Simek	 * for finding where is it */
530ca54502bSMichal Simek	addik	r17, r17, -4
531ca54502bSMichal Simek	SAVE_STATE /* Save registers */
53206a54604SMichal Simek	/* PC, before IRQ/trap - this is one instruction above */
5336e83557cSMichal Simek	swi	r17, r1, PT_PC;
53406a54604SMichal Simek	tovirt(r1,r1)
535ca54502bSMichal Simek	/* FIXME this can be store directly in PT_ESR reg.
536ca54502bSMichal Simek	 * I tested it but there is a fault */
537ca54502bSMichal Simek	/* where the trap should return need -8 to adjust for rtsd r15, 8 */
538b9ea77e2SMichal Simek	addik	r15, r0, ret_from_exc - 8
539ca54502bSMichal Simek	mfs	r6, resr
540ca54502bSMichal Simek	mfs	r7, rfsr;		/* save FSR */
541131e4e97SMichal Simek	mts	rfsr, r0;	/* Clear sticky fsr */
542c318d483SMichal Simek	rted	r0, full_exception
5436e83557cSMichal Simek	addik	r5, r1, 0		 /* parameter struct pt_regs * regs */
544ca54502bSMichal Simek
545ca54502bSMichal Simek/*
546ca54502bSMichal Simek * Unaligned data trap.
547ca54502bSMichal Simek *
548ca54502bSMichal Simek * Unaligned data trap last on 4k page is handled here.
549ca54502bSMichal Simek *
550ca54502bSMichal Simek * Trap entered via exception, so EE bit is set, and interrupts
551ca54502bSMichal Simek * are masked.  This is nice, means we don't have to CLI before state save
552ca54502bSMichal Simek *
553ca54502bSMichal Simek * The assembler routine is in "arch/microblaze/kernel/hw_exception_handler.S"
554ca54502bSMichal Simek */
555ca54502bSMichal SimekC_ENTRY(unaligned_data_trap):
5568b110d15SMichal Simek	/* MS: I have to save r11 value and then restore it because
5578b110d15SMichal Simek	 * set_bit, clear_eip, set_ee use r11 as temp register if MSR
5588b110d15SMichal Simek	 * instructions are not used. We don't need to do if MSR instructions
5598b110d15SMichal Simek	 * are used and they use r0 instead of r11.
5608b110d15SMichal Simek	 * I am using ENTRY_SP which should be primary used only for stack
5618b110d15SMichal Simek	 * pointer saving. */
5628b110d15SMichal Simek	swi	r11, r0, TOPHYS(PER_CPU(ENTRY_SP));
5638b110d15SMichal Simek	set_bip;        /* equalize initial state for all possible entries */
5648b110d15SMichal Simek	clear_eip;
5658b110d15SMichal Simek	set_ee;
5668b110d15SMichal Simek	lwi	r11, r0, TOPHYS(PER_CPU(ENTRY_SP));
567ca54502bSMichal Simek	SAVE_STATE		/* Save registers.*/
56806a54604SMichal Simek	/* PC, before IRQ/trap - this is one instruction above */
5696e83557cSMichal Simek	swi	r17, r1, PT_PC;
57006a54604SMichal Simek	tovirt(r1,r1)
571ca54502bSMichal Simek	/* where the trap should return need -8 to adjust for rtsd r15, 8 */
572b9ea77e2SMichal Simek	addik	r15, r0, ret_from_exc-8
573ca54502bSMichal Simek	mfs	r3, resr		/* ESR */
574ca54502bSMichal Simek	mfs	r4, rear		/* EAR */
575c318d483SMichal Simek	rtbd	r0, _unaligned_data_exception
5766e83557cSMichal Simek	addik	r7, r1, 0		/* parameter struct pt_regs * regs */
577ca54502bSMichal Simek
578ca54502bSMichal Simek/*
579ca54502bSMichal Simek * Page fault traps.
580ca54502bSMichal Simek *
581ca54502bSMichal Simek * If the real exception handler (from hw_exception_handler.S) didn't find
582ca54502bSMichal Simek * the mapping for the process, then we're thrown here to handle such situation.
583ca54502bSMichal Simek *
584ca54502bSMichal Simek * Trap entered via exceptions, so EE bit is set, and interrupts
585ca54502bSMichal Simek * are masked.  This is nice, means we don't have to CLI before state save
586ca54502bSMichal Simek *
587ca54502bSMichal Simek * Build a standard exception frame for TLB Access errors.  All TLB exceptions
588ca54502bSMichal Simek * will bail out to this point if they can't resolve the lightweight TLB fault.
589ca54502bSMichal Simek *
590ca54502bSMichal Simek * The C function called is in "arch/microblaze/mm/fault.c", declared as:
591ca54502bSMichal Simek * void do_page_fault(struct pt_regs *regs,
592ca54502bSMichal Simek *				unsigned long address,
593ca54502bSMichal Simek *				unsigned long error_code)
594ca54502bSMichal Simek */
595ca54502bSMichal Simek/* data and intruction trap - which is choose is resolved int fault.c */
596ca54502bSMichal SimekC_ENTRY(page_fault_data_trap):
597ca54502bSMichal Simek	SAVE_STATE		/* Save registers.*/
59806a54604SMichal Simek	/* PC, before IRQ/trap - this is one instruction above */
5996e83557cSMichal Simek	swi	r17, r1, PT_PC;
60006a54604SMichal Simek	tovirt(r1,r1)
601ca54502bSMichal Simek	/* where the trap should return need -8 to adjust for rtsd r15, 8 */
602b9ea77e2SMichal Simek	addik	r15, r0, ret_from_exc-8
603ca54502bSMichal Simek	mfs	r6, rear		/* parameter unsigned long address */
604ca54502bSMichal Simek	mfs	r7, resr		/* parameter unsigned long error_code */
605c318d483SMichal Simek	rted	r0, do_page_fault
6066e83557cSMichal Simek	addik	r5, r1, 0		/* parameter struct pt_regs * regs */
607ca54502bSMichal Simek
608ca54502bSMichal SimekC_ENTRY(page_fault_instr_trap):
609ca54502bSMichal Simek	SAVE_STATE		/* Save registers.*/
61006a54604SMichal Simek	/* PC, before IRQ/trap - this is one instruction above */
6116e83557cSMichal Simek	swi	r17, r1, PT_PC;
61206a54604SMichal Simek	tovirt(r1,r1)
613ca54502bSMichal Simek	/* where the trap should return need -8 to adjust for rtsd r15, 8 */
614b9ea77e2SMichal Simek	addik	r15, r0, ret_from_exc-8
615ca54502bSMichal Simek	mfs	r6, rear		/* parameter unsigned long address */
616ca54502bSMichal Simek	ori	r7, r0, 0		/* parameter unsigned long error_code */
6179814cc11SMichal Simek	rted	r0, do_page_fault
6186e83557cSMichal Simek	addik	r5, r1, 0		/* parameter struct pt_regs * regs */
619ca54502bSMichal Simek
620ca54502bSMichal Simek/* Entry point used to return from an exception.  */
621ca54502bSMichal SimekC_ENTRY(ret_from_exc):
6226e83557cSMichal Simek	lwi	r11, r1, PT_MODE;
623ca54502bSMichal Simek	bnei	r11, 2f;		/* See if returning to kernel mode, */
624ca54502bSMichal Simek					/* ... if so, skip resched &c.  */
625ca54502bSMichal Simek
626ca54502bSMichal Simek	/* We're returning to user mode, so check for various conditions that
627ca54502bSMichal Simek	   trigger rescheduling. */
628e9f92526SAl Viro1:
629b1d70c62SMichal Simek	lwi	r11, CURRENT_TASK, TS_THREAD_INFO;	/* get thread info */
630e9f92526SAl Viro	lwi	r19, r11, TI_FLAGS;	/* get flags in thread info */
631e9f92526SAl Viro	andi	r11, r19, _TIF_NEED_RESCHED;
632ca54502bSMichal Simek	beqi	r11, 5f;
633ca54502bSMichal Simek
634ca54502bSMichal Simek/* Call the scheduler before returning from a syscall/trap. */
635ca54502bSMichal Simek	bralid	r15, schedule;	/* Call scheduler */
636ca54502bSMichal Simek	nop;				/* delay slot */
637e9f92526SAl Viro	bri	1b
638ca54502bSMichal Simek
639ca54502bSMichal Simek	/* Maybe handle a signal */
640e9f92526SAl Viro5:	andi	r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME;
641e9f92526SAl Viro	beqi	r11, 4f;		/* Signals to handle, handle them */
642ca54502bSMichal Simek
643ca54502bSMichal Simek	/*
644ca54502bSMichal Simek	 * Handle a signal return; Pending signals should be in r18.
645ca54502bSMichal Simek	 *
646ca54502bSMichal Simek	 * Not all registers are saved by the normal trap/interrupt entry
647ca54502bSMichal Simek	 * points (for instance, call-saved registers (because the normal
648ca54502bSMichal Simek	 * C-compiler calling sequence in the kernel makes sure they're
649ca54502bSMichal Simek	 * preserved), and call-clobbered registers in the case of
650ca54502bSMichal Simek	 * traps), but signal handlers may want to examine or change the
651ca54502bSMichal Simek	 * complete register state.  Here we save anything not saved by
652ca54502bSMichal Simek	 * the normal entry sequence, so that it may be safely restored
653969a9616SAl Viro	 * (in a possibly modified form) after do_notify_resume returns. */
6546e83557cSMichal Simek	addik	r5, r1, 0;		/* Arg 1: struct pt_regs *regs */
655969a9616SAl Viro	bralid	r15, do_notify_resume;	/* Handle any signals */
65683140191SAl Viro	addi	r6, r0, 0;		/* Arg 2: int in_syscall */
657e9f92526SAl Viro	bri	1b
658ca54502bSMichal Simek
659ca54502bSMichal Simek/* Finally, return to user state.  */
660e9f92526SAl Viro4:	set_bip;			/* Ints masked for state restore */
6618633bebcSMichal Simek	swi	CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */
662ca54502bSMichal Simek	VM_OFF;
663ca54502bSMichal Simek	tophys(r1,r1);
664ca54502bSMichal Simek
66514ef905bSMichal Simek	RESTORE_REGS_RTBD;
6666e83557cSMichal Simek	addik	r1, r1, PT_SIZE		/* Clean up stack space.  */
667ca54502bSMichal Simek
668ca54502bSMichal Simek	lwi	r1, r1, PT_R1 - PT_SIZE; /* Restore user stack pointer. */
669ca54502bSMichal Simek	bri	6f;
670ca54502bSMichal Simek/* Return to kernel state.  */
67196014cc3SMichal Simek2:	set_bip;			/* Ints masked for state restore */
67296014cc3SMichal Simek	VM_OFF;
673ca54502bSMichal Simek	tophys(r1,r1);
67414ef905bSMichal Simek	RESTORE_REGS_RTBD;
6756e83557cSMichal Simek	addik	r1, r1, PT_SIZE		/* Clean up stack space.  */
676ca54502bSMichal Simek
677ca54502bSMichal Simek	tovirt(r1,r1);
678ca54502bSMichal Simek6:
679ca54502bSMichal SimekEXC_return:		/* Make global symbol for debugging */
680ca54502bSMichal Simek	rtbd	r14, 0;	/* Instructions to return from an IRQ */
681ca54502bSMichal Simek	nop;
682ca54502bSMichal Simek
683ca54502bSMichal Simek/*
684ca54502bSMichal Simek * HW EXCEPTION rutine end
685ca54502bSMichal Simek */
686ca54502bSMichal Simek
687ca54502bSMichal Simek/*
688ca54502bSMichal Simek * Hardware maskable interrupts.
689ca54502bSMichal Simek *
690ca54502bSMichal Simek * The stack-pointer (r1) should have already been saved to the memory
691ca54502bSMichal Simek * location PER_CPU(ENTRY_SP).
692ca54502bSMichal Simek */
693ca54502bSMichal SimekC_ENTRY(_interrupt):
694ca54502bSMichal Simek/* MS: we are in physical address */
695ca54502bSMichal Simek/* Save registers, switch to proper stack, convert SP to virtual.*/
696ca54502bSMichal Simek	swi	r1, r0, TOPHYS(PER_CPU(ENTRY_SP))
697ca54502bSMichal Simek	/* MS: See if already in kernel mode. */
698653e447eSMichal Simek	mfs	r1, rmsr
6995c0d72b1SMichal Simek	nop
700653e447eSMichal Simek	andi	r1, r1, MSR_UMS
701653e447eSMichal Simek	bnei	r1, 1f
702ca54502bSMichal Simek
703ca54502bSMichal Simek/* Kernel-mode state save. */
704653e447eSMichal Simek	lwi	r1, r0, TOPHYS(PER_CPU(ENTRY_SP))
705653e447eSMichal Simek	tophys(r1,r1); /* MS: I have in r1 physical address where stack is */
706ca54502bSMichal Simek	/* save registers */
707ca54502bSMichal Simek/* MS: Make room on the stack -> activation record */
7086e83557cSMichal Simek	addik	r1, r1, -PT_SIZE;
709ca54502bSMichal Simek	SAVE_REGS
710ca54502bSMichal Simek	brid	2f;
7116e83557cSMichal Simek	swi	r1, r1, PT_MODE; /* 0 - user mode, 1 - kernel mode */
712ca54502bSMichal Simek1:
713ca54502bSMichal Simek/* User-mode state save. */
714ca54502bSMichal Simek /* MS: get the saved current */
715ca54502bSMichal Simek	lwi	r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE));
716ca54502bSMichal Simek	tophys(r1,r1);
717ca54502bSMichal Simek	lwi	r1, r1, TS_THREAD_INFO;
718ca54502bSMichal Simek	addik	r1, r1, THREAD_SIZE;
719ca54502bSMichal Simek	tophys(r1,r1);
720ca54502bSMichal Simek	/* save registers */
7216e83557cSMichal Simek	addik	r1, r1, -PT_SIZE;
722ca54502bSMichal Simek	SAVE_REGS
723ca54502bSMichal Simek	/* calculate mode */
7246e83557cSMichal Simek	swi	r0, r1, PT_MODE;
725ca54502bSMichal Simek	lwi	r11, r0, TOPHYS(PER_CPU(ENTRY_SP));
7266e83557cSMichal Simek	swi	r11, r1, PT_R1;
72780c5ff6bSMichal Simek	clear_ums;
728ca54502bSMichal Simek2:
729b1d70c62SMichal Simek	lwi	CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE));
730ca54502bSMichal Simek	tovirt(r1,r1)
731b9ea77e2SMichal Simek	addik	r15, r0, irq_call;
73280c5ff6bSMichal Simekirq_call:rtbd	r0, do_IRQ;
7336e83557cSMichal Simek	addik	r5, r1, 0;
734ca54502bSMichal Simek
735ca54502bSMichal Simek/* MS: we are in virtual mode */
736ca54502bSMichal Simekret_from_irq:
7376e83557cSMichal Simek	lwi	r11, r1, PT_MODE;
738ca54502bSMichal Simek	bnei	r11, 2f;
739ca54502bSMichal Simek
740e9f92526SAl Viro1:
741b1d70c62SMichal Simek	lwi	r11, CURRENT_TASK, TS_THREAD_INFO;
742e9f92526SAl Viro	lwi	r19, r11, TI_FLAGS; /* MS: get flags from thread info */
743e9f92526SAl Viro	andi	r11, r19, _TIF_NEED_RESCHED;
744ca54502bSMichal Simek	beqi	r11, 5f
745ca54502bSMichal Simek	bralid	r15, schedule;
746ca54502bSMichal Simek	nop; /* delay slot */
747e9f92526SAl Viro	bri	1b
748ca54502bSMichal Simek
749ca54502bSMichal Simek    /* Maybe handle a signal */
750e9f92526SAl Viro5:	andi	r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME;
751ca54502bSMichal Simek	beqid	r11, no_intr_resched
752ca54502bSMichal Simek/* Handle a signal return; Pending signals should be in r18. */
7536e83557cSMichal Simek	addik	r5, r1, 0; /* Arg 1: struct pt_regs *regs */
754969a9616SAl Viro	bralid	r15, do_notify_resume;	/* Handle any signals */
75583140191SAl Viro	addi	r6, r0, 0; /* Arg 2: int in_syscall */
756e9f92526SAl Viro	bri	1b
757ca54502bSMichal Simek
758ca54502bSMichal Simek/* Finally, return to user state. */
759ca54502bSMichal Simekno_intr_resched:
760ca54502bSMichal Simek    /* Disable interrupts, we are now committed to the state restore */
761ca54502bSMichal Simek	disable_irq
7628633bebcSMichal Simek	swi	CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE);
763ca54502bSMichal Simek	VM_OFF;
764ca54502bSMichal Simek	tophys(r1,r1);
765ca54502bSMichal Simek	RESTORE_REGS
7666e83557cSMichal Simek	addik	r1, r1, PT_SIZE /* MS: Clean up stack space. */
767ca54502bSMichal Simek	lwi	r1, r1, PT_R1 - PT_SIZE;
768ca54502bSMichal Simek	bri	6f;
769ca54502bSMichal Simek/* MS: Return to kernel state. */
77077753790SMichal Simek2:
77118803733SThomas Gleixner#ifdef CONFIG_PREEMPTION
772b1d70c62SMichal Simek	lwi	r11, CURRENT_TASK, TS_THREAD_INFO;
77377753790SMichal Simek	/* MS: get preempt_count from thread info */
77477753790SMichal Simek	lwi	r5, r11, TI_PREEMPT_COUNT;
77577753790SMichal Simek	bgti	r5, restore;
77677753790SMichal Simek
77777753790SMichal Simek	lwi	r5, r11, TI_FLAGS;		/* get flags in thread info */
77877753790SMichal Simek	andi	r5, r5, _TIF_NEED_RESCHED;
77977753790SMichal Simek	beqi	r5, restore /* if zero jump over */
78077753790SMichal Simek
78177753790SMichal Simek	/* interrupts are off that's why I am calling preempt_chedule_irq */
78277753790SMichal Simek	bralid	r15, preempt_schedule_irq
78377753790SMichal Simek	nop
78477753790SMichal Simekrestore:
78577753790SMichal Simek#endif
78677753790SMichal Simek	VM_OFF /* MS: turn off MMU */
787ca54502bSMichal Simek	tophys(r1,r1)
788ca54502bSMichal Simek	RESTORE_REGS
7896e83557cSMichal Simek	addik	r1, r1, PT_SIZE	/* MS: Clean up stack space. */
790ca54502bSMichal Simek	tovirt(r1,r1);
791ca54502bSMichal Simek6:
792ca54502bSMichal SimekIRQ_return: /* MS: Make global symbol for debugging */
793ca54502bSMichal Simek	rtid	r14, 0
794ca54502bSMichal Simek	nop
795ca54502bSMichal Simek
79688707ebeSAppana Durga Kedareswara rao#ifdef CONFIG_MB_MANAGER
79788707ebeSAppana Durga Kedareswara rao
79888707ebeSAppana Durga Kedareswara rao#define	PT_PID		PT_SIZE
79988707ebeSAppana Durga Kedareswara rao#define	PT_TLBI		PT_SIZE + 4
80088707ebeSAppana Durga Kedareswara rao#define	PT_ZPR		PT_SIZE	+ 8
80188707ebeSAppana Durga Kedareswara rao#define	PT_TLBL0	PT_SIZE + 12
80288707ebeSAppana Durga Kedareswara rao#define	PT_TLBH0	PT_SIZE + 16
80388707ebeSAppana Durga Kedareswara rao
80488707ebeSAppana Durga Kedareswara raoC_ENTRY(_xtmr_manager_reset):
80588707ebeSAppana Durga Kedareswara rao	lwi	r1, r0, xmb_manager_stackpointer
80688707ebeSAppana Durga Kedareswara rao
80788707ebeSAppana Durga Kedareswara rao	/* Restore MSR */
80888707ebeSAppana Durga Kedareswara rao	lwi	r2, r1, PT_MSR
80988707ebeSAppana Durga Kedareswara rao	mts	rmsr, r2
81088707ebeSAppana Durga Kedareswara rao	bri	4
81188707ebeSAppana Durga Kedareswara rao
81288707ebeSAppana Durga Kedareswara rao	/* restore Special purpose registers */
81388707ebeSAppana Durga Kedareswara rao	lwi	r2, r1, PT_PID
81488707ebeSAppana Durga Kedareswara rao	mts	rpid, r2
81588707ebeSAppana Durga Kedareswara rao
81688707ebeSAppana Durga Kedareswara rao	lwi	r2, r1, PT_TLBI
81788707ebeSAppana Durga Kedareswara rao	mts	rtlbx, r2
81888707ebeSAppana Durga Kedareswara rao
81988707ebeSAppana Durga Kedareswara rao	lwi	r2, r1, PT_ZPR
82088707ebeSAppana Durga Kedareswara rao	mts	rzpr, r2
82188707ebeSAppana Durga Kedareswara rao
82288707ebeSAppana Durga Kedareswara rao#if CONFIG_XILINX_MICROBLAZE0_USE_FPU
82388707ebeSAppana Durga Kedareswara rao	lwi	r2, r1, PT_FSR
82488707ebeSAppana Durga Kedareswara rao	mts	rfsr, r2
82588707ebeSAppana Durga Kedareswara rao#endif
82688707ebeSAppana Durga Kedareswara rao
82788707ebeSAppana Durga Kedareswara rao	/* restore all the tlb's */
82888707ebeSAppana Durga Kedareswara rao	addik	r3, r0, TOPHYS(tlb_skip)
82988707ebeSAppana Durga Kedareswara rao	addik	r6, r0, PT_TLBL0
83088707ebeSAppana Durga Kedareswara rao	addik	r7, r0, PT_TLBH0
83188707ebeSAppana Durga Kedareswara raorestore_tlb:
83288707ebeSAppana Durga Kedareswara rao	add	r6, r6, r1
83388707ebeSAppana Durga Kedareswara rao	add	r7, r7, r1
83488707ebeSAppana Durga Kedareswara rao	lwi	r2, r6, 0
83588707ebeSAppana Durga Kedareswara rao	mts 	rtlblo, r2
83688707ebeSAppana Durga Kedareswara rao	lwi	r2, r7, 0
83788707ebeSAppana Durga Kedareswara rao	mts	rtlbhi, r2
83888707ebeSAppana Durga Kedareswara rao	addik	r6, r6, 4
83988707ebeSAppana Durga Kedareswara rao	addik	r7, r7, 4
84088707ebeSAppana Durga Kedareswara rao	bgtid	r3, restore_tlb
84188707ebeSAppana Durga Kedareswara rao	addik	r3, r3, -1
84288707ebeSAppana Durga Kedareswara rao
84388707ebeSAppana Durga Kedareswara rao	lwi  	r5, r0, TOPHYS(xmb_manager_dev)
84488707ebeSAppana Durga Kedareswara rao	lwi	r8, r0, TOPHYS(xmb_manager_reset_callback)
84588707ebeSAppana Durga Kedareswara rao	set_vms
84688707ebeSAppana Durga Kedareswara rao	/* return from reset need -8 to adjust for rtsd r15, 8 */
84788707ebeSAppana Durga Kedareswara rao	addik   r15, r0, ret_from_reset - 8
84888707ebeSAppana Durga Kedareswara rao	rtbd	r8, 0
84988707ebeSAppana Durga Kedareswara rao	nop
85088707ebeSAppana Durga Kedareswara rao
85188707ebeSAppana Durga Kedareswara raoret_from_reset:
85288707ebeSAppana Durga Kedareswara rao	set_bip /* Ints masked for state restore */
85388707ebeSAppana Durga Kedareswara rao	VM_OFF
85488707ebeSAppana Durga Kedareswara rao	/* MS: Restore all regs */
85588707ebeSAppana Durga Kedareswara rao	RESTORE_REGS
85688707ebeSAppana Durga Kedareswara rao	lwi	r14, r1, PT_R14
85788707ebeSAppana Durga Kedareswara rao	lwi	r16, r1, PT_PC
85888707ebeSAppana Durga Kedareswara rao	addik	r1, r1, PT_SIZE + 36
85988707ebeSAppana Durga Kedareswara rao	rtbd	r16, 0
86088707ebeSAppana Durga Kedareswara rao	nop
86188707ebeSAppana Durga Kedareswara rao
86288707ebeSAppana Durga Kedareswara rao/*
86388707ebeSAppana Durga Kedareswara rao * Break handler for MB Manager. Enter to _xmb_manager_break by
86488707ebeSAppana Durga Kedareswara rao * injecting fault in one of the TMR Microblaze core.
86588707ebeSAppana Durga Kedareswara rao * FIXME: This break handler supports getting
86688707ebeSAppana Durga Kedareswara rao * called from kernel space only.
86788707ebeSAppana Durga Kedareswara rao */
86888707ebeSAppana Durga Kedareswara raoC_ENTRY(_xmb_manager_break):
86988707ebeSAppana Durga Kedareswara rao	/*
87088707ebeSAppana Durga Kedareswara rao	 * Reserve memory in the stack for context store/restore
87188707ebeSAppana Durga Kedareswara rao	 * (which includes memory for storing tlbs (max two tlbs))
87288707ebeSAppana Durga Kedareswara rao	 */
87388707ebeSAppana Durga Kedareswara rao	addik	r1, r1, -PT_SIZE - 36
87488707ebeSAppana Durga Kedareswara rao	swi	r1, r0, xmb_manager_stackpointer
87588707ebeSAppana Durga Kedareswara rao	SAVE_REGS
87688707ebeSAppana Durga Kedareswara rao	swi	r14, r1, PT_R14	/* rewrite saved R14 value */
87788707ebeSAppana Durga Kedareswara rao	swi	r16, r1, PT_PC; /* PC and r16 are the same */
87888707ebeSAppana Durga Kedareswara rao
87988707ebeSAppana Durga Kedareswara rao	lwi	r6, r0, TOPHYS(xmb_manager_baseaddr)
88088707ebeSAppana Durga Kedareswara rao	lwi	r7, r0, TOPHYS(xmb_manager_crval)
88188707ebeSAppana Durga Kedareswara rao	/*
88288707ebeSAppana Durga Kedareswara rao	 * When the break vector gets asserted because of error injection,
88388707ebeSAppana Durga Kedareswara rao	 * the break signal must be blocked before exiting from the
88488707ebeSAppana Durga Kedareswara rao	 * break handler, below code configures the tmr manager
88588707ebeSAppana Durga Kedareswara rao	 * control register to block break signal.
88688707ebeSAppana Durga Kedareswara rao	 */
88788707ebeSAppana Durga Kedareswara rao	swi	r7, r6, 0
88888707ebeSAppana Durga Kedareswara rao
88988707ebeSAppana Durga Kedareswara rao	/* Save the special purpose registers  */
89088707ebeSAppana Durga Kedareswara rao	mfs	r2, rpid
89188707ebeSAppana Durga Kedareswara rao	swi	r2, r1, PT_PID
89288707ebeSAppana Durga Kedareswara rao
89388707ebeSAppana Durga Kedareswara rao	mfs	r2, rtlbx
89488707ebeSAppana Durga Kedareswara rao	swi	r2, r1, PT_TLBI
89588707ebeSAppana Durga Kedareswara rao
89688707ebeSAppana Durga Kedareswara rao	mfs	r2, rzpr
89788707ebeSAppana Durga Kedareswara rao	swi	r2, r1, PT_ZPR
89888707ebeSAppana Durga Kedareswara rao
89988707ebeSAppana Durga Kedareswara rao#if CONFIG_XILINX_MICROBLAZE0_USE_FPU
90088707ebeSAppana Durga Kedareswara rao	mfs	r2, rfsr
90188707ebeSAppana Durga Kedareswara rao	swi	r2, r1, PT_FSR
90288707ebeSAppana Durga Kedareswara rao#endif
90388707ebeSAppana Durga Kedareswara rao	mfs	r2, rmsr
90488707ebeSAppana Durga Kedareswara rao	swi	r2, r1, PT_MSR
90588707ebeSAppana Durga Kedareswara rao
90688707ebeSAppana Durga Kedareswara rao	/* Save all the tlb's */
90788707ebeSAppana Durga Kedareswara rao	addik	r3, r0, TOPHYS(tlb_skip)
90888707ebeSAppana Durga Kedareswara rao	addik	r6, r0, PT_TLBL0
90988707ebeSAppana Durga Kedareswara rao	addik	r7, r0, PT_TLBH0
91088707ebeSAppana Durga Kedareswara raosave_tlb:
91188707ebeSAppana Durga Kedareswara rao	add	r6, r6, r1
91288707ebeSAppana Durga Kedareswara rao	add	r7, r7, r1
91388707ebeSAppana Durga Kedareswara rao	mfs	r2, rtlblo
91488707ebeSAppana Durga Kedareswara rao	swi	r2, r6, 0
91588707ebeSAppana Durga Kedareswara rao	mfs	r2, rtlbhi
91688707ebeSAppana Durga Kedareswara rao	swi	r2, r7, 0
91788707ebeSAppana Durga Kedareswara rao	addik	r6, r6, 4
91888707ebeSAppana Durga Kedareswara rao	addik	r7, r7, 4
91988707ebeSAppana Durga Kedareswara rao	bgtid	r3, save_tlb
92088707ebeSAppana Durga Kedareswara rao	addik	r3, r3, -1
92188707ebeSAppana Durga Kedareswara rao
92288707ebeSAppana Durga Kedareswara rao	lwi  	r5, r0, TOPHYS(xmb_manager_dev)
92388707ebeSAppana Durga Kedareswara rao	lwi	r8, r0, TOPHYS(xmb_manager_callback)
92488707ebeSAppana Durga Kedareswara rao	/* return from break need -8 to adjust for rtsd r15, 8 */
92588707ebeSAppana Durga Kedareswara rao	addik   r15, r0, ret_from_break - 8
92688707ebeSAppana Durga Kedareswara rao	rtbd	r8, 0
92788707ebeSAppana Durga Kedareswara rao	nop
92888707ebeSAppana Durga Kedareswara rao
92988707ebeSAppana Durga Kedareswara raoret_from_break:
93088707ebeSAppana Durga Kedareswara rao	/* flush the d-cache */
93188707ebeSAppana Durga Kedareswara rao	bralid	r15, mb_flush_dcache
93288707ebeSAppana Durga Kedareswara rao	nop
93388707ebeSAppana Durga Kedareswara rao
93488707ebeSAppana Durga Kedareswara rao	/*
93588707ebeSAppana Durga Kedareswara rao	 * To make sure microblaze i-cache is in a proper state
93688707ebeSAppana Durga Kedareswara rao	 * invalidate the i-cache.
93788707ebeSAppana Durga Kedareswara rao	 */
93888707ebeSAppana Durga Kedareswara rao	bralid	r15, mb_invalidate_icache
93988707ebeSAppana Durga Kedareswara rao	nop
94088707ebeSAppana Durga Kedareswara rao
94188707ebeSAppana Durga Kedareswara rao	set_bip; /* Ints masked for state restore */
94288707ebeSAppana Durga Kedareswara rao	VM_OFF;
94388707ebeSAppana Durga Kedareswara rao	mbar	1
94488707ebeSAppana Durga Kedareswara rao	mbar	2
94588707ebeSAppana Durga Kedareswara rao	bri	4
94688707ebeSAppana Durga Kedareswara rao	suspend
94788707ebeSAppana Durga Kedareswara rao	nop
94888707ebeSAppana Durga Kedareswara rao#endif
94988707ebeSAppana Durga Kedareswara rao
950ca54502bSMichal Simek/*
9512d5973cbSMichal Simek * Debug trap for KGDB. Enter to _debug_exception by brki r16, 0x18
9522d5973cbSMichal Simek * and call handling function with saved pt_regs
953ca54502bSMichal Simek */
954ca54502bSMichal SimekC_ENTRY(_debug_exception):
955ca54502bSMichal Simek	/* BIP bit is set on entry, no interrupts can occur */
956ca54502bSMichal Simek	swi	r1, r0, TOPHYS(PER_CPU(ENTRY_SP))
957ca54502bSMichal Simek
958653e447eSMichal Simek	mfs	r1, rmsr
9595c0d72b1SMichal Simek	nop
960653e447eSMichal Simek	andi	r1, r1, MSR_UMS
961653e447eSMichal Simek	bnei	r1, 1f
9622d5973cbSMichal Simek/* MS: Kernel-mode state save - kgdb */
963653e447eSMichal Simek	lwi	r1, r0, TOPHYS(PER_CPU(ENTRY_SP)); /* Reload kernel stack-ptr*/
964ca54502bSMichal Simek
9652d5973cbSMichal Simek	/* BIP bit is set on entry, no interrupts can occur */
9666e83557cSMichal Simek	addik   r1, r1, CONFIG_KERNEL_BASE_ADDR - CONFIG_KERNEL_START - PT_SIZE;
967ca54502bSMichal Simek	SAVE_REGS;
9682d5973cbSMichal Simek	/* save all regs to pt_reg structure */
9696e83557cSMichal Simek	swi	r0, r1, PT_R0;	/* R0 must be saved too */
9706e83557cSMichal Simek	swi	r14, r1, PT_R14	/* rewrite saved R14 value */
9716e83557cSMichal Simek	swi	r16, r1, PT_PC; /* PC and r16 are the same */
9722d5973cbSMichal Simek	/* save special purpose registers to pt_regs */
9732d5973cbSMichal Simek	mfs	r11, rear;
9746e83557cSMichal Simek	swi	r11, r1, PT_EAR;
9752d5973cbSMichal Simek	mfs	r11, resr;
9766e83557cSMichal Simek	swi	r11, r1, PT_ESR;
9772d5973cbSMichal Simek	mfs	r11, rfsr;
9786e83557cSMichal Simek	swi	r11, r1, PT_FSR;
979ca54502bSMichal Simek
9802d5973cbSMichal Simek	/* stack pointer is in physical address at it is decrease
9816e83557cSMichal Simek	 * by PT_SIZE but we need to get correct R1 value */
9826e83557cSMichal Simek	addik   r11, r1, CONFIG_KERNEL_START - CONFIG_KERNEL_BASE_ADDR + PT_SIZE;
9836e83557cSMichal Simek	swi	r11, r1, PT_R1
9842d5973cbSMichal Simek	/* MS: r31 - current pointer isn't changed */
9852d5973cbSMichal Simek	tovirt(r1,r1)
9862d5973cbSMichal Simek#ifdef CONFIG_KGDB
9876e83557cSMichal Simek	addi	r5, r1, 0 /* pass pt_reg address as the first arg */
988cd341577SMichal Simek	addik	r15, r0, dbtrap_call; /* return address */
9892d5973cbSMichal Simek	rtbd	r0, microblaze_kgdb_break
9902d5973cbSMichal Simek	nop;
9912d5973cbSMichal Simek#endif
9922d5973cbSMichal Simek	/* MS: Place handler for brki from kernel space if KGDB is OFF.
9932d5973cbSMichal Simek	 * It is very unlikely that another brki instruction is called. */
9942d5973cbSMichal Simek	bri 0
9952d5973cbSMichal Simek
9962d5973cbSMichal Simek/* MS: User-mode state save - gdb */
9972d5973cbSMichal Simek1:	lwi	r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */
998ca54502bSMichal Simek	tophys(r1,r1);
999ca54502bSMichal Simek	lwi	r1, r1, TS_THREAD_INFO;	/* get the thread info */
1000ca54502bSMichal Simek	addik	r1, r1, THREAD_SIZE;	/* calculate kernel stack pointer */
1001ca54502bSMichal Simek	tophys(r1,r1);
1002ca54502bSMichal Simek
10036e83557cSMichal Simek	addik	r1, r1, -PT_SIZE; /* Make room on the stack.  */
1004ca54502bSMichal Simek	SAVE_REGS;
10056e83557cSMichal Simek	swi	r16, r1, PT_PC;	/* Save LP */
10066e83557cSMichal Simek	swi	r0, r1, PT_MODE; /* Was in user-mode.  */
1007ca54502bSMichal Simek	lwi	r11, r0, TOPHYS(PER_CPU(ENTRY_SP));
10086e83557cSMichal Simek	swi	r11, r1, PT_R1; /* Store user SP.  */
10092d5973cbSMichal Simek	lwi	CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE));
1010ca54502bSMichal Simek	tovirt(r1,r1)
101106b28640SMichal Simek	set_vms;
10126e83557cSMichal Simek	addik	r5, r1, 0;
1013b9ea77e2SMichal Simek	addik	r15, r0, dbtrap_call;
10142d5973cbSMichal Simekdbtrap_call: /* Return point for kernel/user entry + 8 because of rtsd r15, 8 */
1015751f1605SMichal Simek	rtbd	r0, sw_exception
1016751f1605SMichal Simek	nop
1017ca54502bSMichal Simek
10182d5973cbSMichal Simek	/* MS: The first instruction for the second part of the gdb/kgdb */
1019ca54502bSMichal Simek	set_bip; /* Ints masked for state restore */
10206e83557cSMichal Simek	lwi	r11, r1, PT_MODE;
1021ca54502bSMichal Simek	bnei	r11, 2f;
10222d5973cbSMichal Simek/* MS: Return to user space - gdb */
1023e9f92526SAl Viro1:
1024ca54502bSMichal Simek	/* Get current task ptr into r11 */
1025b1d70c62SMichal Simek	lwi	r11, CURRENT_TASK, TS_THREAD_INFO;	/* get thread info */
1026e9f92526SAl Viro	lwi	r19, r11, TI_FLAGS;	/* get flags in thread info */
1027e9f92526SAl Viro	andi	r11, r19, _TIF_NEED_RESCHED;
1028ca54502bSMichal Simek	beqi	r11, 5f;
1029ca54502bSMichal Simek
1030ca54502bSMichal Simek	/* Call the scheduler before returning from a syscall/trap. */
1031ca54502bSMichal Simek	bralid	r15, schedule;	/* Call scheduler */
1032ca54502bSMichal Simek	nop;				/* delay slot */
1033e9f92526SAl Viro	bri	1b
1034ca54502bSMichal Simek
1035ca54502bSMichal Simek	/* Maybe handle a signal */
1036e9f92526SAl Viro5:	andi	r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME;
1037e9f92526SAl Viro	beqi	r11, 4f;		/* Signals to handle, handle them */
1038ca54502bSMichal Simek
10396e83557cSMichal Simek	addik	r5, r1, 0;		/* Arg 1: struct pt_regs *regs */
1040969a9616SAl Viro	bralid	r15, do_notify_resume;	/* Handle any signals */
104183140191SAl Viro	addi  r6, r0, 0;	/* Arg 2: int in_syscall */
1042e9f92526SAl Viro	bri	1b
1043ca54502bSMichal Simek
1044ca54502bSMichal Simek/* Finally, return to user state.  */
1045e9f92526SAl Viro4:	swi	CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */
1046ca54502bSMichal Simek	VM_OFF;
1047ca54502bSMichal Simek	tophys(r1,r1);
10482d5973cbSMichal Simek	/* MS: Restore all regs */
104914ef905bSMichal Simek	RESTORE_REGS_RTBD
10506e83557cSMichal Simek	addik	r1, r1, PT_SIZE	 /* Clean up stack space */
10512d5973cbSMichal Simek	lwi	r1, r1, PT_R1 - PT_SIZE; /* Restore user stack pointer */
10522d5973cbSMichal SimekDBTRAP_return_user: /* MS: Make global symbol for debugging */
10532d5973cbSMichal Simek	rtbd	r16, 0; /* MS: Instructions to return from a debug trap */
10542d5973cbSMichal Simek	nop;
1055ca54502bSMichal Simek
10562d5973cbSMichal Simek/* MS: Return to kernel state - kgdb */
1057ca54502bSMichal Simek2:	VM_OFF;
1058ca54502bSMichal Simek	tophys(r1,r1);
10592d5973cbSMichal Simek	/* MS: Restore all regs */
106014ef905bSMichal Simek	RESTORE_REGS_RTBD
10616e83557cSMichal Simek	lwi	r14, r1, PT_R14;
10626e83557cSMichal Simek	lwi	r16, r1, PT_PC;
10636e83557cSMichal Simek	addik	r1, r1, PT_SIZE; /* MS: Clean up stack space */
1064ca54502bSMichal Simek	tovirt(r1,r1);
10652d5973cbSMichal SimekDBTRAP_return_kernel: /* MS: Make global symbol for debugging */
10662d5973cbSMichal Simek	rtbd	r16, 0; /* MS: Instructions to return from a debug trap */
1067ca54502bSMichal Simek	nop;
1068ca54502bSMichal Simek
1069ca54502bSMichal Simek
1070ca54502bSMichal SimekENTRY(_switch_to)
1071ca54502bSMichal Simek	/* prepare return value */
1072b1d70c62SMichal Simek	addk	r3, r0, CURRENT_TASK
1073ca54502bSMichal Simek
1074ca54502bSMichal Simek	/* save registers in cpu_context */
1075ca54502bSMichal Simek	/* use r11 and r12, volatile registers, as temp register */
1076ca54502bSMichal Simek	/* give start of cpu_context for previous process */
1077ca54502bSMichal Simek	addik	r11, r5, TI_CPU_CONTEXT
1078ca54502bSMichal Simek	swi	r1, r11, CC_R1
1079ca54502bSMichal Simek	swi	r2, r11, CC_R2
1080ca54502bSMichal Simek	/* skip volatile registers.
1081ca54502bSMichal Simek	 * they are saved on stack when we jumped to _switch_to() */
1082ca54502bSMichal Simek	/* dedicated registers */
1083ca54502bSMichal Simek	swi	r13, r11, CC_R13
1084ca54502bSMichal Simek	swi	r14, r11, CC_R14
1085ca54502bSMichal Simek	swi	r15, r11, CC_R15
1086ca54502bSMichal Simek	swi	r16, r11, CC_R16
1087ca54502bSMichal Simek	swi	r17, r11, CC_R17
1088ca54502bSMichal Simek	swi	r18, r11, CC_R18
1089ca54502bSMichal Simek	/* save non-volatile registers */
1090ca54502bSMichal Simek	swi	r19, r11, CC_R19
1091ca54502bSMichal Simek	swi	r20, r11, CC_R20
1092ca54502bSMichal Simek	swi	r21, r11, CC_R21
1093ca54502bSMichal Simek	swi	r22, r11, CC_R22
1094ca54502bSMichal Simek	swi	r23, r11, CC_R23
1095ca54502bSMichal Simek	swi	r24, r11, CC_R24
1096ca54502bSMichal Simek	swi	r25, r11, CC_R25
1097ca54502bSMichal Simek	swi	r26, r11, CC_R26
1098ca54502bSMichal Simek	swi	r27, r11, CC_R27
1099ca54502bSMichal Simek	swi	r28, r11, CC_R28
1100ca54502bSMichal Simek	swi	r29, r11, CC_R29
1101ca54502bSMichal Simek	swi	r30, r11, CC_R30
1102ca54502bSMichal Simek	/* special purpose registers */
1103ca54502bSMichal Simek	mfs	r12, rmsr
1104ca54502bSMichal Simek	swi	r12, r11, CC_MSR
1105ca54502bSMichal Simek	mfs	r12, rear
1106ca54502bSMichal Simek	swi	r12, r11, CC_EAR
1107ca54502bSMichal Simek	mfs	r12, resr
1108ca54502bSMichal Simek	swi	r12, r11, CC_ESR
1109ca54502bSMichal Simek	mfs	r12, rfsr
1110ca54502bSMichal Simek	swi	r12, r11, CC_FSR
1111ca54502bSMichal Simek
1112b1d70c62SMichal Simek	/* update r31, the current-give me pointer to task which will be next */
1113b1d70c62SMichal Simek	lwi	CURRENT_TASK, r6, TI_TASK
1114ca54502bSMichal Simek	/* stored it to current_save too */
1115b1d70c62SMichal Simek	swi	CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE)
1116ca54502bSMichal Simek
1117ca54502bSMichal Simek	/* get new process' cpu context and restore */
1118ca54502bSMichal Simek	/* give me start where start context of next task */
1119ca54502bSMichal Simek	addik	r11, r6, TI_CPU_CONTEXT
1120ca54502bSMichal Simek
1121ca54502bSMichal Simek	/* non-volatile registers */
1122ca54502bSMichal Simek	lwi	r30, r11, CC_R30
1123ca54502bSMichal Simek	lwi	r29, r11, CC_R29
1124ca54502bSMichal Simek	lwi	r28, r11, CC_R28
1125ca54502bSMichal Simek	lwi	r27, r11, CC_R27
1126ca54502bSMichal Simek	lwi	r26, r11, CC_R26
1127ca54502bSMichal Simek	lwi	r25, r11, CC_R25
1128ca54502bSMichal Simek	lwi	r24, r11, CC_R24
1129ca54502bSMichal Simek	lwi	r23, r11, CC_R23
1130ca54502bSMichal Simek	lwi	r22, r11, CC_R22
1131ca54502bSMichal Simek	lwi	r21, r11, CC_R21
1132ca54502bSMichal Simek	lwi	r20, r11, CC_R20
1133ca54502bSMichal Simek	lwi	r19, r11, CC_R19
1134ca54502bSMichal Simek	/* dedicated registers */
1135ca54502bSMichal Simek	lwi	r18, r11, CC_R18
1136ca54502bSMichal Simek	lwi	r17, r11, CC_R17
1137ca54502bSMichal Simek	lwi	r16, r11, CC_R16
1138ca54502bSMichal Simek	lwi	r15, r11, CC_R15
1139ca54502bSMichal Simek	lwi	r14, r11, CC_R14
1140ca54502bSMichal Simek	lwi	r13, r11, CC_R13
1141ca54502bSMichal Simek	/* skip volatile registers */
1142ca54502bSMichal Simek	lwi	r2, r11, CC_R2
1143ca54502bSMichal Simek	lwi	r1, r11, CC_R1
1144ca54502bSMichal Simek
1145ca54502bSMichal Simek	/* special purpose registers */
1146ca54502bSMichal Simek	lwi	r12, r11, CC_FSR
1147ca54502bSMichal Simek	mts	rfsr, r12
1148ca54502bSMichal Simek	lwi	r12, r11, CC_MSR
1149ca54502bSMichal Simek	mts	rmsr, r12
1150ca54502bSMichal Simek
1151ca54502bSMichal Simek	rtsd	r15, 8
1152ca54502bSMichal Simek	nop
1153ca54502bSMichal Simek
1154a5e3aaa6SAppana Durga Kedareswara rao#ifdef CONFIG_MB_MANAGER
1155*adc4cefaSAppana Durga Kedareswara rao.global xmb_inject_err
1156*adc4cefaSAppana Durga Kedareswara rao.section .text
1157*adc4cefaSAppana Durga Kedareswara rao.align 2
1158*adc4cefaSAppana Durga Kedareswara rao.ent xmb_inject_err
1159*adc4cefaSAppana Durga Kedareswara rao.type xmb_inject_err, @function
1160*adc4cefaSAppana Durga Kedareswara raoxmb_inject_err:
1161*adc4cefaSAppana Durga Kedareswara rao	addik	r1, r1, -PT_SIZE
1162*adc4cefaSAppana Durga Kedareswara rao	SAVE_REGS
1163*adc4cefaSAppana Durga Kedareswara rao
1164*adc4cefaSAppana Durga Kedareswara rao	/* Switch to real mode */
1165*adc4cefaSAppana Durga Kedareswara rao	VM_OFF;
1166*adc4cefaSAppana Durga Kedareswara rao	set_bip;
1167*adc4cefaSAppana Durga Kedareswara rao	mbar	1
1168*adc4cefaSAppana Durga Kedareswara rao	mbar	2
1169*adc4cefaSAppana Durga Kedareswara rao	bralid	r15, XMB_INJECT_ERR_OFFSET
1170*adc4cefaSAppana Durga Kedareswara rao	nop;
1171*adc4cefaSAppana Durga Kedareswara rao
1172*adc4cefaSAppana Durga Kedareswara rao	/* enable virtual mode */
1173*adc4cefaSAppana Durga Kedareswara rao	set_vms;
1174*adc4cefaSAppana Durga Kedareswara rao	/* barrier for instructions and data accesses */
1175*adc4cefaSAppana Durga Kedareswara rao	mbar	1
1176*adc4cefaSAppana Durga Kedareswara rao	mbar	2
1177*adc4cefaSAppana Durga Kedareswara rao	/*
1178*adc4cefaSAppana Durga Kedareswara rao	 * Enable Interrupts, Virtual Protected Mode, equalize
1179*adc4cefaSAppana Durga Kedareswara rao	 * initial state for all possible entries.
1180*adc4cefaSAppana Durga Kedareswara rao	 */
1181*adc4cefaSAppana Durga Kedareswara rao	rtbd    r0, 1f
1182*adc4cefaSAppana Durga Kedareswara rao	nop;
1183*adc4cefaSAppana Durga Kedareswara rao1:
1184*adc4cefaSAppana Durga Kedareswara rao	RESTORE_REGS
1185*adc4cefaSAppana Durga Kedareswara rao	addik	r1, r1, PT_SIZE
1186*adc4cefaSAppana Durga Kedareswara rao	rtsd	r15, 8;
1187*adc4cefaSAppana Durga Kedareswara rao	nop;
1188*adc4cefaSAppana Durga Kedareswara rao.end xmb_inject_err
1189*adc4cefaSAppana Durga Kedareswara rao
1190a5e3aaa6SAppana Durga Kedareswara rao.section .data
1191a5e3aaa6SAppana Durga Kedareswara rao.global xmb_manager_dev
1192a5e3aaa6SAppana Durga Kedareswara rao.global xmb_manager_baseaddr
1193a5e3aaa6SAppana Durga Kedareswara rao.global xmb_manager_crval
1194a5e3aaa6SAppana Durga Kedareswara rao.global xmb_manager_callback
1195a5e3aaa6SAppana Durga Kedareswara rao.global xmb_manager_reset_callback
119688707ebeSAppana Durga Kedareswara rao.global xmb_manager_stackpointer
1197a5e3aaa6SAppana Durga Kedareswara rao.align 4
1198a5e3aaa6SAppana Durga Kedareswara raoxmb_manager_dev:
1199a5e3aaa6SAppana Durga Kedareswara rao	.long 0
1200a5e3aaa6SAppana Durga Kedareswara raoxmb_manager_baseaddr:
1201a5e3aaa6SAppana Durga Kedareswara rao	.long 0
1202a5e3aaa6SAppana Durga Kedareswara raoxmb_manager_crval:
1203a5e3aaa6SAppana Durga Kedareswara rao	.long 0
1204a5e3aaa6SAppana Durga Kedareswara raoxmb_manager_callback:
1205a5e3aaa6SAppana Durga Kedareswara rao	.long 0
1206a5e3aaa6SAppana Durga Kedareswara raoxmb_manager_reset_callback:
1207a5e3aaa6SAppana Durga Kedareswara rao	.long 0
120888707ebeSAppana Durga Kedareswara raoxmb_manager_stackpointer:
120988707ebeSAppana Durga Kedareswara rao	.long 0
1210a5e3aaa6SAppana Durga Kedareswara rao
1211a5e3aaa6SAppana Durga Kedareswara rao/*
1212a5e3aaa6SAppana Durga Kedareswara rao * When the break vector gets asserted because of error injection,
1213a5e3aaa6SAppana Durga Kedareswara rao * the break signal must be blocked before exiting from the
1214a5e3aaa6SAppana Durga Kedareswara rao * break handler, Below api updates the manager address and
1215a5e3aaa6SAppana Durga Kedareswara rao * control register and error count callback arguments,
1216a5e3aaa6SAppana Durga Kedareswara rao * which will be used by the break handler to block the
1217a5e3aaa6SAppana Durga Kedareswara rao * break and call the callback function.
1218a5e3aaa6SAppana Durga Kedareswara rao */
1219a5e3aaa6SAppana Durga Kedareswara rao.global xmb_manager_register
1220a5e3aaa6SAppana Durga Kedareswara rao.section .text
1221a5e3aaa6SAppana Durga Kedareswara rao.align 2
1222a5e3aaa6SAppana Durga Kedareswara rao.ent xmb_manager_register
1223a5e3aaa6SAppana Durga Kedareswara rao.type xmb_manager_register, @function
1224a5e3aaa6SAppana Durga Kedareswara raoxmb_manager_register:
1225a5e3aaa6SAppana Durga Kedareswara rao	swi	r5, r0, xmb_manager_baseaddr
1226a5e3aaa6SAppana Durga Kedareswara rao	swi	r6, r0, xmb_manager_crval
1227a5e3aaa6SAppana Durga Kedareswara rao	swi	r7, r0, xmb_manager_callback
1228a5e3aaa6SAppana Durga Kedareswara rao	swi	r8, r0, xmb_manager_dev
1229a5e3aaa6SAppana Durga Kedareswara rao	swi	r9, r0, xmb_manager_reset_callback
1230a5e3aaa6SAppana Durga Kedareswara rao
1231a5e3aaa6SAppana Durga Kedareswara rao	rtsd	r15, 8;
1232a5e3aaa6SAppana Durga Kedareswara rao	nop;
1233a5e3aaa6SAppana Durga Kedareswara rao.end xmb_manager_register
1234a5e3aaa6SAppana Durga Kedareswara rao#endif
1235a5e3aaa6SAppana Durga Kedareswara rao
1236ca54502bSMichal SimekENTRY(_reset)
12375119c418SMichal Simek	VM_OFF
12387574349cSMichal Simek	brai	0; /* Jump to reset vector */
1239ca54502bSMichal Simek
1240ca54502bSMichal Simek	/* These are compiled and loaded into high memory, then
1241ca54502bSMichal Simek	 * copied into place in mach_early_setup */
1242ca54502bSMichal Simek	.section	.init.ivt, "ax"
124388707ebeSAppana Durga Kedareswara rao#if CONFIG_MANUAL_RESET_VECTOR && !defined(CONFIG_MB_MANAGER)
1244ca54502bSMichal Simek	.org	0x0
12450b9b0200SMichal Simek	brai	CONFIG_MANUAL_RESET_VECTOR
124688707ebeSAppana Durga Kedareswara rao#elif defined(CONFIG_MB_MANAGER)
124788707ebeSAppana Durga Kedareswara rao	.org	0x0
124888707ebeSAppana Durga Kedareswara rao	brai	TOPHYS(_xtmr_manager_reset);
12490b9b0200SMichal Simek#endif
1250626afa35SMichal Simek	.org	0x8
1251ca54502bSMichal Simek	brai	TOPHYS(_user_exception); /* syscall handler */
1252626afa35SMichal Simek	.org	0x10
1253ca54502bSMichal Simek	brai	TOPHYS(_interrupt);	/* Interrupt handler */
125488707ebeSAppana Durga Kedareswara rao#ifdef CONFIG_MB_MANAGER
125588707ebeSAppana Durga Kedareswara rao	.org	0x18
125688707ebeSAppana Durga Kedareswara rao	brai	TOPHYS(_xmb_manager_break);	/* microblaze manager break handler */
125788707ebeSAppana Durga Kedareswara rao#else
1258626afa35SMichal Simek	.org	0x18
1259ca54502bSMichal Simek	brai	TOPHYS(_debug_exception);	/* debug trap handler */
126088707ebeSAppana Durga Kedareswara rao#endif
1261626afa35SMichal Simek	.org	0x20
1262751f1605SMichal Simek	brai	TOPHYS(_hw_exception_handler);	/* HW exception handler */
1263ca54502bSMichal Simek
1264*adc4cefaSAppana Durga Kedareswara rao#ifdef CONFIG_MB_MANAGER
1265*adc4cefaSAppana Durga Kedareswara rao	/*
1266*adc4cefaSAppana Durga Kedareswara rao	 * For TMR Inject API which injects the error should
1267*adc4cefaSAppana Durga Kedareswara rao	 * be executed from LMB.
1268*adc4cefaSAppana Durga Kedareswara rao	 * TMR Inject is programmed with address of 0x200 so that
1269*adc4cefaSAppana Durga Kedareswara rao	 * when program counter matches with this address error will
1270*adc4cefaSAppana Durga Kedareswara rao	 * be injected. 0x200 is expected to be next available bram
1271*adc4cefaSAppana Durga Kedareswara rao	 * offset, hence used for this api.
1272*adc4cefaSAppana Durga Kedareswara rao	 */
1273*adc4cefaSAppana Durga Kedareswara rao	.org	XMB_INJECT_ERR_OFFSET
1274*adc4cefaSAppana Durga Kedareswara raoxmb_inject_error:
1275*adc4cefaSAppana Durga Kedareswara rao	nop
1276*adc4cefaSAppana Durga Kedareswara rao	rtsd	r15, 8
1277*adc4cefaSAppana Durga Kedareswara rao	nop
1278*adc4cefaSAppana Durga Kedareswara rao#endif
1279*adc4cefaSAppana Durga Kedareswara rao
1280ca54502bSMichal Simek.section .rodata,"a"
1281ca54502bSMichal Simek#include "syscall_table.S"
1282ca54502bSMichal Simek
1283ca54502bSMichal Simeksyscall_table_size=(.-sys_call_table)
1284ca54502bSMichal Simek
1285ce3266c0SSteven J. Magnanitype_SYSCALL:
1286ce3266c0SSteven J. Magnani	.ascii "SYSCALL\0"
1287ce3266c0SSteven J. Magnanitype_IRQ:
1288ce3266c0SSteven J. Magnani	.ascii "IRQ\0"
1289ce3266c0SSteven J. Magnanitype_IRQ_PREEMPT:
1290ce3266c0SSteven J. Magnani	.ascii "IRQ (PREEMPTED)\0"
1291ce3266c0SSteven J. Magnanitype_SYSCALL_PREEMPT:
1292ce3266c0SSteven J. Magnani	.ascii " SYSCALL (PREEMPTED)\0"
1293ce3266c0SSteven J. Magnani
1294ce3266c0SSteven J. Magnani	/*
1295ce3266c0SSteven J. Magnani	 * Trap decoding for stack unwinder
1296ce3266c0SSteven J. Magnani	 * Tuples are (start addr, end addr, string)
1297ce3266c0SSteven J. Magnani	 * If return address lies on [start addr, end addr],
1298ce3266c0SSteven J. Magnani	 * unwinder displays 'string'
1299ce3266c0SSteven J. Magnani	 */
1300ce3266c0SSteven J. Magnani
1301ce3266c0SSteven J. Magnani	.align 4
1302ce3266c0SSteven J. Magnani.global microblaze_trap_handlers
1303ce3266c0SSteven J. Magnanimicroblaze_trap_handlers:
1304ce3266c0SSteven J. Magnani	/* Exact matches come first */
1305ce3266c0SSteven J. Magnani	.word ret_from_trap; .word ret_from_trap   ; .word type_SYSCALL
1306ce3266c0SSteven J. Magnani	.word ret_from_irq ; .word ret_from_irq    ; .word type_IRQ
1307ce3266c0SSteven J. Magnani	/* Fuzzy matches go here */
1308ce3266c0SSteven J. Magnani	.word ret_from_irq ; .word no_intr_resched ; .word type_IRQ_PREEMPT
1309ce3266c0SSteven J. Magnani	.word ret_from_trap; .word TRAP_return     ; .word type_SYSCALL_PREEMPT
1310ce3266c0SSteven J. Magnani	/* End of table */
1311ce3266c0SSteven J. Magnani	.word 0               ; .word 0               ; .word 0
1312