• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * OpenRISC head.S
3 *
4 * Linux architectural port borrowing liberally from similar works of
5 * others.  All original copyrights apply as per the original source
6 * declaration.
7 *
8 * Modifications for the OpenRISC architecture:
9 * Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
10 * Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
11 *
12 *      This program is free software; you can redistribute it and/or
13 *      modify it under the terms of the GNU General Public License
14 *      as published by the Free Software Foundation; either version
15 *      2 of the License, or (at your option) any later version.
16 */
17
18#include <linux/linkage.h>
19#include <linux/threads.h>
20#include <linux/errno.h>
21#include <linux/init.h>
22#include <linux/serial_reg.h>
23#include <asm/processor.h>
24#include <asm/page.h>
25#include <asm/mmu.h>
26#include <asm/pgtable.h>
27#include <asm/thread_info.h>
28#include <asm/cache.h>
29#include <asm/spr_defs.h>
30#include <asm/asm-offsets.h>
31#include <linux/of_fdt.h>
32
33#define tophys(rd,rs)				\
34	l.movhi	rd,hi(-KERNELBASE)		;\
35	l.add	rd,rd,rs
36
37#define CLEAR_GPR(gpr)				\
38	l.movhi	gpr,0x0
39
40#define LOAD_SYMBOL_2_GPR(gpr,symbol)		\
41	l.movhi gpr,hi(symbol)			;\
42	l.ori   gpr,gpr,lo(symbol)
43
44
45#define UART_BASE_ADD      0x90000000
46
47#define EXCEPTION_SR  (SPR_SR_DME | SPR_SR_IME | SPR_SR_DCE | SPR_SR_ICE | SPR_SR_SM)
48#define SYSCALL_SR  (SPR_SR_DME | SPR_SR_IME | SPR_SR_DCE | SPR_SR_ICE | SPR_SR_IEE | SPR_SR_TEE | SPR_SR_SM)
49
50/* ============================================[ tmp store locations ]=== */
51
52/*
53 * emergency_print temporary stores
54 */
55#define EMERGENCY_PRINT_STORE_GPR4	l.sw    0x20(r0),r4
56#define EMERGENCY_PRINT_LOAD_GPR4	l.lwz   r4,0x20(r0)
57
58#define EMERGENCY_PRINT_STORE_GPR5	l.sw    0x24(r0),r5
59#define EMERGENCY_PRINT_LOAD_GPR5	l.lwz   r5,0x24(r0)
60
61#define EMERGENCY_PRINT_STORE_GPR6	l.sw    0x28(r0),r6
62#define EMERGENCY_PRINT_LOAD_GPR6	l.lwz   r6,0x28(r0)
63
64#define EMERGENCY_PRINT_STORE_GPR7	l.sw    0x2c(r0),r7
65#define EMERGENCY_PRINT_LOAD_GPR7	l.lwz   r7,0x2c(r0)
66
67#define EMERGENCY_PRINT_STORE_GPR8	l.sw    0x30(r0),r8
68#define EMERGENCY_PRINT_LOAD_GPR8	l.lwz   r8,0x30(r0)
69
70#define EMERGENCY_PRINT_STORE_GPR9	l.sw    0x34(r0),r9
71#define EMERGENCY_PRINT_LOAD_GPR9	l.lwz   r9,0x34(r0)
72
73
74/*
75 * TLB miss handlers temorary stores
76 */
77#define EXCEPTION_STORE_GPR9		l.sw    0x10(r0),r9
78#define EXCEPTION_LOAD_GPR9		l.lwz   r9,0x10(r0)
79
80#define EXCEPTION_STORE_GPR2		l.sw    0x64(r0),r2
81#define EXCEPTION_LOAD_GPR2		l.lwz   r2,0x64(r0)
82
83#define EXCEPTION_STORE_GPR3		l.sw    0x68(r0),r3
84#define EXCEPTION_LOAD_GPR3		l.lwz   r3,0x68(r0)
85
86#define EXCEPTION_STORE_GPR4		l.sw    0x6c(r0),r4
87#define EXCEPTION_LOAD_GPR4		l.lwz   r4,0x6c(r0)
88
89#define EXCEPTION_STORE_GPR5		l.sw    0x70(r0),r5
90#define EXCEPTION_LOAD_GPR5		l.lwz   r5,0x70(r0)
91
92#define EXCEPTION_STORE_GPR6		l.sw    0x74(r0),r6
93#define EXCEPTION_LOAD_GPR6		l.lwz   r6,0x74(r0)
94
95
96/*
97 * EXCEPTION_HANDLE temporary stores
98 */
99
100#define EXCEPTION_T_STORE_GPR30		l.sw    0x78(r0),r30
101#define EXCEPTION_T_LOAD_GPR30(reg)	l.lwz   reg,0x78(r0)
102
103#define EXCEPTION_T_STORE_GPR10		l.sw    0x7c(r0),r10
104#define EXCEPTION_T_LOAD_GPR10(reg)	l.lwz   reg,0x7c(r0)
105
106#define EXCEPTION_T_STORE_SP		l.sw	0x80(r0),r1
107#define EXCEPTION_T_LOAD_SP(reg)	l.lwz   reg,0x80(r0)
108
109/*
110 * For UNHANLDED_EXCEPTION
111 */
112
113#define EXCEPTION_T_STORE_GPR31		l.sw    0x84(r0),r31
114#define EXCEPTION_T_LOAD_GPR31(reg)	l.lwz   reg,0x84(r0)
115
116/* =========================================================[ macros ]=== */
117
118
119#define GET_CURRENT_PGD(reg,t1)					\
120	LOAD_SYMBOL_2_GPR(reg,current_pgd)			;\
121	tophys  (t1,reg)					;\
122	l.lwz   reg,0(t1)
123
124
125/*
126 * DSCR: this is a common hook for handling exceptions. it will save
127 *       the needed registers, set up stack and pointer to current
128 *	 then jump to the handler while enabling MMU
129 *
130 * PRMS: handler	- a function to jump to. it has to save the
131 *			remaining registers to kernel stack, call
132 *			appropriate arch-independant exception handler
133 *			and finaly jump to ret_from_except
134 *
135 * PREQ: unchanged state from the time exception happened
136 *
137 * POST: SAVED the following registers original value
138 *	       to the new created exception frame pointed to by r1
139 *
140 *	 r1  - ksp	pointing to the new (exception) frame
141 *	 r4  - EEAR     exception EA
142 *	 r10 - current	pointing to current_thread_info struct
143 *	 r12 - syscall  0, since we didn't come from syscall
144 *	 r30 - handler	address of the handler we'll jump to
145 *
146 *	 handler has to save remaining registers to the exception
147 *	 ksp frame *before* tainting them!
148 *
149 * NOTE: this function is not reentrant per se. reentrancy is guaranteed
150 *       by processor disabling all exceptions/interrupts when exception
151 *	 accours.
152 *
153 * OPTM: no need to make it so wasteful to extract ksp when in user mode
154 */
155
156#define EXCEPTION_HANDLE(handler)				\
157	EXCEPTION_T_STORE_GPR30					;\
158	l.mfspr r30,r0,SPR_ESR_BASE				;\
159	l.andi  r30,r30,SPR_SR_SM				;\
160	l.sfeqi r30,0						;\
161	EXCEPTION_T_STORE_GPR10					;\
162	l.bnf   2f                            /* kernel_mode */	;\
163	 EXCEPTION_T_STORE_SP                 /* delay slot */	;\
1641: /* user_mode:   */						;\
165	LOAD_SYMBOL_2_GPR(r1,current_thread_info_set)		;\
166	tophys  (r30,r1)					;\
167	/* r10: current_thread_info  */				;\
168	l.lwz   r10,0(r30)					;\
169	tophys  (r30,r10)					;\
170	l.lwz   r1,(TI_KSP)(r30)				;\
171	/* fall through */					;\
1722: /* kernel_mode: */						;\
173	/* create new stack frame, save only needed gprs */	;\
174	/* r1: KSP, r10: current, r4: EEAR, r31: __pa(KSP) */	;\
175	/* r12:	temp, syscall indicator */			;\
176	l.addi  r1,r1,-(INT_FRAME_SIZE)				;\
177	/* r1 is KSP, r30 is __pa(KSP) */			;\
178	tophys  (r30,r1)					;\
179	l.sw    PT_GPR12(r30),r12				;\
180	/* r4 use for tmp before EA */				;\
181	l.mfspr r12,r0,SPR_EPCR_BASE				;\
182	l.sw    PT_PC(r30),r12					;\
183	l.mfspr r12,r0,SPR_ESR_BASE				;\
184	l.sw    PT_SR(r30),r12					;\
185	/* save r30 */						;\
186	EXCEPTION_T_LOAD_GPR30(r12)				;\
187	l.sw	PT_GPR30(r30),r12				;\
188	/* save r10 as was prior to exception */		;\
189	EXCEPTION_T_LOAD_GPR10(r12)				;\
190	l.sw	PT_GPR10(r30),r12				;\
191	/* save PT_SP as was prior to exception */		;\
192	EXCEPTION_T_LOAD_SP(r12)				;\
193	l.sw	PT_SP(r30),r12					;\
194	/* save exception r4, set r4 = EA */			;\
195	l.sw	PT_GPR4(r30),r4					;\
196	l.mfspr r4,r0,SPR_EEAR_BASE				;\
197	/* r12 == 1 if we come from syscall */			;\
198	CLEAR_GPR(r12)						;\
199	/* ----- turn on MMU ----- */				;\
200	/* Carry DSX into exception SR */			;\
201	l.mfspr r30,r0,SPR_SR					;\
202	l.andi	r30,r30,SPR_SR_DSX				;\
203	l.ori	r30,r30,(EXCEPTION_SR)				;\
204	l.mtspr	r0,r30,SPR_ESR_BASE				;\
205	/* r30:	EA address of handler */			;\
206	LOAD_SYMBOL_2_GPR(r30,handler)				;\
207	l.mtspr r0,r30,SPR_EPCR_BASE				;\
208	l.rfe
209
210/*
211 * this doesn't work
212 *
213 *
214 * #ifdef CONFIG_JUMP_UPON_UNHANDLED_EXCEPTION
215 * #define UNHANDLED_EXCEPTION(handler)				\
216 *	l.ori   r3,r0,0x1					;\
217 *	l.mtspr r0,r3,SPR_SR					;\
218 *      l.movhi r3,hi(0xf0000100)				;\
219 *      l.ori   r3,r3,lo(0xf0000100)				;\
220 *	l.jr	r3						;\
221 *	l.nop	1
222 *
223 * #endif
224 */
225
226/* DSCR: this is the same as EXCEPTION_HANDLE(), we are just
227 *       a bit more carefull (if we have a PT_SP or current pointer
228 *       corruption) and set them up from 'current_set'
229 *
230 */
231#define UNHANDLED_EXCEPTION(handler)				\
232	EXCEPTION_T_STORE_GPR31					;\
233	EXCEPTION_T_STORE_GPR10					;\
234	EXCEPTION_T_STORE_SP					;\
235	/* temporary store r3, r9 into r1, r10 */		;\
236	l.addi	r1,r3,0x0					;\
237	l.addi	r10,r9,0x0					;\
238	/* the string referenced by r3 must be low enough */	;\
239	l.jal	_emergency_print				;\
240	l.ori	r3,r0,lo(_string_unhandled_exception)		;\
241	l.mfspr	r3,r0,SPR_NPC					;\
242	l.jal	_emergency_print_nr				;\
243	l.andi	r3,r3,0x1f00					;\
244	/* the string referenced by r3 must be low enough */	;\
245	l.jal	_emergency_print				;\
246	l.ori	r3,r0,lo(_string_epc_prefix)			;\
247	l.jal	_emergency_print_nr				;\
248	l.mfspr	r3,r0,SPR_EPCR_BASE				;\
249	l.jal	_emergency_print				;\
250	l.ori	r3,r0,lo(_string_nl)				;\
251	/* end of printing */					;\
252	l.addi	r3,r1,0x0					;\
253	l.addi	r9,r10,0x0					;\
254	/* extract current, ksp from current_set */		;\
255	LOAD_SYMBOL_2_GPR(r1,_unhandled_stack_top)		;\
256	LOAD_SYMBOL_2_GPR(r10,init_thread_union)		;\
257	/* create new stack frame, save only needed gprs */	;\
258	/* r1: KSP, r10: current, r31: __pa(KSP) */		;\
259	/* r12:	temp, syscall indicator, r13 temp */		;\
260	l.addi  r1,r1,-(INT_FRAME_SIZE)				;\
261	/* r1 is KSP, r31 is __pa(KSP) */			;\
262	tophys  (r31,r1)					;\
263	l.sw    PT_GPR12(r31),r12					;\
264	l.mfspr r12,r0,SPR_EPCR_BASE				;\
265	l.sw    PT_PC(r31),r12					;\
266	l.mfspr r12,r0,SPR_ESR_BASE				;\
267	l.sw    PT_SR(r31),r12					;\
268	/* save r31 */						;\
269	EXCEPTION_T_LOAD_GPR31(r12)				;\
270	l.sw	PT_GPR31(r31),r12					;\
271	/* save r10 as was prior to exception */		;\
272	EXCEPTION_T_LOAD_GPR10(r12)				;\
273	l.sw	PT_GPR10(r31),r12					;\
274	/* save PT_SP as was prior to exception */			;\
275	EXCEPTION_T_LOAD_SP(r12)				;\
276	l.sw	PT_SP(r31),r12					;\
277	l.sw    PT_GPR13(r31),r13					;\
278	/* --> */						;\
279	/* save exception r4, set r4 = EA */			;\
280	l.sw	PT_GPR4(r31),r4					;\
281	l.mfspr r4,r0,SPR_EEAR_BASE				;\
282	/* r12 == 1 if we come from syscall */			;\
283	CLEAR_GPR(r12)						;\
284	/* ----- play a MMU trick ----- */			;\
285	l.ori	r31,r0,(EXCEPTION_SR)				;\
286	l.mtspr	r0,r31,SPR_ESR_BASE				;\
287	/* r31:	EA address of handler */			;\
288	LOAD_SYMBOL_2_GPR(r31,handler)				;\
289	l.mtspr r0,r31,SPR_EPCR_BASE				;\
290	l.rfe
291
292/* =====================================================[ exceptions] === */
293
294/* ---[ 0x100: RESET exception ]----------------------------------------- */
295    .org 0x100
296	/* Jump to .init code at _start which lives in the .head section
297	 * and will be discarded after boot.
298	 */
299	LOAD_SYMBOL_2_GPR(r15, _start)
300	tophys	(r13,r15)			/* MMU disabled */
301	l.jr	r13
302	 l.nop
303
304/* ---[ 0x200: BUS exception ]------------------------------------------- */
305    .org 0x200
306_dispatch_bus_fault:
307	EXCEPTION_HANDLE(_bus_fault_handler)
308
309/* ---[ 0x300: Data Page Fault exception ]------------------------------- */
310    .org 0x300
311_dispatch_do_dpage_fault:
312//      totaly disable timer interrupt
313// 	l.mtspr	r0,r0,SPR_TTMR
314//	DEBUG_TLB_PROBE(0x300)
315//	EXCEPTION_DEBUG_VALUE_ER_ENABLED(0x300)
316	EXCEPTION_HANDLE(_data_page_fault_handler)
317
318/* ---[ 0x400: Insn Page Fault exception ]------------------------------- */
319    .org 0x400
320_dispatch_do_ipage_fault:
321//      totaly disable timer interrupt
322//	l.mtspr	r0,r0,SPR_TTMR
323//	DEBUG_TLB_PROBE(0x400)
324//	EXCEPTION_DEBUG_VALUE_ER_ENABLED(0x400)
325	EXCEPTION_HANDLE(_insn_page_fault_handler)
326
327/* ---[ 0x500: Timer exception ]----------------------------------------- */
328    .org 0x500
329	EXCEPTION_HANDLE(_timer_handler)
330
331/* ---[ 0x600: Alignment exception ]-------------------------------------- */
332    .org 0x600
333	EXCEPTION_HANDLE(_alignment_handler)
334
335/* ---[ 0x700: Illegal insn exception ]---------------------------------- */
336    .org 0x700
337	EXCEPTION_HANDLE(_illegal_instruction_handler)
338
339/* ---[ 0x800: External interrupt exception ]---------------------------- */
340    .org 0x800
341	EXCEPTION_HANDLE(_external_irq_handler)
342
343/* ---[ 0x900: DTLB miss exception ]------------------------------------- */
344    .org 0x900
345	l.j	boot_dtlb_miss_handler
346	l.nop
347
348/* ---[ 0xa00: ITLB miss exception ]------------------------------------- */
349    .org 0xa00
350	l.j	boot_itlb_miss_handler
351	l.nop
352
353/* ---[ 0xb00: Range exception ]----------------------------------------- */
354    .org 0xb00
355	UNHANDLED_EXCEPTION(_vector_0xb00)
356
357/* ---[ 0xc00: Syscall exception ]--------------------------------------- */
358    .org 0xc00
359	EXCEPTION_HANDLE(_sys_call_handler)
360
361/* ---[ 0xd00: Trap exception ]------------------------------------------ */
362    .org 0xd00
363	UNHANDLED_EXCEPTION(_vector_0xd00)
364
365/* ---[ 0xe00: Trap exception ]------------------------------------------ */
366    .org 0xe00
367//	UNHANDLED_EXCEPTION(_vector_0xe00)
368	EXCEPTION_HANDLE(_trap_handler)
369
370/* ---[ 0xf00: Reserved exception ]-------------------------------------- */
371    .org 0xf00
372	UNHANDLED_EXCEPTION(_vector_0xf00)
373
374/* ---[ 0x1000: Reserved exception ]------------------------------------- */
375    .org 0x1000
376	UNHANDLED_EXCEPTION(_vector_0x1000)
377
378/* ---[ 0x1100: Reserved exception ]------------------------------------- */
379    .org 0x1100
380	UNHANDLED_EXCEPTION(_vector_0x1100)
381
382/* ---[ 0x1200: Reserved exception ]------------------------------------- */
383    .org 0x1200
384	UNHANDLED_EXCEPTION(_vector_0x1200)
385
386/* ---[ 0x1300: Reserved exception ]------------------------------------- */
387    .org 0x1300
388	UNHANDLED_EXCEPTION(_vector_0x1300)
389
390/* ---[ 0x1400: Reserved exception ]------------------------------------- */
391    .org 0x1400
392	UNHANDLED_EXCEPTION(_vector_0x1400)
393
394/* ---[ 0x1500: Reserved exception ]------------------------------------- */
395    .org 0x1500
396	UNHANDLED_EXCEPTION(_vector_0x1500)
397
398/* ---[ 0x1600: Reserved exception ]------------------------------------- */
399    .org 0x1600
400	UNHANDLED_EXCEPTION(_vector_0x1600)
401
402/* ---[ 0x1700: Reserved exception ]------------------------------------- */
403    .org 0x1700
404	UNHANDLED_EXCEPTION(_vector_0x1700)
405
406/* ---[ 0x1800: Reserved exception ]------------------------------------- */
407    .org 0x1800
408	UNHANDLED_EXCEPTION(_vector_0x1800)
409
410/* ---[ 0x1900: Reserved exception ]------------------------------------- */
411    .org 0x1900
412	UNHANDLED_EXCEPTION(_vector_0x1900)
413
414/* ---[ 0x1a00: Reserved exception ]------------------------------------- */
415    .org 0x1a00
416	UNHANDLED_EXCEPTION(_vector_0x1a00)
417
418/* ---[ 0x1b00: Reserved exception ]------------------------------------- */
419    .org 0x1b00
420	UNHANDLED_EXCEPTION(_vector_0x1b00)
421
422/* ---[ 0x1c00: Reserved exception ]------------------------------------- */
423    .org 0x1c00
424	UNHANDLED_EXCEPTION(_vector_0x1c00)
425
426/* ---[ 0x1d00: Reserved exception ]------------------------------------- */
427    .org 0x1d00
428	UNHANDLED_EXCEPTION(_vector_0x1d00)
429
430/* ---[ 0x1e00: Reserved exception ]------------------------------------- */
431    .org 0x1e00
432	UNHANDLED_EXCEPTION(_vector_0x1e00)
433
434/* ---[ 0x1f00: Reserved exception ]------------------------------------- */
435    .org 0x1f00
436	UNHANDLED_EXCEPTION(_vector_0x1f00)
437
438    .org 0x2000
439/* ===================================================[ kernel start ]=== */
440
441/*    .text*/
442
443/* This early stuff belongs in HEAD, but some of the functions below definitely
444 * don't... */
445
446	__HEAD
447	.global _start
448_start:
449	/* Init r0 to zero as per spec */
450	CLEAR_GPR(r0)
451
452	/* save kernel parameters */
453	l.or	r25,r0,r3	/* pointer to fdt */
454
455	/*
456	 * ensure a deterministic start
457	 */
458
459	l.ori	r3,r0,0x1
460	l.mtspr	r0,r3,SPR_SR
461
462	CLEAR_GPR(r1)
463	CLEAR_GPR(r2)
464	CLEAR_GPR(r3)
465	CLEAR_GPR(r4)
466	CLEAR_GPR(r5)
467	CLEAR_GPR(r6)
468	CLEAR_GPR(r7)
469	CLEAR_GPR(r8)
470	CLEAR_GPR(r9)
471	CLEAR_GPR(r10)
472	CLEAR_GPR(r11)
473	CLEAR_GPR(r12)
474	CLEAR_GPR(r13)
475	CLEAR_GPR(r14)
476	CLEAR_GPR(r15)
477	CLEAR_GPR(r16)
478	CLEAR_GPR(r17)
479	CLEAR_GPR(r18)
480	CLEAR_GPR(r19)
481	CLEAR_GPR(r20)
482	CLEAR_GPR(r21)
483	CLEAR_GPR(r22)
484	CLEAR_GPR(r23)
485	CLEAR_GPR(r24)
486	CLEAR_GPR(r26)
487	CLEAR_GPR(r27)
488	CLEAR_GPR(r28)
489	CLEAR_GPR(r29)
490	CLEAR_GPR(r30)
491	CLEAR_GPR(r31)
492
493	/*
494	 * set up initial ksp and current
495	 */
496	/* setup kernel stack */
497	LOAD_SYMBOL_2_GPR(r1,init_thread_union + THREAD_SIZE)
498	LOAD_SYMBOL_2_GPR(r10,init_thread_union)	// setup current
499	tophys	(r31,r10)
500	l.sw	TI_KSP(r31), r1
501
502	l.ori	r4,r0,0x0
503
504
505	/*
506	 * .data contains initialized data,
507	 * .bss contains uninitialized data - clear it up
508	 */
509clear_bss:
510	LOAD_SYMBOL_2_GPR(r24, __bss_start)
511	LOAD_SYMBOL_2_GPR(r26, _end)
512	tophys(r28,r24)
513	tophys(r30,r26)
514	CLEAR_GPR(r24)
515	CLEAR_GPR(r26)
5161:
517	l.sw    (0)(r28),r0
518	l.sfltu r28,r30
519	l.bf    1b
520	l.addi  r28,r28,4
521
522enable_ic:
523	l.jal	_ic_enable
524	 l.nop
525
526enable_dc:
527	l.jal	_dc_enable
528	 l.nop
529
530flush_tlb:
531	l.jal	_flush_tlb
532	 l.nop
533
534/* The MMU needs to be enabled before or32_early_setup is called */
535
536enable_mmu:
537	/*
538	 * enable dmmu & immu
539	 * SR[5] = 0, SR[6] = 0, 6th and 7th bit of SR set to 0
540	 */
541	l.mfspr	r30,r0,SPR_SR
542	l.movhi	r28,hi(SPR_SR_DME | SPR_SR_IME)
543	l.ori	r28,r28,lo(SPR_SR_DME | SPR_SR_IME)
544	l.or	r30,r30,r28
545	l.mtspr	r0,r30,SPR_SR
546	l.nop
547	l.nop
548	l.nop
549	l.nop
550	l.nop
551	l.nop
552	l.nop
553	l.nop
554	l.nop
555	l.nop
556	l.nop
557	l.nop
558	l.nop
559	l.nop
560	l.nop
561	l.nop
562
563	// reset the simulation counters
564	l.nop 5
565
566	/* check fdt header magic word */
567	l.lwz	r3,0(r25)	/* load magic from fdt into r3 */
568	l.movhi	r4,hi(OF_DT_HEADER)
569	l.ori	r4,r4,lo(OF_DT_HEADER)
570	l.sfeq	r3,r4
571	l.bf	_fdt_found
572	 l.nop
573	/* magic number mismatch, set fdt pointer to null */
574	l.or	r25,r0,r0
575_fdt_found:
576	/* pass fdt pointer to or32_early_setup in r3 */
577	l.or	r3,r0,r25
578	LOAD_SYMBOL_2_GPR(r24, or32_early_setup)
579	l.jalr r24
580	 l.nop
581
582clear_regs:
583	/*
584	 * clear all GPRS to increase determinism
585	 */
586	CLEAR_GPR(r2)
587	CLEAR_GPR(r3)
588	CLEAR_GPR(r4)
589	CLEAR_GPR(r5)
590	CLEAR_GPR(r6)
591	CLEAR_GPR(r7)
592	CLEAR_GPR(r8)
593	CLEAR_GPR(r9)
594	CLEAR_GPR(r11)
595	CLEAR_GPR(r12)
596	CLEAR_GPR(r13)
597	CLEAR_GPR(r14)
598	CLEAR_GPR(r15)
599	CLEAR_GPR(r16)
600	CLEAR_GPR(r17)
601	CLEAR_GPR(r18)
602	CLEAR_GPR(r19)
603	CLEAR_GPR(r20)
604	CLEAR_GPR(r21)
605	CLEAR_GPR(r22)
606	CLEAR_GPR(r23)
607	CLEAR_GPR(r24)
608	CLEAR_GPR(r25)
609	CLEAR_GPR(r26)
610	CLEAR_GPR(r27)
611	CLEAR_GPR(r28)
612	CLEAR_GPR(r29)
613	CLEAR_GPR(r30)
614	CLEAR_GPR(r31)
615
616jump_start_kernel:
617	/*
618	 * jump to kernel entry (start_kernel)
619	 */
620	LOAD_SYMBOL_2_GPR(r30, start_kernel)
621	l.jr    r30
622	 l.nop
623
624_flush_tlb:
625	/*
626	 *  I N V A L I D A T E   T L B   e n t r i e s
627	 */
628	LOAD_SYMBOL_2_GPR(r5,SPR_DTLBMR_BASE(0))
629	LOAD_SYMBOL_2_GPR(r6,SPR_ITLBMR_BASE(0))
630	l.addi	r7,r0,128 /* Maximum number of sets */
6311:
632	l.mtspr	r5,r0,0x0
633	l.mtspr	r6,r0,0x0
634
635	l.addi	r5,r5,1
636	l.addi	r6,r6,1
637	l.sfeq	r7,r0
638	l.bnf	1b
639	 l.addi	r7,r7,-1
640
641	l.jr	r9
642	 l.nop
643
644/* ========================================[ cache ]=== */
645
646	/* alignment here so we don't change memory offsets with
647	 * memory controller defined
648	 */
649	.align 0x2000
650
651_ic_enable:
652	/* Check if IC present and skip enabling otherwise */
653	l.mfspr r24,r0,SPR_UPR
654	l.andi  r26,r24,SPR_UPR_ICP
655	l.sfeq  r26,r0
656	l.bf	9f
657	l.nop
658
659	/* Disable IC */
660	l.mfspr r6,r0,SPR_SR
661	l.addi  r5,r0,-1
662	l.xori  r5,r5,SPR_SR_ICE
663	l.and   r5,r6,r5
664	l.mtspr r0,r5,SPR_SR
665
666	/* Establish cache block size
667	   If BS=0, 16;
668	   If BS=1, 32;
669	   r14 contain block size
670	*/
671	l.mfspr r24,r0,SPR_ICCFGR
672	l.andi	r26,r24,SPR_ICCFGR_CBS
673	l.srli	r28,r26,7
674	l.ori	r30,r0,16
675	l.sll	r14,r30,r28
676
677	/* Establish number of cache sets
678	   r16 contains number of cache sets
679	   r28 contains log(# of cache sets)
680	*/
681	l.andi  r26,r24,SPR_ICCFGR_NCS
682	l.srli 	r28,r26,3
683	l.ori   r30,r0,1
684	l.sll   r16,r30,r28
685
686	/* Invalidate IC */
687	l.addi  r6,r0,0
688	l.sll   r5,r14,r28
689//        l.mul   r5,r14,r16
690//	l.trap  1
691//	l.addi  r5,r0,IC_SIZE
6921:
693	l.mtspr r0,r6,SPR_ICBIR
694	l.sfne  r6,r5
695	l.bf    1b
696	l.add   r6,r6,r14
697 //       l.addi   r6,r6,IC_LINE
698
699	/* Enable IC */
700	l.mfspr r6,r0,SPR_SR
701	l.ori   r6,r6,SPR_SR_ICE
702	l.mtspr r0,r6,SPR_SR
703	l.nop
704	l.nop
705	l.nop
706	l.nop
707	l.nop
708	l.nop
709	l.nop
710	l.nop
711	l.nop
712	l.nop
7139:
714	l.jr    r9
715	l.nop
716
717_dc_enable:
718	/* Check if DC present and skip enabling otherwise */
719	l.mfspr r24,r0,SPR_UPR
720	l.andi  r26,r24,SPR_UPR_DCP
721	l.sfeq  r26,r0
722	l.bf	9f
723	l.nop
724
725	/* Disable DC */
726	l.mfspr r6,r0,SPR_SR
727	l.addi  r5,r0,-1
728	l.xori  r5,r5,SPR_SR_DCE
729	l.and   r5,r6,r5
730	l.mtspr r0,r5,SPR_SR
731
732	/* Establish cache block size
733	   If BS=0, 16;
734	   If BS=1, 32;
735	   r14 contain block size
736	*/
737	l.mfspr r24,r0,SPR_DCCFGR
738	l.andi	r26,r24,SPR_DCCFGR_CBS
739	l.srli	r28,r26,7
740	l.ori	r30,r0,16
741	l.sll	r14,r30,r28
742
743	/* Establish number of cache sets
744	   r16 contains number of cache sets
745	   r28 contains log(# of cache sets)
746	*/
747	l.andi  r26,r24,SPR_DCCFGR_NCS
748	l.srli 	r28,r26,3
749	l.ori   r30,r0,1
750	l.sll   r16,r30,r28
751
752	/* Invalidate DC */
753	l.addi  r6,r0,0
754	l.sll   r5,r14,r28
7551:
756	l.mtspr r0,r6,SPR_DCBIR
757	l.sfne  r6,r5
758	l.bf    1b
759	l.add   r6,r6,r14
760
761	/* Enable DC */
762	l.mfspr r6,r0,SPR_SR
763	l.ori   r6,r6,SPR_SR_DCE
764	l.mtspr r0,r6,SPR_SR
7659:
766	l.jr    r9
767	l.nop
768
769/* ===============================================[ page table masks ]=== */
770
771#define DTLB_UP_CONVERT_MASK  0x3fa
772#define ITLB_UP_CONVERT_MASK  0x3a
773
774/* for SMP we'd have (this is a bit subtle, CC must be always set
775 * for SMP, but since we have _PAGE_PRESENT bit always defined
776 * we can just modify the mask)
777 */
778#define DTLB_SMP_CONVERT_MASK  0x3fb
779#define ITLB_SMP_CONVERT_MASK  0x3b
780
781/* ---[ boot dtlb miss handler ]----------------------------------------- */
782
783boot_dtlb_miss_handler:
784
785/* mask for DTLB_MR register: - (0) sets V (valid) bit,
786 *                            - (31-12) sets bits belonging to VPN (31-12)
787 */
788#define DTLB_MR_MASK 0xfffff001
789
790/* mask for DTLB_TR register: - (2) sets CI (cache inhibit) bit,
791 *			      - (4) sets A (access) bit,
792 *                            - (5) sets D (dirty) bit,
793 *                            - (8) sets SRE (superuser read) bit
794 *                            - (9) sets SWE (superuser write) bit
795 *                            - (31-12) sets bits belonging to VPN (31-12)
796 */
797#define DTLB_TR_MASK 0xfffff332
798
799/* These are for masking out the VPN/PPN value from the MR/TR registers...
800 * it's not the same as the PFN */
801#define VPN_MASK 0xfffff000
802#define PPN_MASK 0xfffff000
803
804
805	EXCEPTION_STORE_GPR6
806
807#if 0
808	l.mfspr r6,r0,SPR_ESR_BASE	   //
809	l.andi  r6,r6,SPR_SR_SM            // are we in kernel mode ?
810	l.sfeqi r6,0                       // r6 == 0x1 --> SM
811	l.bf    exit_with_no_dtranslation  //
812	l.nop
813#endif
814
815	/* this could be optimized by moving storing of
816	 * non r6 registers here, and jumping r6 restore
817	 * if not in supervisor mode
818	 */
819
820	EXCEPTION_STORE_GPR2
821	EXCEPTION_STORE_GPR3
822	EXCEPTION_STORE_GPR4
823	EXCEPTION_STORE_GPR5
824
825	l.mfspr r4,r0,SPR_EEAR_BASE        // get the offending EA
826
827immediate_translation:
828	CLEAR_GPR(r6)
829
830	l.srli	r3,r4,0xd                  // r3 <- r4 / 8192 (sets are relative to page size (8Kb) NOT VPN size (4Kb)
831
832	l.mfspr r6, r0, SPR_DMMUCFGR
833	l.andi	r6, r6, SPR_DMMUCFGR_NTS
834	l.srli	r6, r6, SPR_DMMUCFGR_NTS_OFF
835	l.ori	r5, r0, 0x1
836	l.sll	r5, r5, r6 	// r5 = number DMMU sets
837	l.addi	r6, r5, -1  	// r6 = nsets mask
838	l.and	r2, r3, r6	// r2 <- r3 % NSETS_MASK
839
840	l.or    r6,r6,r4                   // r6 <- r4
841	l.ori   r6,r6,~(VPN_MASK)          // r6 <- VPN :VPN .xfff - clear up lo(r6) to 0x**** *fff
842	l.movhi r5,hi(DTLB_MR_MASK)        // r5 <- ffff:0000.x000
843	l.ori   r5,r5,lo(DTLB_MR_MASK)     // r5 <- ffff:1111.x001 - apply DTLB_MR_MASK
844	l.and   r5,r5,r6                   // r5 <- VPN :VPN .x001 - we have DTLBMR entry
845	l.mtspr r2,r5,SPR_DTLBMR_BASE(0)   // set DTLBMR
846
847	/* set up DTLB with no translation for EA <= 0xbfffffff */
848	LOAD_SYMBOL_2_GPR(r6,0xbfffffff)
849	l.sfgeu  r6,r4                     // flag if r6 >= r4 (if 0xbfffffff >= EA)
850	l.bf     1f                        // goto out
851	l.and    r3,r4,r4                  // delay slot :: 24 <- r4 (if flag==1)
852
853	tophys(r3,r4)                      // r3 <- PA
8541:
855	l.ori   r3,r3,~(PPN_MASK)          // r3 <- PPN :PPN .xfff - clear up lo(r6) to 0x**** *fff
856	l.movhi r5,hi(DTLB_TR_MASK)        // r5 <- ffff:0000.x000
857	l.ori   r5,r5,lo(DTLB_TR_MASK)     // r5 <- ffff:1111.x330 - apply DTLB_MR_MASK
858	l.and   r5,r5,r3                   // r5 <- PPN :PPN .x330 - we have DTLBTR entry
859	l.mtspr r2,r5,SPR_DTLBTR_BASE(0)   // set DTLBTR
860
861	EXCEPTION_LOAD_GPR6
862	EXCEPTION_LOAD_GPR5
863	EXCEPTION_LOAD_GPR4
864	EXCEPTION_LOAD_GPR3
865	EXCEPTION_LOAD_GPR2
866
867	l.rfe                              // SR <- ESR, PC <- EPC
868
869exit_with_no_dtranslation:
870	/* EA out of memory or not in supervisor mode */
871	EXCEPTION_LOAD_GPR6
872	EXCEPTION_LOAD_GPR4
873	l.j	_dispatch_bus_fault
874
875/* ---[ boot itlb miss handler ]----------------------------------------- */
876
877boot_itlb_miss_handler:
878
879/* mask for ITLB_MR register: - sets V (valid) bit,
880 *                            - sets bits belonging to VPN (15-12)
881 */
882#define ITLB_MR_MASK 0xfffff001
883
884/* mask for ITLB_TR register: - sets A (access) bit,
885 *                            - sets SXE (superuser execute) bit
886 *                            - sets bits belonging to VPN (15-12)
887 */
888#define ITLB_TR_MASK 0xfffff050
889
890/*
891#define VPN_MASK 0xffffe000
892#define PPN_MASK 0xffffe000
893*/
894
895
896
897	EXCEPTION_STORE_GPR2
898	EXCEPTION_STORE_GPR3
899	EXCEPTION_STORE_GPR4
900	EXCEPTION_STORE_GPR5
901	EXCEPTION_STORE_GPR6
902
903#if 0
904	l.mfspr r6,r0,SPR_ESR_BASE         //
905	l.andi  r6,r6,SPR_SR_SM            // are we in kernel mode ?
906	l.sfeqi r6,0                       // r6 == 0x1 --> SM
907	l.bf    exit_with_no_itranslation
908	l.nop
909#endif
910
911
912	l.mfspr r4,r0,SPR_EEAR_BASE        // get the offending EA
913
914earlyearly:
915	CLEAR_GPR(r6)
916
917	l.srli  r3,r4,0xd                  // r3 <- r4 / 8192 (sets are relative to page size (8Kb) NOT VPN size (4Kb)
918
919	l.mfspr r6, r0, SPR_IMMUCFGR
920	l.andi	r6, r6, SPR_IMMUCFGR_NTS
921	l.srli	r6, r6, SPR_IMMUCFGR_NTS_OFF
922	l.ori	r5, r0, 0x1
923	l.sll	r5, r5, r6 	// r5 = number IMMU sets from IMMUCFGR
924	l.addi	r6, r5, -1  	// r6 = nsets mask
925	l.and	r2, r3, r6	// r2 <- r3 % NSETS_MASK
926
927	l.or    r6,r6,r4                   // r6 <- r4
928	l.ori   r6,r6,~(VPN_MASK)          // r6 <- VPN :VPN .xfff - clear up lo(r6) to 0x**** *fff
929	l.movhi r5,hi(ITLB_MR_MASK)        // r5 <- ffff:0000.x000
930	l.ori   r5,r5,lo(ITLB_MR_MASK)     // r5 <- ffff:1111.x001 - apply ITLB_MR_MASK
931	l.and   r5,r5,r6                   // r5 <- VPN :VPN .x001 - we have ITLBMR entry
932	l.mtspr r2,r5,SPR_ITLBMR_BASE(0)   // set ITLBMR
933
934	/*
935	 * set up ITLB with no translation for EA <= 0x0fffffff
936	 *
937	 * we need this for head.S mapping (EA = PA). if we move all functions
938	 * which run with mmu enabled into entry.S, we might be able to eliminate this.
939	 *
940	 */
941	LOAD_SYMBOL_2_GPR(r6,0x0fffffff)
942	l.sfgeu  r6,r4                     // flag if r6 >= r4 (if 0xb0ffffff >= EA)
943	l.bf     1f                        // goto out
944	l.and    r3,r4,r4                  // delay slot :: 24 <- r4 (if flag==1)
945
946	tophys(r3,r4)                      // r3 <- PA
9471:
948	l.ori   r3,r3,~(PPN_MASK)          // r3 <- PPN :PPN .xfff - clear up lo(r6) to 0x**** *fff
949	l.movhi r5,hi(ITLB_TR_MASK)        // r5 <- ffff:0000.x000
950	l.ori   r5,r5,lo(ITLB_TR_MASK)     // r5 <- ffff:1111.x050 - apply ITLB_MR_MASK
951	l.and   r5,r5,r3                   // r5 <- PPN :PPN .x050 - we have ITLBTR entry
952	l.mtspr r2,r5,SPR_ITLBTR_BASE(0)   // set ITLBTR
953
954	EXCEPTION_LOAD_GPR6
955	EXCEPTION_LOAD_GPR5
956	EXCEPTION_LOAD_GPR4
957	EXCEPTION_LOAD_GPR3
958	EXCEPTION_LOAD_GPR2
959
960	l.rfe                              // SR <- ESR, PC <- EPC
961
962exit_with_no_itranslation:
963	EXCEPTION_LOAD_GPR4
964	EXCEPTION_LOAD_GPR6
965	l.j    _dispatch_bus_fault
966	l.nop
967
968/* ====================================================================== */
969/*
970 * Stuff below here shouldn't go into .head section... maybe this stuff
971 * can be moved to entry.S ???
972 */
973
974/* ==============================================[ DTLB miss handler ]=== */
975
976/*
977 * Comments:
978 *   Exception handlers are entered with MMU off so the following handler
979 *   needs to use physical addressing
980 *
981 */
982
983	.text
984ENTRY(dtlb_miss_handler)
985	EXCEPTION_STORE_GPR2
986	EXCEPTION_STORE_GPR3
987	EXCEPTION_STORE_GPR4
988	/*
989	 * get EA of the miss
990	 */
991	l.mfspr	r2,r0,SPR_EEAR_BASE
992	/*
993	 * pmd = (pmd_t *)(current_pgd + pgd_index(daddr));
994	 */
995	GET_CURRENT_PGD(r3,r4)		// r3 is current_pgd, r4 is temp
996	l.srli	r4,r2,0x18		// >> PAGE_SHIFT + (PAGE_SHIFT - 2)
997	l.slli	r4,r4,0x2		// to get address << 2
998	l.add	r3,r4,r3		// r4 is pgd_index(daddr)
999	/*
1000	 * if (pmd_none(*pmd))
1001	 *   goto pmd_none:
1002	 */
1003	tophys	(r4,r3)
1004	l.lwz	r3,0x0(r4)		// get *pmd value
1005	l.sfne	r3,r0
1006	l.bnf	d_pmd_none
1007	 l.addi	r3,r0,0xffffe000	// PAGE_MASK
1008
1009d_pmd_good:
1010	/*
1011	 * pte = *pte_offset(pmd, daddr);
1012	 */
1013	l.lwz	r4,0x0(r4)		// get **pmd value
1014	l.and	r4,r4,r3		// & PAGE_MASK
1015	l.srli	r2,r2,0xd		// >> PAGE_SHIFT, r2 == EEAR
1016	l.andi	r3,r2,0x7ff		// (1UL << PAGE_SHIFT - 2) - 1
1017	l.slli	r3,r3,0x2		// to get address << 2
1018	l.add	r3,r3,r4
1019	l.lwz	r3,0x0(r3)		// this is pte at last
1020	/*
1021	 * if (!pte_present(pte))
1022	 */
1023	l.andi	r4,r3,0x1
1024	l.sfne	r4,r0			// is pte present
1025	l.bnf	d_pte_not_present
1026	l.addi	r4,r0,0xffffe3fa	// PAGE_MASK | DTLB_UP_CONVERT_MASK
1027	/*
1028	 * fill DTLB TR register
1029	 */
1030	l.and	r4,r3,r4		// apply the mask
1031	// Determine number of DMMU sets
1032	l.mfspr r2, r0, SPR_DMMUCFGR
1033	l.andi	r2, r2, SPR_DMMUCFGR_NTS
1034	l.srli	r2, r2, SPR_DMMUCFGR_NTS_OFF
1035	l.ori	r3, r0, 0x1
1036	l.sll	r3, r3, r2 	// r3 = number DMMU sets DMMUCFGR
1037	l.addi	r2, r3, -1  	// r2 = nsets mask
1038	l.mfspr	r3, r0, SPR_EEAR_BASE
1039	l.srli	r3, r3, 0xd	// >> PAGE_SHIFT
1040	l.and	r2, r3, r2	// calc offset:	 & (NUM_TLB_ENTRIES-1)
1041	                                                   //NUM_TLB_ENTRIES
1042	l.mtspr	r2,r4,SPR_DTLBTR_BASE(0)
1043	/*
1044	 * fill DTLB MR register
1045	 */
1046	l.slli	r3, r3, 0xd		/* << PAGE_SHIFT => EA & PAGE_MASK */
1047	l.ori	r4,r3,0x1		// set hardware valid bit: DTBL_MR entry
1048	l.mtspr	r2,r4,SPR_DTLBMR_BASE(0)
1049
1050	EXCEPTION_LOAD_GPR2
1051	EXCEPTION_LOAD_GPR3
1052	EXCEPTION_LOAD_GPR4
1053	l.rfe
1054d_pmd_none:
1055d_pte_not_present:
1056	EXCEPTION_LOAD_GPR2
1057	EXCEPTION_LOAD_GPR3
1058	EXCEPTION_LOAD_GPR4
1059	EXCEPTION_HANDLE(_dtlb_miss_page_fault_handler)
1060
1061/* ==============================================[ ITLB miss handler ]=== */
1062ENTRY(itlb_miss_handler)
1063	EXCEPTION_STORE_GPR2
1064	EXCEPTION_STORE_GPR3
1065	EXCEPTION_STORE_GPR4
1066	/*
1067	 * get EA of the miss
1068	 */
1069	l.mfspr	r2,r0,SPR_EEAR_BASE
1070
1071	/*
1072	 * pmd = (pmd_t *)(current_pgd + pgd_index(daddr));
1073	 *
1074	 */
1075	GET_CURRENT_PGD(r3,r4)		// r3 is current_pgd, r5 is temp
1076	l.srli	r4,r2,0x18		// >> PAGE_SHIFT + (PAGE_SHIFT - 2)
1077	l.slli	r4,r4,0x2		// to get address << 2
1078	l.add	r3,r4,r3		// r4 is pgd_index(daddr)
1079	/*
1080	 * if (pmd_none(*pmd))
1081	 *   goto pmd_none:
1082	 */
1083	tophys	(r4,r3)
1084	l.lwz	r3,0x0(r4)		// get *pmd value
1085	l.sfne	r3,r0
1086	l.bnf	i_pmd_none
1087	 l.addi	r3,r0,0xffffe000	// PAGE_MASK
1088
1089i_pmd_good:
1090	/*
1091	 * pte = *pte_offset(pmd, iaddr);
1092	 *
1093	 */
1094	l.lwz	r4,0x0(r4)		// get **pmd value
1095	l.and	r4,r4,r3		// & PAGE_MASK
1096	l.srli	r2,r2,0xd		// >> PAGE_SHIFT, r2 == EEAR
1097	l.andi	r3,r2,0x7ff		// (1UL << PAGE_SHIFT - 2) - 1
1098	l.slli	r3,r3,0x2		// to get address << 2
1099	l.add	r3,r3,r4
1100	l.lwz	r3,0x0(r3)		// this is pte at last
1101	/*
1102	 * if (!pte_present(pte))
1103	 *
1104	 */
1105	l.andi	r4,r3,0x1
1106	l.sfne	r4,r0			// is pte present
1107	l.bnf	i_pte_not_present
1108	 l.addi	r4,r0,0xffffe03a	// PAGE_MASK | ITLB_UP_CONVERT_MASK
1109	/*
1110	 * fill ITLB TR register
1111	 */
1112	l.and	r4,r3,r4		// apply the mask
1113	l.andi	r3,r3,0x7c0		// _PAGE_EXEC | _PAGE_SRE | _PAGE_SWE |  _PAGE_URE | _PAGE_UWE
1114	l.sfeq	r3,r0
1115	l.bf	itlb_tr_fill //_workaround
1116	// Determine number of IMMU sets
1117	l.mfspr r2, r0, SPR_IMMUCFGR
1118	l.andi	r2, r2, SPR_IMMUCFGR_NTS
1119	l.srli	r2, r2, SPR_IMMUCFGR_NTS_OFF
1120	l.ori	r3, r0, 0x1
1121	l.sll	r3, r3, r2 	// r3 = number IMMU sets IMMUCFGR
1122	l.addi	r2, r3, -1  	// r2 = nsets mask
1123	l.mfspr	r3, r0, SPR_EEAR_BASE
1124	l.srli	r3, r3, 0xd	// >> PAGE_SHIFT
1125	l.and	r2, r3, r2	// calc offset:	 & (NUM_TLB_ENTRIES-1)
1126
1127/*
1128 * __PHX__ :: fixme
1129 * we should not just blindly set executable flags,
1130 * but it does help with ping. the clean way would be to find out
1131 * (and fix it) why stack doesn't have execution permissions
1132 */
1133
1134itlb_tr_fill_workaround:
1135	l.ori	r4,r4,0xc0		// | (SPR_ITLBTR_UXE | ITLBTR_SXE)
1136itlb_tr_fill:
1137	l.mtspr	r2,r4,SPR_ITLBTR_BASE(0)
1138	/*
1139	 * fill DTLB MR register
1140	 */
1141	l.slli	r3, r3, 0xd		/* << PAGE_SHIFT => EA & PAGE_MASK */
1142	l.ori	r4,r3,0x1		// set hardware valid bit: ITBL_MR entry
1143	l.mtspr	r2,r4,SPR_ITLBMR_BASE(0)
1144
1145	EXCEPTION_LOAD_GPR2
1146	EXCEPTION_LOAD_GPR3
1147	EXCEPTION_LOAD_GPR4
1148	l.rfe
1149
1150i_pmd_none:
1151i_pte_not_present:
1152	EXCEPTION_LOAD_GPR2
1153	EXCEPTION_LOAD_GPR3
1154	EXCEPTION_LOAD_GPR4
1155	EXCEPTION_HANDLE(_itlb_miss_page_fault_handler)
1156
1157/* ==============================================[ boot tlb handlers ]=== */
1158
1159
1160/* =================================================[ debugging aids ]=== */
1161
1162	.align 64
1163_immu_trampoline:
1164	.space 64
1165_immu_trampoline_top:
1166
1167#define TRAMP_SLOT_0		(0x0)
1168#define TRAMP_SLOT_1		(0x4)
1169#define TRAMP_SLOT_2		(0x8)
1170#define TRAMP_SLOT_3		(0xc)
1171#define TRAMP_SLOT_4		(0x10)
1172#define TRAMP_SLOT_5		(0x14)
1173#define TRAMP_FRAME_SIZE	(0x18)
1174
1175ENTRY(_immu_trampoline_workaround)
1176	// r2 EEA
1177	// r6 is physical EEA
1178	tophys(r6,r2)
1179
1180	LOAD_SYMBOL_2_GPR(r5,_immu_trampoline)
1181	tophys	(r3,r5)			// r3 is trampoline (physical)
1182
1183	LOAD_SYMBOL_2_GPR(r4,0x15000000)
1184	l.sw	TRAMP_SLOT_0(r3),r4
1185	l.sw	TRAMP_SLOT_1(r3),r4
1186	l.sw	TRAMP_SLOT_4(r3),r4
1187	l.sw	TRAMP_SLOT_5(r3),r4
1188
1189					// EPC = EEA - 0x4
1190	l.lwz	r4,0x0(r6)		// load op @ EEA + 0x0 (fc address)
1191	l.sw	TRAMP_SLOT_3(r3),r4	// store it to _immu_trampoline_data
1192	l.lwz	r4,-0x4(r6)		// load op @ EEA - 0x4 (f8 address)
1193	l.sw	TRAMP_SLOT_2(r3),r4	// store it to _immu_trampoline_data
1194
1195	l.srli  r5,r4,26                // check opcode for write access
1196	l.sfeqi r5,0                    // l.j
1197	l.bf    0f
1198	l.sfeqi r5,0x11                 // l.jr
1199	l.bf    1f
1200	l.sfeqi r5,1                    // l.jal
1201	l.bf    2f
1202	l.sfeqi r5,0x12                 // l.jalr
1203	l.bf    3f
1204	l.sfeqi r5,3                    // l.bnf
1205	l.bf    4f
1206	l.sfeqi r5,4                    // l.bf
1207	l.bf    5f
120899:
1209	l.nop
1210	l.j	99b			// should never happen
1211	l.nop	1
1212
1213	// r2 is EEA
1214	// r3 is trampoline address (physical)
1215	// r4 is instruction
1216	// r6 is physical(EEA)
1217	//
1218	// r5
1219
12202:	// l.jal
1221
1222	/* 19 20 aa aa	l.movhi r9,0xaaaa
1223	 * a9 29 bb bb  l.ori	r9,0xbbbb
1224	 *
1225	 * where 0xaaaabbbb is EEA + 0x4 shifted right 2
1226	 */
1227
1228	l.addi	r6,r2,0x4		// this is 0xaaaabbbb
1229
1230					// l.movhi r9,0xaaaa
1231	l.ori	r5,r0,0x1920		// 0x1920 == l.movhi r9
1232	l.sh	(TRAMP_SLOT_0+0x0)(r3),r5
1233	l.srli	r5,r6,16
1234	l.sh	(TRAMP_SLOT_0+0x2)(r3),r5
1235
1236					// l.ori   r9,0xbbbb
1237	l.ori	r5,r0,0xa929		// 0xa929 == l.ori r9
1238	l.sh	(TRAMP_SLOT_1+0x0)(r3),r5
1239	l.andi	r5,r6,0xffff
1240	l.sh	(TRAMP_SLOT_1+0x2)(r3),r5
1241
1242	/* falthrough, need to set up new jump offset */
1243
1244
12450:	// l.j
1246	l.slli	r6,r4,6			// original offset shifted left 6 - 2
1247//	l.srli	r6,r6,6			// original offset shifted right 2
1248
1249	l.slli	r4,r2,4			// old jump position: EEA shifted left 4
1250//	l.srli	r4,r4,6			// old jump position: shifted right 2
1251
1252	l.addi	r5,r3,0xc		// new jump position (physical)
1253	l.slli	r5,r5,4			// new jump position: shifted left 4
1254
1255	// calculate new jump offset
1256	// new_off = old_off + (old_jump - new_jump)
1257
1258	l.sub	r5,r4,r5		// old_jump - new_jump
1259	l.add	r5,r6,r5		// orig_off + (old_jump - new_jump)
1260	l.srli	r5,r5,6			// new offset shifted right 2
1261
1262	// r5 is new jump offset
1263					// l.j has opcode 0x0...
1264	l.sw	TRAMP_SLOT_2(r3),r5	// write it back
1265
1266	l.j	trampoline_out
1267	l.nop
1268
1269/* ----------------------------- */
1270
12713:	// l.jalr
1272
1273	/* 19 20 aa aa	l.movhi r9,0xaaaa
1274	 * a9 29 bb bb  l.ori	r9,0xbbbb
1275	 *
1276	 * where 0xaaaabbbb is EEA + 0x4 shifted right 2
1277	 */
1278
1279	l.addi	r6,r2,0x4		// this is 0xaaaabbbb
1280
1281					// l.movhi r9,0xaaaa
1282	l.ori	r5,r0,0x1920		// 0x1920 == l.movhi r9
1283	l.sh	(TRAMP_SLOT_0+0x0)(r3),r5
1284	l.srli	r5,r6,16
1285	l.sh	(TRAMP_SLOT_0+0x2)(r3),r5
1286
1287					// l.ori   r9,0xbbbb
1288	l.ori	r5,r0,0xa929		// 0xa929 == l.ori r9
1289	l.sh	(TRAMP_SLOT_1+0x0)(r3),r5
1290	l.andi	r5,r6,0xffff
1291	l.sh	(TRAMP_SLOT_1+0x2)(r3),r5
1292
1293	l.lhz	r5,(TRAMP_SLOT_2+0x0)(r3)	// load hi part of jump instruction
1294	l.andi	r5,r5,0x3ff		// clear out opcode part
1295	l.ori	r5,r5,0x4400		// opcode changed from l.jalr -> l.jr
1296	l.sh	(TRAMP_SLOT_2+0x0)(r3),r5 // write it back
1297
1298	/* falthrough */
1299
13001:	// l.jr
1301	l.j	trampoline_out
1302	l.nop
1303
1304/* ----------------------------- */
1305
13064:	// l.bnf
13075:	// l.bf
1308	l.slli	r6,r4,6			// original offset shifted left 6 - 2
1309//	l.srli	r6,r6,6			// original offset shifted right 2
1310
1311	l.slli	r4,r2,4			// old jump position: EEA shifted left 4
1312//	l.srli	r4,r4,6			// old jump position: shifted right 2
1313
1314	l.addi	r5,r3,0xc		// new jump position (physical)
1315	l.slli	r5,r5,4			// new jump position: shifted left 4
1316
1317	// calculate new jump offset
1318	// new_off = old_off + (old_jump - new_jump)
1319
1320	l.add	r6,r6,r4		// (orig_off + old_jump)
1321	l.sub	r6,r6,r5		// (orig_off + old_jump) - new_jump
1322	l.srli	r6,r6,6			// new offset shifted right 2
1323
1324	// r6 is new jump offset
1325	l.lwz	r4,(TRAMP_SLOT_2+0x0)(r3)	// load jump instruction
1326	l.srli	r4,r4,16
1327	l.andi	r4,r4,0xfc00		// get opcode part
1328	l.slli	r4,r4,16
1329	l.or	r6,r4,r6		// l.b(n)f new offset
1330	l.sw	TRAMP_SLOT_2(r3),r6	// write it back
1331
1332	/* we need to add l.j to EEA + 0x8 */
1333	tophys	(r4,r2)			// may not be needed (due to shifts down_
1334	l.addi	r4,r4,(0x8 - 0x8)	// jump target = r2 + 0x8 (compensate for 0x8)
1335					// jump position = r5 + 0x8 (0x8 compensated)
1336	l.sub	r4,r4,r5		// jump offset = target - new_position + 0x8
1337
1338	l.slli	r4,r4,4			// the amount of info in imediate of jump
1339	l.srli	r4,r4,6			// jump instruction with offset
1340	l.sw	TRAMP_SLOT_4(r3),r4	// write it to 4th slot
1341
1342	/* fallthrough */
1343
1344trampoline_out:
1345	// set up new EPC to point to our trampoline code
1346	LOAD_SYMBOL_2_GPR(r5,_immu_trampoline)
1347	l.mtspr	r0,r5,SPR_EPCR_BASE
1348
1349	// immu_trampoline is (4x) CACHE_LINE aligned
1350	// and only 6 instructions long,
1351	// so we need to invalidate only 2 lines
1352
1353	/* Establish cache block size
1354	   If BS=0, 16;
1355	   If BS=1, 32;
1356	   r14 contain block size
1357	*/
1358	l.mfspr r21,r0,SPR_ICCFGR
1359	l.andi	r21,r21,SPR_ICCFGR_CBS
1360	l.srli	r21,r21,7
1361	l.ori	r23,r0,16
1362	l.sll	r14,r23,r21
1363
1364	l.mtspr	r0,r5,SPR_ICBIR
1365	l.add	r5,r5,r14
1366	l.mtspr	r0,r5,SPR_ICBIR
1367
1368	l.jr	r9
1369	l.nop
1370
1371
1372/*
1373 * DSCR: prints a string referenced by r3.
1374 *
1375 * PRMS: r3     	- address of the first character of null
1376 *			terminated string to be printed
1377 *
1378 * PREQ: UART at UART_BASE_ADD has to be initialized
1379 *
1380 * POST: caller should be aware that r3, r9 are changed
1381 */
1382ENTRY(_emergency_print)
1383	EMERGENCY_PRINT_STORE_GPR4
1384	EMERGENCY_PRINT_STORE_GPR5
1385	EMERGENCY_PRINT_STORE_GPR6
1386	EMERGENCY_PRINT_STORE_GPR7
13872:
1388	l.lbz	r7,0(r3)
1389	l.sfeq	r7,r0
1390	l.bf	9f
1391	l.nop
1392
1393// putc:
1394	l.movhi r4,hi(UART_BASE_ADD)
1395
1396	l.addi  r6,r0,0x20
13971:      l.lbz   r5,5(r4)
1398	l.andi  r5,r5,0x20
1399	l.sfeq  r5,r6
1400	l.bnf   1b
1401	l.nop
1402
1403	l.sb    0(r4),r7
1404
1405	l.addi  r6,r0,0x60
14061:      l.lbz   r5,5(r4)
1407	l.andi  r5,r5,0x60
1408	l.sfeq  r5,r6
1409	l.bnf   1b
1410	l.nop
1411
1412	/* next character */
1413	l.j	2b
1414	l.addi	r3,r3,0x1
1415
14169:
1417	EMERGENCY_PRINT_LOAD_GPR7
1418	EMERGENCY_PRINT_LOAD_GPR6
1419	EMERGENCY_PRINT_LOAD_GPR5
1420	EMERGENCY_PRINT_LOAD_GPR4
1421	l.jr	r9
1422	l.nop
1423
1424ENTRY(_emergency_print_nr)
1425	EMERGENCY_PRINT_STORE_GPR4
1426	EMERGENCY_PRINT_STORE_GPR5
1427	EMERGENCY_PRINT_STORE_GPR6
1428	EMERGENCY_PRINT_STORE_GPR7
1429	EMERGENCY_PRINT_STORE_GPR8
1430
1431	l.addi	r8,r0,32		// shift register
1432
14331:	/* remove leading zeros */
1434	l.addi	r8,r8,-0x4
1435	l.srl	r7,r3,r8
1436	l.andi	r7,r7,0xf
1437
1438	/* don't skip the last zero if number == 0x0 */
1439	l.sfeqi	r8,0x4
1440	l.bf	2f
1441	l.nop
1442
1443	l.sfeq	r7,r0
1444	l.bf	1b
1445	l.nop
1446
14472:
1448	l.srl	r7,r3,r8
1449
1450	l.andi	r7,r7,0xf
1451	l.sflts	r8,r0
1452	l.bf	9f
1453
1454	l.sfgtui r7,0x9
1455	l.bnf	8f
1456	l.nop
1457	l.addi	r7,r7,0x27
1458
14598:
1460	l.addi	r7,r7,0x30
1461// putc:
1462	l.movhi r4,hi(UART_BASE_ADD)
1463
1464	l.addi  r6,r0,0x20
14651:      l.lbz   r5,5(r4)
1466	l.andi  r5,r5,0x20
1467	l.sfeq  r5,r6
1468	l.bnf   1b
1469	l.nop
1470
1471	l.sb    0(r4),r7
1472
1473	l.addi  r6,r0,0x60
14741:      l.lbz   r5,5(r4)
1475	l.andi  r5,r5,0x60
1476	l.sfeq  r5,r6
1477	l.bnf   1b
1478	l.nop
1479
1480	/* next character */
1481	l.j	2b
1482	l.addi	r8,r8,-0x4
1483
14849:
1485	EMERGENCY_PRINT_LOAD_GPR8
1486	EMERGENCY_PRINT_LOAD_GPR7
1487	EMERGENCY_PRINT_LOAD_GPR6
1488	EMERGENCY_PRINT_LOAD_GPR5
1489	EMERGENCY_PRINT_LOAD_GPR4
1490	l.jr	r9
1491	l.nop
1492
1493
1494/*
1495 * This should be used for debugging only.
1496 * It messes up the Linux early serial output
1497 * somehow, so use it sparingly and essentially
1498 * only if you need to debug something that goes wrong
1499 * before Linux gets the early serial going.
1500 *
1501 * Furthermore, you'll have to make sure you set the
1502 * UART_DEVISOR correctly according to the system
1503 * clock rate.
1504 *
1505 *
1506 */
1507
1508
1509
1510#define SYS_CLK            20000000
1511//#define SYS_CLK            1843200
1512#define OR32_CONSOLE_BAUD  115200
1513#define UART_DIVISOR       SYS_CLK/(16*OR32_CONSOLE_BAUD)
1514
1515ENTRY(_early_uart_init)
1516	l.movhi	r3,hi(UART_BASE_ADD)
1517
1518	l.addi	r4,r0,0x7
1519	l.sb	0x2(r3),r4
1520
1521	l.addi	r4,r0,0x0
1522	l.sb	0x1(r3),r4
1523
1524	l.addi	r4,r0,0x3
1525	l.sb	0x3(r3),r4
1526
1527	l.lbz	r5,3(r3)
1528	l.ori	r4,r5,0x80
1529	l.sb	0x3(r3),r4
1530	l.addi	r4,r0,((UART_DIVISOR>>8) & 0x000000ff)
1531	l.sb	UART_DLM(r3),r4
1532	l.addi  r4,r0,((UART_DIVISOR) & 0x000000ff)
1533	l.sb	UART_DLL(r3),r4
1534	l.sb	0x3(r3),r5
1535
1536	l.jr	r9
1537	l.nop
1538
1539	.section .rodata
1540_string_unhandled_exception:
1541	.string "\n\rRunarunaround: Unhandled exception 0x\0"
1542
1543_string_epc_prefix:
1544	.string ": EPC=0x\0"
1545
1546_string_nl:
1547	.string "\n\r\0"
1548
1549
1550/* ========================================[ page aligned structures ]=== */
1551
1552/*
1553 * .data section should be page aligned
1554 *	(look into arch/openrisc/kernel/vmlinux.lds.S)
1555 */
1556	.section .data,"aw"
1557	.align	8192
1558	.global  empty_zero_page
1559empty_zero_page:
1560	.space  8192
1561
1562	.global  swapper_pg_dir
1563swapper_pg_dir:
1564	.space  8192
1565
1566	.global	_unhandled_stack
1567_unhandled_stack:
1568	.space	8192
1569_unhandled_stack_top:
1570
1571/* ============================================================[ EOF ]=== */
1572