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