xref: /openbmc/linux/arch/microblaze/kernel/hw_exception_handler.S (revision cdd38c5f1ce4398ec58fec95904b75824daab7b5)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3  * Exception handling for Microblaze
4  *
5  * Rewriten interrupt handling
6  *
7  * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
8  * Copyright (C) 2008-2009 PetaLogix
9  *
10  * uClinux customisation (C) 2005 John Williams
11  *
12  * MMU code derived from arch/ppc/kernel/head_4xx.S:
13  *	Copyright (C) 1995-1996 Gary Thomas <gdt@linuxppc.org>
14  *		Initial PowerPC version.
15  *	Copyright (C) 1996 Cort Dougan <cort@cs.nmt.edu>
16  *		Rewritten for PReP
17  *	Copyright (C) 1996 Paul Mackerras <paulus@cs.anu.edu.au>
18  *		Low-level exception handers, MMU support, and rewrite.
19  *	Copyright (C) 1997 Dan Malek <dmalek@jlc.net>
20  *		PowerPC 8xx modifications.
21  *	Copyright (C) 1998-1999 TiVo, Inc.
22  *		PowerPC 403GCX modifications.
23  *	Copyright (C) 1999 Grant Erickson <grant@lcse.umn.edu>
24  *		PowerPC 403GCX/405GP modifications.
25  *	Copyright 2000 MontaVista Software Inc.
26  *		PPC405 modifications
27  *	PowerPC 403GCX/405GP modifications.
28  *		Author: MontaVista Software, Inc.
29  *		frank_rowand@mvista.com or source@mvista.com
30  *		debbie_chu@mvista.com
31  *
32  * Original code
33  * Copyright (C) 2004 Xilinx, Inc.
34  */
35 
36 /*
37  * Here are the handlers which don't require enabling translation
38  * and calling other kernel code thus we can keep their design very simple
39  * and do all processing in real mode. All what they need is a valid current
40  * (that is an issue for the CONFIG_REGISTER_TASK_PTR case)
41  * This handlers use r3,r4,r5,r6 and optionally r[current] to work therefore
42  * these registers are saved/restored
43  * The handlers which require translation are in entry.S --KAA
44  *
45  * Microblaze HW Exception Handler
46  * - Non self-modifying exception handler for the following exception conditions
47  *   - Unalignment
48  *   - Instruction bus error
49  *   - Data bus error
50  *   - Illegal instruction opcode
51  *   - Divide-by-zero
52  *
53  *   - Privileged instruction exception (MMU)
54  *   - Data storage exception (MMU)
55  *   - Instruction storage exception (MMU)
56  *   - Data TLB miss exception (MMU)
57  *   - Instruction TLB miss exception (MMU)
58  *
59  * Note we disable interrupts during exception handling, otherwise we will
60  * possibly get multiple re-entrancy if interrupt handles themselves cause
61  * exceptions. JW
62  */
63 
64 #include <asm/exceptions.h>
65 #include <asm/unistd.h>
66 #include <asm/page.h>
67 
68 #include <asm/entry.h>
69 #include <asm/current.h>
70 #include <linux/linkage.h>
71 #include <linux/pgtable.h>
72 
73 #include <asm/mmu.h>
74 #include <asm/signal.h>
75 #include <asm/registers.h>
76 #include <asm/asm-offsets.h>
77 
78 #undef DEBUG
79 
80 /* Helpful Macros */
81 #define NUM_TO_REG(num)		r ## num
82 
83 	#define RESTORE_STATE			\
84 		lwi	r5, r1, 0;		\
85 		mts	rmsr, r5;		\
86 		nop;				\
87 		lwi	r3, r1, PT_R3;		\
88 		lwi	r4, r1, PT_R4;		\
89 		lwi	r5, r1, PT_R5;		\
90 		lwi	r6, r1, PT_R6;		\
91 		lwi	r11, r1, PT_R11;	\
92 		lwi	r31, r1, PT_R31;	\
93 		lwi	r1, r1, PT_R1;
94 
95 #define LWREG_NOP			\
96 	bri	ex_handler_unhandled;	\
97 	nop;
98 
99 #define SWREG_NOP			\
100 	bri	ex_handler_unhandled;	\
101 	nop;
102 
103 /* r3 is the source */
104 #define R3_TO_LWREG_V(regnum)				\
105 	swi	r3, r1, 4 * regnum;				\
106 	bri	ex_handler_done;
107 
108 /* r3 is the source */
109 #define R3_TO_LWREG(regnum)				\
110 	or	NUM_TO_REG (regnum), r0, r3;		\
111 	bri	ex_handler_done;
112 
113 /* r3 is the target */
114 #define SWREG_TO_R3_V(regnum)				\
115 	lwi	r3, r1, 4 * regnum;				\
116 	bri	ex_sw_tail;
117 
118 /* r3 is the target */
119 #define SWREG_TO_R3(regnum)				\
120 	or	r3, r0, NUM_TO_REG (regnum);		\
121 	bri	ex_sw_tail;
122 
123 	#define R3_TO_LWREG_VM_V(regnum)		\
124 		brid	ex_lw_end_vm;			\
125 		swi	r3, r7, 4 * regnum;
126 
127 	#define R3_TO_LWREG_VM(regnum)			\
128 		brid	ex_lw_end_vm;			\
129 		or	NUM_TO_REG (regnum), r0, r3;
130 
131 	#define SWREG_TO_R3_VM_V(regnum)		\
132 		brid	ex_sw_tail_vm;			\
133 		lwi	r3, r7, 4 * regnum;
134 
135 	#define SWREG_TO_R3_VM(regnum)			\
136 		brid	ex_sw_tail_vm;			\
137 		or	r3, r0, NUM_TO_REG (regnum);
138 
139 	/* Shift right instruction depending on available configuration */
140 	#if CONFIG_XILINX_MICROBLAZE0_USE_BARREL == 0
141 	/* Only the used shift constants defined here - add more if needed */
142 	#define BSRLI2(rD, rA)				\
143 		srl rD, rA;		/* << 1 */	\
144 		srl rD, rD;		/* << 2 */
145 	#define BSRLI4(rD, rA)		\
146 		BSRLI2(rD, rA);		\
147 		BSRLI2(rD, rD)
148 	#define BSRLI10(rD, rA)				\
149 		srl rD, rA;		/* << 1 */	\
150 		srl rD, rD;		/* << 2 */	\
151 		srl rD, rD;		/* << 3 */	\
152 		srl rD, rD;		/* << 4 */	\
153 		srl rD, rD;		/* << 5 */	\
154 		srl rD, rD;		/* << 6 */	\
155 		srl rD, rD;		/* << 7 */	\
156 		srl rD, rD;		/* << 8 */	\
157 		srl rD, rD;		/* << 9 */	\
158 		srl rD, rD		/* << 10 */
159 	#define BSRLI20(rD, rA)		\
160 		BSRLI10(rD, rA);	\
161 		BSRLI10(rD, rD)
162 
163 	.macro	bsrli, rD, rA, IMM
164 	.if (\IMM) == 2
165 		BSRLI2(\rD, \rA)
166 	.elseif (\IMM) == 10
167 		BSRLI10(\rD, \rA)
168 	.elseif (\IMM) == 12
169 		BSRLI2(\rD, \rA)
170 		BSRLI10(\rD, \rD)
171 	.elseif (\IMM) == 14
172 		BSRLI4(\rD, \rA)
173 		BSRLI10(\rD, \rD)
174 	.elseif (\IMM) == 20
175 		BSRLI20(\rD, \rA)
176 	.elseif (\IMM) == 24
177 		BSRLI4(\rD, \rA)
178 		BSRLI20(\rD, \rD)
179 	.elseif (\IMM) == 28
180 		BSRLI4(\rD, \rA)
181 		BSRLI4(\rD, \rD)
182 		BSRLI20(\rD, \rD)
183 	.else
184 	.error "BSRLI shift macros \IMM"
185 	.endif
186 	.endm
187 	#endif
188 
189 
190 .extern other_exception_handler /* Defined in exception.c */
191 
192 /*
193  * hw_exception_handler - Handler for exceptions
194  *
195  * Exception handler notes:
196  * - Handles all exceptions
197  * - Does not handle unaligned exceptions during load into r17, r1, r0.
198  * - Does not handle unaligned exceptions during store from r17 (cannot be
199  *   done) and r1 (slows down common case)
200  *
201  *  Relevant register structures
202  *
203  *  EAR - |----|----|----|----|----|----|----|----|
204  *      - <  ##   32 bit faulting address     ##  >
205  *
206  *  ESR - |----|----|----|----|----| - | - |-----|-----|
207  *      -                            W   S   REG   EXC
208  *
209  *
210  * STACK FRAME STRUCTURE (for CONFIG_MMU=n)
211  * ----------------------------------------
212  *
213  *      +-------------+         + 0
214  *      |     MSR     |
215  *      +-------------+         + 4
216  *      |     r1      |
217  *      |      .      |
218  *      |      .      |
219  *      |      .      |
220  *      |      .      |
221  *      |     r18     |
222  *      +-------------+         + 76
223  *      |      .      |
224  *      |      .      |
225  *
226  * MMU kernel uses the same 'pt_pool_space' pointed space
227  * which is used for storing register values - noMMu style was, that values were
228  * stored in stack but in case of failure you lost information about register.
229  * Currently you can see register value in memory in specific place.
230  * In compare to with previous solution the speed should be the same.
231  *
232  * MMU exception handler has different handling compare to no MMU kernel.
233  * Exception handler use jump table for directing of what happen. For MMU kernel
234  * is this approach better because MMU relate exception are handled by asm code
235  * in this file. In compare to with MMU expect of unaligned exception
236  * is everything handled by C code.
237  */
238 
239 /*
240  * every of these handlers is entered having R3/4/5/6/11/current saved on stack
241  * and clobbered so care should be taken to restore them if someone is going to
242  * return from exception
243  */
244 
245 /* wrappers to restore state before coming to entry.S */
246 .section .data
247 .align 4
248 pt_pool_space:
249 	.space	PT_SIZE
250 
251 #ifdef DEBUG
252 /* Create space for exception counting. */
253 .section .data
254 .global exception_debug_table
255 .align 4
256 exception_debug_table:
257 	/* Look at exception vector table. There is 32 exceptions * word size */
258 	.space	(32 * 4)
259 #endif /* DEBUG */
260 
261 .section .rodata
262 .align 4
263 _MB_HW_ExceptionVectorTable:
264 /*  0 - Undefined */
265 	.long	TOPHYS(ex_handler_unhandled)
266 /*  1 - Unaligned data access exception */
267 	.long	TOPHYS(handle_unaligned_ex)
268 /*  2 - Illegal op-code exception */
269 	.long	TOPHYS(full_exception_trapw)
270 /*  3 - Instruction bus error exception */
271 	.long	TOPHYS(full_exception_trapw)
272 /*  4 - Data bus error exception */
273 	.long	TOPHYS(full_exception_trapw)
274 /*  5 - Divide by zero exception */
275 	.long	TOPHYS(full_exception_trapw)
276 /*  6 - Floating point unit exception */
277 	.long	TOPHYS(full_exception_trapw)
278 /*  7 - Privileged instruction exception */
279 	.long	TOPHYS(full_exception_trapw)
280 /*  8 - 15 - Undefined */
281 	.long	TOPHYS(ex_handler_unhandled)
282 	.long	TOPHYS(ex_handler_unhandled)
283 	.long	TOPHYS(ex_handler_unhandled)
284 	.long	TOPHYS(ex_handler_unhandled)
285 	.long	TOPHYS(ex_handler_unhandled)
286 	.long	TOPHYS(ex_handler_unhandled)
287 	.long	TOPHYS(ex_handler_unhandled)
288 	.long	TOPHYS(ex_handler_unhandled)
289 /* 16 - Data storage exception */
290 	.long	TOPHYS(handle_data_storage_exception)
291 /* 17 - Instruction storage exception */
292 	.long	TOPHYS(handle_instruction_storage_exception)
293 /* 18 - Data TLB miss exception */
294 	.long	TOPHYS(handle_data_tlb_miss_exception)
295 /* 19 - Instruction TLB miss exception */
296 	.long	TOPHYS(handle_instruction_tlb_miss_exception)
297 /* 20 - 31 - Undefined */
298 	.long	TOPHYS(ex_handler_unhandled)
299 	.long	TOPHYS(ex_handler_unhandled)
300 	.long	TOPHYS(ex_handler_unhandled)
301 	.long	TOPHYS(ex_handler_unhandled)
302 	.long	TOPHYS(ex_handler_unhandled)
303 	.long	TOPHYS(ex_handler_unhandled)
304 	.long	TOPHYS(ex_handler_unhandled)
305 	.long	TOPHYS(ex_handler_unhandled)
306 	.long	TOPHYS(ex_handler_unhandled)
307 	.long	TOPHYS(ex_handler_unhandled)
308 	.long	TOPHYS(ex_handler_unhandled)
309 	.long	TOPHYS(ex_handler_unhandled)
310 
311 .global _hw_exception_handler
312 .section .text
313 .align 4
314 .ent _hw_exception_handler
315 _hw_exception_handler:
316 	swi	r1, r0, TOPHYS(pt_pool_space + PT_R1); /* GET_SP */
317 	/* Save date to kernel memory. Here is the problem
318 	 * when you came from user space */
319 	ori	r1, r0, TOPHYS(pt_pool_space);
320 	swi	r3, r1, PT_R3
321 	swi	r4, r1, PT_R4
322 	swi	r5, r1, PT_R5
323 	swi	r6, r1, PT_R6
324 
325 	swi	r11, r1, PT_R11
326 	swi	r31, r1, PT_R31
327 	lwi	r31, r0, TOPHYS(PER_CPU(CURRENT_SAVE)) /* get saved current */
328 
329 	mfs	r5, rmsr;
330 	nop
331 	swi	r5, r1, 0;
332 	mfs	r4, resr
333 	nop
334 	mfs	r3, rear;
335 	nop
336 
337 	andi	r5, r4, 0x1F;		/* Extract ESR[EXC] */
338 
339 	/* Calculate exception vector offset = r5 << 2 */
340 	addk	r6, r5, r5; /* << 1 */
341 	addk	r6, r6, r6; /* << 2 */
342 
343 #ifdef DEBUG
344 /* counting which exception happen */
345 	lwi	r5, r0, TOPHYS(exception_debug_table)
346 	addi	r5, r5, 1
347 	swi	r5, r0, TOPHYS(exception_debug_table)
348 	lwi	r5, r6, TOPHYS(exception_debug_table)
349 	addi	r5, r5, 1
350 	swi	r5, r6, TOPHYS(exception_debug_table)
351 #endif
352 /* end */
353 	/* Load the HW Exception vector */
354 	lwi	r6, r6, TOPHYS(_MB_HW_ExceptionVectorTable)
355 	bra	r6
356 
357 full_exception_trapw:
358 	RESTORE_STATE
359 	bri	full_exception_trap
360 
361 /* 0x01 - Unaligned data access exception
362  * This occurs when a word access is not aligned on a word boundary,
363  * or when a 16-bit access is not aligned on a 16-bit boundary.
364  * This handler perform the access, and returns, except for MMU when
365  * the unaligned address is last on a 4k page or the physical address is
366  * not found in the page table, in which case unaligned_data_trap is called.
367  */
368 handle_unaligned_ex:
369 	/* Working registers already saved: R3, R4, R5, R6
370 	 *  R4 = ESR
371 	 *  R3 = EAR
372 	 */
373 	andi	r6, r4, 0x1000			/* Check ESR[DS] */
374 	beqi	r6, _no_delayslot		/* Branch if ESR[DS] not set */
375 	mfs	r17, rbtr;	/* ESR[DS] set - return address in BTR */
376 	nop
377 _no_delayslot:
378 	/* jump to high level unaligned handler */
379 	RESTORE_STATE;
380 	bri	unaligned_data_trap
381 
382 	andi	r6, r4, 0x3E0; /* Mask and extract the register operand */
383 	srl	r6, r6; /* r6 >> 5 */
384 	srl	r6, r6;
385 	srl	r6, r6;
386 	srl	r6, r6;
387 	srl	r6, r6;
388 	/* Store the register operand in a temporary location */
389 	sbi	r6, r0, TOPHYS(ex_reg_op);
390 
391 	andi	r6, r4, 0x400; /* Extract ESR[S] */
392 	bnei	r6, ex_sw;
393 ex_lw:
394 	andi	r6, r4, 0x800; /* Extract ESR[W] */
395 	beqi	r6, ex_lhw;
396 	lbui	r5, r3, 0; /* Exception address in r3 */
397 	/* Load a word, byte-by-byte from destination address
398 		and save it in tmp space */
399 	sbi	r5, r0, TOPHYS(ex_tmp_data_loc_0);
400 	lbui	r5, r3, 1;
401 	sbi	r5, r0, TOPHYS(ex_tmp_data_loc_1);
402 	lbui	r5, r3, 2;
403 	sbi	r5, r0, TOPHYS(ex_tmp_data_loc_2);
404 	lbui	r5, r3, 3;
405 	sbi	r5, r0, TOPHYS(ex_tmp_data_loc_3);
406 	/* Get the destination register value into r4 */
407 	lwi	r4, r0, TOPHYS(ex_tmp_data_loc_0);
408 	bri	ex_lw_tail;
409 ex_lhw:
410 	lbui	r5, r3, 0; /* Exception address in r3 */
411 	/* Load a half-word, byte-by-byte from destination
412 		address and save it in tmp space */
413 	sbi	r5, r0, TOPHYS(ex_tmp_data_loc_0);
414 	lbui	r5, r3, 1;
415 	sbi	r5, r0, TOPHYS(ex_tmp_data_loc_1);
416 	/* Get the destination register value into r4 */
417 	lhui	r4, r0, TOPHYS(ex_tmp_data_loc_0);
418 ex_lw_tail:
419 	/* Get the destination register number into r5 */
420 	lbui	r5, r0, TOPHYS(ex_reg_op);
421 	/* Form load_word jump table offset (lw_table + (8 * regnum)) */
422 	addik	r6, r0, TOPHYS(lw_table);
423 	addk	r5, r5, r5;
424 	addk	r5, r5, r5;
425 	addk	r5, r5, r5;
426 	addk	r5, r5, r6;
427 	bra	r5;
428 ex_lw_end: /* Exception handling of load word, ends */
429 ex_sw:
430 	/* Get the destination register number into r5 */
431 	lbui	r5, r0, TOPHYS(ex_reg_op);
432 	/* Form store_word jump table offset (sw_table + (8 * regnum)) */
433 	addik	r6, r0, TOPHYS(sw_table);
434 	add	r5, r5, r5;
435 	add	r5, r5, r5;
436 	add	r5, r5, r5;
437 	add	r5, r5, r6;
438 	bra	r5;
439 ex_sw_tail:
440 	mfs	r6, resr;
441 	nop
442 	andi	r6, r6, 0x800; /* Extract ESR[W] */
443 	beqi	r6, ex_shw;
444 	/* Get the word - delay slot */
445 	swi	r4, r0, TOPHYS(ex_tmp_data_loc_0);
446 	/* Store the word, byte-by-byte into destination address */
447 	lbui	r4, r0, TOPHYS(ex_tmp_data_loc_0);
448 	sbi	r4, r3, 0;
449 	lbui	r4, r0, TOPHYS(ex_tmp_data_loc_1);
450 	sbi	r4, r3, 1;
451 	lbui	r4, r0, TOPHYS(ex_tmp_data_loc_2);
452 	sbi	r4, r3, 2;
453 	lbui	r4, r0, TOPHYS(ex_tmp_data_loc_3);
454 	sbi	r4, r3, 3;
455 	bri	ex_handler_done;
456 
457 ex_shw:
458 	/* Store the lower half-word, byte-by-byte into destination address */
459 	swi	r4, r0, TOPHYS(ex_tmp_data_loc_0);
460 	lbui	r4, r0, TOPHYS(ex_tmp_data_loc_2);
461 	sbi	r4, r3, 0;
462 	lbui	r4, r0, TOPHYS(ex_tmp_data_loc_3);
463 	sbi	r4, r3, 1;
464 ex_sw_end: /* Exception handling of store word, ends. */
465 
466 ex_handler_done:
467 	RESTORE_STATE;
468 	rted	r17, 0
469 	nop
470 
471 	/* Exception vector entry code. This code runs with address translation
472 	 * turned off (i.e. using physical addresses). */
473 
474 	/* Exception vectors. */
475 
476 	/* 0x10 - Data Storage Exception
477 	 * This happens for just a few reasons. U0 set (but we don't do that),
478 	 * or zone protection fault (user violation, write to protected page).
479 	 * If this is just an update of modified status, we do that quickly
480 	 * and exit. Otherwise, we call heavyweight functions to do the work.
481 	 */
482 	handle_data_storage_exception:
483 		/* Working registers already saved: R3, R4, R5, R6
484 		 * R3 = ESR
485 		 */
486 		mfs	r11, rpid
487 		nop
488 		/* If we are faulting a kernel address, we have to use the
489 		 * kernel page tables.
490 		 */
491 		ori	r5, r0, CONFIG_KERNEL_START
492 		cmpu	r5, r3, r5
493 		bgti	r5, ex3
494 		/* First, check if it was a zone fault (which means a user
495 		 * tried to access a kernel or read-protected page - always
496 		 * a SEGV). All other faults here must be stores, so no
497 		 * need to check ESR_S as well. */
498 		andi	r4, r4, ESR_DIZ		/* ESR_Z - zone protection */
499 		bnei	r4, ex2
500 
501 		ori	r4, r0, swapper_pg_dir
502 		mts	rpid, r0		/* TLB will have 0 TID */
503 		nop
504 		bri	ex4
505 
506 		/* Get the PGD for the current thread. */
507 	ex3:
508 		/* First, check if it was a zone fault (which means a user
509 		 * tried to access a kernel or read-protected page - always
510 		 * a SEGV). All other faults here must be stores, so no
511 		 * need to check ESR_S as well. */
512 		andi	r4, r4, ESR_DIZ		/* ESR_Z */
513 		bnei	r4, ex2
514 		/* get current task address */
515 		addi	r4 ,CURRENT_TASK, TOPHYS(0);
516 		lwi	r4, r4, TASK_THREAD+PGDIR
517 	ex4:
518 		tophys(r4,r4)
519 		/* Create L1 (pgdir/pmd) address */
520 		bsrli	r5, r3, PGDIR_SHIFT - 2
521 		andi	r5, r5, PAGE_SIZE - 4
522 /* Assume pgdir aligned on 4K boundary, no need for "andi r4,r4,0xfffff003" */
523 		or	r4, r4, r5
524 		lwi	r4, r4, 0		/* Get L1 entry */
525 		andi	r5, r4, PAGE_MASK /* Extract L2 (pte) base address */
526 		beqi	r5, ex2			/* Bail if no table */
527 
528 		tophys(r5,r5)
529 		bsrli	r6, r3, PTE_SHIFT /* Compute PTE address */
530 		andi	r6, r6, PAGE_SIZE - 4
531 		or	r5, r5, r6
532 		lwi	r4, r5, 0		/* Get Linux PTE */
533 
534 		andi	r6, r4, _PAGE_RW	/* Is it writeable? */
535 		beqi	r6, ex2			/* Bail if not */
536 
537 		/* Update 'changed' */
538 		ori	r4, r4, _PAGE_DIRTY|_PAGE_ACCESSED|_PAGE_HWWRITE
539 		swi	r4, r5, 0		/* Update Linux page table */
540 
541 		/* Most of the Linux PTE is ready to load into the TLB LO.
542 		 * We set ZSEL, where only the LS-bit determines user access.
543 		 * We set execute, because we don't have the granularity to
544 		 * properly set this at the page level (Linux problem).
545 		 * If shared is set, we cause a zero PID->TID load.
546 		 * Many of these bits are software only. Bits we don't set
547 		 * here we (properly should) assume have the appropriate value.
548 		 */
549 /* Ignore memory coherent, just LSB on ZSEL is used + EX/WR */
550 		andi	r4, r4, PAGE_MASK | TLB_EX | TLB_WR | \
551 						TLB_ZSEL(1) | TLB_ATTR_MASK
552 		ori	r4, r4, _PAGE_HWEXEC	/* make it executable */
553 
554 		/* find the TLB index that caused the fault. It has to be here*/
555 		mts	rtlbsx, r3
556 		nop
557 		mfs	r5, rtlbx		/* DEBUG: TBD */
558 		nop
559 		mts	rtlblo, r4		/* Load TLB LO */
560 		nop
561 						/* Will sync shadow TLBs */
562 
563 		/* Done...restore registers and get out of here. */
564 		mts	rpid, r11
565 		nop
566 		bri 4
567 
568 		RESTORE_STATE;
569 		rted	r17, 0
570 		nop
571 	ex2:
572 		/* The bailout. Restore registers to pre-exception conditions
573 		 * and call the heavyweights to help us out. */
574 		mts	rpid, r11
575 		nop
576 		bri 4
577 		RESTORE_STATE;
578 		bri	page_fault_data_trap
579 
580 
581 	/* 0x11 - Instruction Storage Exception
582 	 * This is caused by a fetch from non-execute or guarded pages. */
583 	handle_instruction_storage_exception:
584 		/* Working registers already saved: R3, R4, R5, R6
585 		 * R3 = ESR
586 		 */
587 
588 		RESTORE_STATE;
589 		bri	page_fault_instr_trap
590 
591 	/* 0x12 - Data TLB Miss Exception
592 	 * As the name implies, translation is not in the MMU, so search the
593 	 * page tables and fix it. The only purpose of this function is to
594 	 * load TLB entries from the page table if they exist.
595 	 */
596 	handle_data_tlb_miss_exception:
597 		/* Working registers already saved: R3, R4, R5, R6
598 		 * R3 = EAR, R4 = ESR
599 		 */
600 		mfs	r11, rpid
601 		nop
602 
603 		/* If we are faulting a kernel address, we have to use the
604 		 * kernel page tables. */
605 		ori	r6, r0, CONFIG_KERNEL_START
606 		cmpu	r4, r3, r6
607 		bgti	r4, ex5
608 		ori	r4, r0, swapper_pg_dir
609 		mts	rpid, r0		/* TLB will have 0 TID */
610 		nop
611 		bri	ex6
612 
613 		/* Get the PGD for the current thread. */
614 	ex5:
615 		/* get current task address */
616 		addi	r4 ,CURRENT_TASK, TOPHYS(0);
617 		lwi	r4, r4, TASK_THREAD+PGDIR
618 	ex6:
619 		tophys(r4,r4)
620 		/* Create L1 (pgdir/pmd) address */
621 		bsrli	r5, r3, PGDIR_SHIFT - 2
622 		andi	r5, r5, PAGE_SIZE - 4
623 /* Assume pgdir aligned on 4K boundary, no need for "andi r4,r4,0xfffff003" */
624 		or	r4, r4, r5
625 		lwi	r4, r4, 0		/* Get L1 entry */
626 		andi	r5, r4, PAGE_MASK /* Extract L2 (pte) base address */
627 		beqi	r5, ex7			/* Bail if no table */
628 
629 		tophys(r5,r5)
630 		bsrli	r6, r3, PTE_SHIFT /* Compute PTE address */
631 		andi	r6, r6, PAGE_SIZE - 4
632 		or	r5, r5, r6
633 		lwi	r4, r5, 0		/* Get Linux PTE */
634 
635 		andi	r6, r4, _PAGE_PRESENT
636 		beqi	r6, ex7
637 
638 		ori	r4, r4, _PAGE_ACCESSED
639 		swi	r4, r5, 0
640 
641 		/* Most of the Linux PTE is ready to load into the TLB LO.
642 		 * We set ZSEL, where only the LS-bit determines user access.
643 		 * We set execute, because we don't have the granularity to
644 		 * properly set this at the page level (Linux problem).
645 		 * If shared is set, we cause a zero PID->TID load.
646 		 * Many of these bits are software only. Bits we don't set
647 		 * here we (properly should) assume have the appropriate value.
648 		 */
649 		brid	finish_tlb_load
650 		andi	r4, r4, PAGE_MASK | TLB_EX | TLB_WR | \
651 						TLB_ZSEL(1) | TLB_ATTR_MASK
652 	ex7:
653 		/* The bailout. Restore registers to pre-exception conditions
654 		 * and call the heavyweights to help us out.
655 		 */
656 		mts	rpid, r11
657 		nop
658 		bri	4
659 		RESTORE_STATE;
660 		bri	page_fault_data_trap
661 
662 	/* 0x13 - Instruction TLB Miss Exception
663 	 * Nearly the same as above, except we get our information from
664 	 * different registers and bailout to a different point.
665 	 */
666 	handle_instruction_tlb_miss_exception:
667 		/* Working registers already saved: R3, R4, R5, R6
668 		 *  R3 = ESR
669 		 */
670 		mfs	r11, rpid
671 		nop
672 
673 		/* If we are faulting a kernel address, we have to use the
674 		 * kernel page tables.
675 		 */
676 		ori	r4, r0, CONFIG_KERNEL_START
677 		cmpu	r4, r3, r4
678 		bgti	r4, ex8
679 		ori	r4, r0, swapper_pg_dir
680 		mts	rpid, r0		/* TLB will have 0 TID */
681 		nop
682 		bri	ex9
683 
684 		/* Get the PGD for the current thread. */
685 	ex8:
686 		/* get current task address */
687 		addi	r4 ,CURRENT_TASK, TOPHYS(0);
688 		lwi	r4, r4, TASK_THREAD+PGDIR
689 	ex9:
690 		tophys(r4,r4)
691 		/* Create L1 (pgdir/pmd) address */
692 		bsrli	r5, r3, PGDIR_SHIFT - 2
693 		andi	r5, r5, PAGE_SIZE - 4
694 /* Assume pgdir aligned on 4K boundary, no need for "andi r4,r4,0xfffff003" */
695 		or	r4, r4, r5
696 		lwi	r4, r4, 0		/* Get L1 entry */
697 		andi	r5, r4, PAGE_MASK /* Extract L2 (pte) base address */
698 		beqi	r5, ex10		/* Bail if no table */
699 
700 		tophys(r5,r5)
701 		bsrli	r6, r3, PTE_SHIFT /* Compute PTE address */
702 		andi	r6, r6, PAGE_SIZE - 4
703 		or	r5, r5, r6
704 		lwi	r4, r5, 0		/* Get Linux PTE */
705 
706 		andi	r6, r4, _PAGE_PRESENT
707 		beqi	r6, ex10
708 
709 		ori	r4, r4, _PAGE_ACCESSED
710 		swi	r4, r5, 0
711 
712 		/* Most of the Linux PTE is ready to load into the TLB LO.
713 		 * We set ZSEL, where only the LS-bit determines user access.
714 		 * We set execute, because we don't have the granularity to
715 		 * properly set this at the page level (Linux problem).
716 		 * If shared is set, we cause a zero PID->TID load.
717 		 * Many of these bits are software only. Bits we don't set
718 		 * here we (properly should) assume have the appropriate value.
719 		 */
720 		brid	finish_tlb_load
721 		andi	r4, r4, PAGE_MASK | TLB_EX | TLB_WR | \
722 						TLB_ZSEL(1) | TLB_ATTR_MASK
723 	ex10:
724 		/* The bailout. Restore registers to pre-exception conditions
725 		 * and call the heavyweights to help us out.
726 		 */
727 		mts	rpid, r11
728 		nop
729 		bri 4
730 		RESTORE_STATE;
731 		bri	page_fault_instr_trap
732 
733 /* Both the instruction and data TLB miss get to this point to load the TLB.
734  *	r3 - EA of fault
735  *	r4 - TLB LO (info from Linux PTE)
736  *	r5, r6 - available to use
737  *	PID - loaded with proper value when we get here
738  *	Upon exit, we reload everything and RFI.
739  * A common place to load the TLB.
740  */
741 .section .data
742 .align 4
743 .global tlb_skip
744 	tlb_skip:
745 		.long	MICROBLAZE_TLB_SKIP
746 	tlb_index:
747 		/* MS: storing last used tlb index */
748 		.long	MICROBLAZE_TLB_SIZE/2
749 .previous
750 	finish_tlb_load:
751 		/* MS: load the last used TLB index. */
752 		lwi	r5, r0, TOPHYS(tlb_index)
753 		addik	r5, r5, 1 /* MS: inc tlb_index -> use next one */
754 
755 /* MS: FIXME this is potential fault, because this is mask not count */
756 		andi	r5, r5, MICROBLAZE_TLB_SIZE - 1
757 		ori	r6, r0, 1
758 		cmp	r31, r5, r6
759 		blti	r31, ex12
760 		lwi	r5, r0, TOPHYS(tlb_skip)
761 	ex12:
762 		/* MS: save back current TLB index */
763 		swi	r5, r0, TOPHYS(tlb_index)
764 
765 		ori	r4, r4, _PAGE_HWEXEC	/* make it executable */
766 		mts	rtlbx, r5		/* MS: save current TLB */
767 		nop
768 		mts	rtlblo,	r4		/* MS: save to TLB LO */
769 		nop
770 
771 		/* Create EPN. This is the faulting address plus a static
772 		 * set of bits. These are size, valid, E, U0, and ensure
773 		 * bits 20 and 21 are zero.
774 		 */
775 		andi	r3, r3, PAGE_MASK
776 		ori	r3, r3, TLB_VALID | TLB_PAGESZ(PAGESZ_4K)
777 		mts	rtlbhi,	r3		/* Load TLB HI */
778 		nop
779 
780 		/* Done...restore registers and get out of here. */
781 		mts	rpid, r11
782 		nop
783 		bri 4
784 		RESTORE_STATE;
785 		rted	r17, 0
786 		nop
787 
788 	/* extern void giveup_fpu(struct task_struct *prev)
789 	 *
790 	 * The MicroBlaze processor may have an FPU, so this should not just
791 	 * return: TBD.
792 	 */
793 	.globl giveup_fpu;
794 	.align 4;
795 	giveup_fpu:
796 		bralid	r15,0			/* TBD */
797 		nop
798 
799 	/* At present, this routine just hangs. - extern void abort(void) */
800 	.globl abort;
801 	.align 4;
802 	abort:
803 		br	r0
804 
805 	.globl set_context;
806 	.align 4;
807 	set_context:
808 		mts	rpid, r5	/* Shadow TLBs are automatically */
809 		nop
810 		bri	4		/* flushed by changing PID */
811 		rtsd	r15,8
812 		nop
813 
814 .end _hw_exception_handler
815 
816 /* Unaligned data access exception last on a 4k page for MMU.
817  * When this is called, we are in virtual mode with exceptions enabled
818  * and registers 1-13,15,17,18 saved.
819  *
820  * R3 = ESR
821  * R4 = EAR
822  * R7 = pointer to saved registers (struct pt_regs *regs)
823  *
824  * This handler perform the access, and returns via ret_from_exc.
825  */
826 .global _unaligned_data_exception
827 .ent _unaligned_data_exception
828 _unaligned_data_exception:
829 	andi	r8, r3, 0x3E0;	/* Mask and extract the register operand */
830 	bsrli   r8, r8, 2;		/* r8 >> 2 = register operand * 8 */
831 	andi	r6, r3, 0x400;	/* Extract ESR[S] */
832 	bneid	r6, ex_sw_vm;
833 	andi	r6, r3, 0x800;	/* Extract ESR[W] - delay slot */
834 ex_lw_vm:
835 	beqid	r6, ex_lhw_vm;
836 load1:	lbui	r5, r4, 0;	/* Exception address in r4 - delay slot */
837 /* Load a word, byte-by-byte from destination address and save it in tmp space*/
838 	addik	r6, r0, ex_tmp_data_loc_0;
839 	sbi	r5, r6, 0;
840 load2:	lbui	r5, r4, 1;
841 	sbi	r5, r6, 1;
842 load3:	lbui	r5, r4, 2;
843 	sbi	r5, r6, 2;
844 load4:	lbui	r5, r4, 3;
845 	sbi	r5, r6, 3;
846 	brid	ex_lw_tail_vm;
847 /* Get the destination register value into r3 - delay slot */
848 	lwi	r3, r6, 0;
849 ex_lhw_vm:
850 	/* Load a half-word, byte-by-byte from destination address and
851 	 * save it in tmp space */
852 	addik	r6, r0, ex_tmp_data_loc_0;
853 	sbi	r5, r6, 0;
854 load5:	lbui	r5, r4, 1;
855 	sbi	r5, r6, 1;
856 	lhui	r3, r6, 0;	/* Get the destination register value into r3 */
857 ex_lw_tail_vm:
858 	/* Form load_word jump table offset (lw_table_vm + (8 * regnum)) */
859 	addik	r5, r8, lw_table_vm;
860 	bra	r5;
861 ex_lw_end_vm:			/* Exception handling of load word, ends */
862 	brai	ret_from_exc;
863 ex_sw_vm:
864 /* Form store_word jump table offset (sw_table_vm + (8 * regnum)) */
865 	addik	r5, r8, sw_table_vm;
866 	bra	r5;
867 ex_sw_tail_vm:
868 	addik	r5, r0, ex_tmp_data_loc_0;
869 	beqid	r6, ex_shw_vm;
870 	swi	r3, r5, 0;	/* Get the word - delay slot */
871 	/* Store the word, byte-by-byte into destination address */
872 	lbui	r3, r5, 0;
873 store1:	sbi	r3, r4, 0;
874 	lbui	r3, r5, 1;
875 store2:	sbi	r3, r4, 1;
876 	lbui	r3, r5, 2;
877 store3:	sbi	r3, r4, 2;
878 	lbui	r3, r5, 3;
879 	brid	ret_from_exc;
880 store4:	sbi	r3, r4, 3;	/* Delay slot */
881 ex_shw_vm:
882 	/* Store the lower half-word, byte-by-byte into destination address */
883 #ifdef __MICROBLAZEEL__
884 	lbui	r3, r5, 0;
885 store5:	sbi	r3, r4, 0;
886 	lbui	r3, r5, 1;
887 	brid	ret_from_exc;
888 store6:	sbi	r3, r4, 1;	/* Delay slot */
889 #else
890 	lbui	r3, r5, 2;
891 store5:	sbi	r3, r4, 0;
892 	lbui	r3, r5, 3;
893 	brid	ret_from_exc;
894 store6:	sbi	r3, r4, 1;	/* Delay slot */
895 #endif
896 
897 ex_sw_end_vm:			/* Exception handling of store word, ends. */
898 
899 /* We have to prevent cases that get/put_user macros get unaligned pointer
900  * to bad page area. We have to find out which origin instruction caused it
901  * and called fixup for that origin instruction not instruction in unaligned
902  * handler */
903 ex_unaligned_fixup:
904 	ori	r5, r7, 0 /* setup pointer to pt_regs */
905 	lwi	r6, r7, PT_PC; /* faulting address is one instruction above */
906 	addik	r6, r6, -4 /* for finding proper fixup */
907 	swi	r6, r7, PT_PC; /* a save back it to PT_PC */
908 	addik	r7, r0, SIGSEGV
909 	/* call bad_page_fault for finding aligned fixup, fixup address is saved
910 	 * in PT_PC which is used as return address from exception */
911 	addik	r15, r0, ret_from_exc-8 /* setup return address */
912 	brid	bad_page_fault
913 	nop
914 
915 /* We prevent all load/store because it could failed any attempt to access */
916 .section __ex_table,"a";
917 	.word	load1,ex_unaligned_fixup;
918 	.word	load2,ex_unaligned_fixup;
919 	.word	load3,ex_unaligned_fixup;
920 	.word	load4,ex_unaligned_fixup;
921 	.word	load5,ex_unaligned_fixup;
922 	.word	store1,ex_unaligned_fixup;
923 	.word	store2,ex_unaligned_fixup;
924 	.word	store3,ex_unaligned_fixup;
925 	.word	store4,ex_unaligned_fixup;
926 	.word	store5,ex_unaligned_fixup;
927 	.word	store6,ex_unaligned_fixup;
928 .previous;
929 .end _unaligned_data_exception
930 
931 .global ex_handler_unhandled
932 ex_handler_unhandled:
933 /* FIXME add handle function for unhandled exception - dump register */
934 	bri 0
935 
936 /*
937  * hw_exception_handler Jump Table
938  * - Contains code snippets for each register that caused the unalign exception
939  * - Hence exception handler is NOT self-modifying
940  * - Separate table for load exceptions and store exceptions.
941  * - Each table is of size: (8 * 32) = 256 bytes
942  */
943 
944 .section .text
945 .align 4
946 lw_table:
947 lw_r0:		R3_TO_LWREG	(0);
948 lw_r1:		LWREG_NOP;
949 lw_r2:		R3_TO_LWREG	(2);
950 lw_r3:		R3_TO_LWREG_V	(3);
951 lw_r4:		R3_TO_LWREG_V	(4);
952 lw_r5:		R3_TO_LWREG_V	(5);
953 lw_r6:		R3_TO_LWREG_V	(6);
954 lw_r7:		R3_TO_LWREG	(7);
955 lw_r8:		R3_TO_LWREG	(8);
956 lw_r9:		R3_TO_LWREG	(9);
957 lw_r10:		R3_TO_LWREG	(10);
958 lw_r11:		R3_TO_LWREG	(11);
959 lw_r12:		R3_TO_LWREG	(12);
960 lw_r13:		R3_TO_LWREG	(13);
961 lw_r14:		R3_TO_LWREG	(14);
962 lw_r15:		R3_TO_LWREG	(15);
963 lw_r16:		R3_TO_LWREG	(16);
964 lw_r17:		LWREG_NOP;
965 lw_r18:		R3_TO_LWREG	(18);
966 lw_r19:		R3_TO_LWREG	(19);
967 lw_r20:		R3_TO_LWREG	(20);
968 lw_r21:		R3_TO_LWREG	(21);
969 lw_r22:		R3_TO_LWREG	(22);
970 lw_r23:		R3_TO_LWREG	(23);
971 lw_r24:		R3_TO_LWREG	(24);
972 lw_r25:		R3_TO_LWREG	(25);
973 lw_r26:		R3_TO_LWREG	(26);
974 lw_r27:		R3_TO_LWREG	(27);
975 lw_r28:		R3_TO_LWREG	(28);
976 lw_r29:		R3_TO_LWREG	(29);
977 lw_r30:		R3_TO_LWREG	(30);
978 lw_r31: 	R3_TO_LWREG_V	(31);
979 
980 sw_table:
981 sw_r0:		SWREG_TO_R3	(0);
982 sw_r1:		SWREG_NOP;
983 sw_r2:		SWREG_TO_R3	(2);
984 sw_r3:		SWREG_TO_R3_V	(3);
985 sw_r4:		SWREG_TO_R3_V	(4);
986 sw_r5:		SWREG_TO_R3_V	(5);
987 sw_r6:		SWREG_TO_R3_V	(6);
988 sw_r7:		SWREG_TO_R3	(7);
989 sw_r8:		SWREG_TO_R3	(8);
990 sw_r9:		SWREG_TO_R3	(9);
991 sw_r10:		SWREG_TO_R3	(10);
992 sw_r11:		SWREG_TO_R3	(11);
993 sw_r12:		SWREG_TO_R3	(12);
994 sw_r13:		SWREG_TO_R3	(13);
995 sw_r14:		SWREG_TO_R3	(14);
996 sw_r15:		SWREG_TO_R3	(15);
997 sw_r16:		SWREG_TO_R3	(16);
998 sw_r17:		SWREG_NOP;
999 sw_r18:		SWREG_TO_R3	(18);
1000 sw_r19:		SWREG_TO_R3	(19);
1001 sw_r20:		SWREG_TO_R3	(20);
1002 sw_r21:		SWREG_TO_R3	(21);
1003 sw_r22:		SWREG_TO_R3	(22);
1004 sw_r23:		SWREG_TO_R3	(23);
1005 sw_r24:		SWREG_TO_R3	(24);
1006 sw_r25:		SWREG_TO_R3	(25);
1007 sw_r26:		SWREG_TO_R3	(26);
1008 sw_r27:		SWREG_TO_R3	(27);
1009 sw_r28:		SWREG_TO_R3	(28);
1010 sw_r29:		SWREG_TO_R3	(29);
1011 sw_r30:		SWREG_TO_R3	(30);
1012 sw_r31:		SWREG_TO_R3_V	(31);
1013 
1014 lw_table_vm:
1015 lw_r0_vm:	R3_TO_LWREG_VM		(0);
1016 lw_r1_vm:	R3_TO_LWREG_VM_V	(1);
1017 lw_r2_vm:	R3_TO_LWREG_VM_V	(2);
1018 lw_r3_vm:	R3_TO_LWREG_VM_V	(3);
1019 lw_r4_vm:	R3_TO_LWREG_VM_V	(4);
1020 lw_r5_vm:	R3_TO_LWREG_VM_V	(5);
1021 lw_r6_vm:	R3_TO_LWREG_VM_V	(6);
1022 lw_r7_vm:	R3_TO_LWREG_VM_V	(7);
1023 lw_r8_vm:	R3_TO_LWREG_VM_V	(8);
1024 lw_r9_vm:	R3_TO_LWREG_VM_V	(9);
1025 lw_r10_vm:	R3_TO_LWREG_VM_V	(10);
1026 lw_r11_vm:	R3_TO_LWREG_VM_V	(11);
1027 lw_r12_vm:	R3_TO_LWREG_VM_V	(12);
1028 lw_r13_vm:	R3_TO_LWREG_VM_V	(13);
1029 lw_r14_vm:	R3_TO_LWREG_VM_V	(14);
1030 lw_r15_vm:	R3_TO_LWREG_VM_V	(15);
1031 lw_r16_vm:	R3_TO_LWREG_VM_V	(16);
1032 lw_r17_vm:	R3_TO_LWREG_VM_V	(17);
1033 lw_r18_vm:	R3_TO_LWREG_VM_V	(18);
1034 lw_r19_vm:	R3_TO_LWREG_VM_V	(19);
1035 lw_r20_vm:	R3_TO_LWREG_VM_V	(20);
1036 lw_r21_vm:	R3_TO_LWREG_VM_V	(21);
1037 lw_r22_vm:	R3_TO_LWREG_VM_V	(22);
1038 lw_r23_vm:	R3_TO_LWREG_VM_V	(23);
1039 lw_r24_vm:	R3_TO_LWREG_VM_V	(24);
1040 lw_r25_vm:	R3_TO_LWREG_VM_V	(25);
1041 lw_r26_vm:	R3_TO_LWREG_VM_V	(26);
1042 lw_r27_vm:	R3_TO_LWREG_VM_V	(27);
1043 lw_r28_vm:	R3_TO_LWREG_VM_V	(28);
1044 lw_r29_vm:	R3_TO_LWREG_VM_V	(29);
1045 lw_r30_vm:	R3_TO_LWREG_VM_V	(30);
1046 lw_r31_vm:	R3_TO_LWREG_VM_V	(31);
1047 
1048 sw_table_vm:
1049 sw_r0_vm:	SWREG_TO_R3_VM		(0);
1050 sw_r1_vm:	SWREG_TO_R3_VM_V	(1);
1051 sw_r2_vm:	SWREG_TO_R3_VM_V	(2);
1052 sw_r3_vm:	SWREG_TO_R3_VM_V	(3);
1053 sw_r4_vm:	SWREG_TO_R3_VM_V	(4);
1054 sw_r5_vm:	SWREG_TO_R3_VM_V	(5);
1055 sw_r6_vm:	SWREG_TO_R3_VM_V	(6);
1056 sw_r7_vm:	SWREG_TO_R3_VM_V	(7);
1057 sw_r8_vm:	SWREG_TO_R3_VM_V	(8);
1058 sw_r9_vm:	SWREG_TO_R3_VM_V	(9);
1059 sw_r10_vm:	SWREG_TO_R3_VM_V	(10);
1060 sw_r11_vm:	SWREG_TO_R3_VM_V	(11);
1061 sw_r12_vm:	SWREG_TO_R3_VM_V	(12);
1062 sw_r13_vm:	SWREG_TO_R3_VM_V	(13);
1063 sw_r14_vm:	SWREG_TO_R3_VM_V	(14);
1064 sw_r15_vm:	SWREG_TO_R3_VM_V	(15);
1065 sw_r16_vm:	SWREG_TO_R3_VM_V	(16);
1066 sw_r17_vm:	SWREG_TO_R3_VM_V	(17);
1067 sw_r18_vm:	SWREG_TO_R3_VM_V	(18);
1068 sw_r19_vm:	SWREG_TO_R3_VM_V	(19);
1069 sw_r20_vm:	SWREG_TO_R3_VM_V	(20);
1070 sw_r21_vm:	SWREG_TO_R3_VM_V	(21);
1071 sw_r22_vm:	SWREG_TO_R3_VM_V	(22);
1072 sw_r23_vm:	SWREG_TO_R3_VM_V	(23);
1073 sw_r24_vm:	SWREG_TO_R3_VM_V	(24);
1074 sw_r25_vm:	SWREG_TO_R3_VM_V	(25);
1075 sw_r26_vm:	SWREG_TO_R3_VM_V	(26);
1076 sw_r27_vm:	SWREG_TO_R3_VM_V	(27);
1077 sw_r28_vm:	SWREG_TO_R3_VM_V	(28);
1078 sw_r29_vm:	SWREG_TO_R3_VM_V	(29);
1079 sw_r30_vm:	SWREG_TO_R3_VM_V	(30);
1080 sw_r31_vm:	SWREG_TO_R3_VM_V	(31);
1081 
1082 /* Temporary data structures used in the handler */
1083 .section .data
1084 .align 4
1085 ex_tmp_data_loc_0:
1086 	.byte 0
1087 ex_tmp_data_loc_1:
1088 	.byte 0
1089 ex_tmp_data_loc_2:
1090 	.byte 0
1091 ex_tmp_data_loc_3:
1092 	.byte 0
1093 ex_reg_op:
1094 	.byte 0
1095