]> git.ipfire.org Git - people/ms/u-boot.git/blob - arch/xtensa/cpu/start.S
8e4bc99e42959ee4cfaa22010be492f793b86ae0
[people/ms/u-boot.git] / arch / xtensa / cpu / start.S
1 /*
2 * (C) Copyright 2008 - 2013 Tensilica Inc.
3 * (C) Copyright 2014 - 2016 Cadence Design Systems Inc.
4 *
5 * SPDX-License-Identifier: GPL-2.0+
6 */
7
8 #include <config.h>
9 #include <asm/asmmacro.h>
10 #include <asm/cacheasm.h>
11 #include <asm/regs.h>
12 #include <asm/arch/tie.h>
13 #include <asm-offsets.h>
14
15 /*
16 * Offsets into the the pt_regs struture.
17 * Make sure these always match with the structure defined in ptrace.h!
18 */
19
20 #define PT_PC 0
21 #define PT_PS 4
22 #define PT_DEPC 8
23 #define PT_EXCCAUSE 12
24 #define PT_EXCVADDR 16
25 #define PT_DEBUGCAUSE 20
26 #define PT_WMASK 24
27 #define PT_LBEG 28
28 #define PT_LEND 32
29 #define PT_LCOUNT 36
30 #define PT_SAR 40
31 #define PT_WINDOWBASE 44
32 #define PT_WINDOWSTART 48
33 #define PT_SYSCALL 52
34 #define PT_ICOUNTLEVEL 56
35 #define PT_RESERVED 60
36 #define PT_AREG 64
37 #define PT_SIZE (64 + 64)
38
39 /*
40 * Cache attributes are different for full MMU and region protection.
41 */
42
43 #if XCHAL_HAVE_PTP_MMU
44 #define CA_WRITEBACK (0x7)
45 #else
46 #define CA_WRITEBACK (0x4)
47 #endif
48
49 /*
50 * Reset vector.
51 * Only a trampoline to jump to _start
52 * (Note that we have to mark the section writable as the section contains
53 * a relocatable literal)
54 */
55
56 .section .ResetVector.text, "awx"
57 .global _ResetVector
58 _ResetVector:
59
60 j 1f
61 .align 4
62 2: .long _start
63 1: l32r a2, 2b
64 jx a2
65
66
67 /*
68 * Processor initialization. We still run in rom space.
69 *
70 * NOTE: Running in ROM
71 * For Xtensa, we currently don't allow to run some code from ROM but
72 * unpack the data immediately to memory. This requires, for example,
73 * that DDR has been set up before running U-Boot. (See also comments
74 * inline for ways to change it)
75 */
76
77 .section .reset.text, "ax"
78 .global _start
79 .align 4
80 _start:
81 /* Keep a0 = 0 for various initializations */
82
83 movi a0, 0
84
85 /*
86 * For full MMU cores, put page table at unmapped virtual address.
87 * This ensures that accesses outside the static maps result
88 * in miss exceptions rather than random behaviour.
89 */
90
91 #if XCHAL_HAVE_PTP_MMU
92 wsr a0, PTEVADDR
93 #endif
94
95 /* Disable dbreak debug exceptions */
96
97 #if XCHAL_HAVE_DEBUG && XCHAL_NUM_DBREAK > 0
98 .set _index, 0
99 .rept XCHAL_NUM_DBREAK
100 wsr a0, DBREAKC + _index
101 .set _index, _index + 1
102 .endr
103 #endif
104
105 /* Reset windowbase and windowstart */
106
107 #if XCHAL_HAVE_WINDOWED
108 movi a3, 1
109 wsr a3, windowstart
110 wsr a0, windowbase
111 rsync
112 movi a0, 0 /* windowbase might have changed */
113 #endif
114
115 /*
116 * Vecbase in bitstream may differ from header files
117 * set or check it.
118 */
119
120 #if XCHAL_HAVE_VECBASE
121 movi a3, XCHAL_VECBASE_RESET_VADDR /* VECBASE reset value */
122 wsr a3, VECBASE
123 #endif
124
125 #if XCHAL_HAVE_LOOPS
126 /* Disable loops */
127
128 wsr a0, LCOUNT
129 #endif
130
131 /* Set PS.WOE = 0, PS.EXCM = 0 (for loop), PS.INTLEVEL = EXCM level */
132
133 #if XCHAL_HAVE_XEA1
134 movi a2, 1
135 #else
136 movi a2, XCHAL_EXCM_LEVEL
137 #endif
138 wsr a2, PS
139 rsync
140
141 /* Unlock and invalidate caches */
142
143 ___unlock_dcache_all a2, a3
144 ___invalidate_dcache_all a2, a3
145 ___unlock_icache_all a2, a3
146 ___invalidate_icache_all a2, a3
147
148 isync
149
150 /* Unpack data sections */
151
152 movi a2, __reloc_table_start
153 movi a3, __reloc_table_end
154
155 1: beq a2, a3, 3f # no more entries?
156 l32i a4, a2, 0 # start destination (in RAM)
157 l32i a5, a2, 4 # end destination (in RAM)
158 l32i a6, a2, 8 # start source (in ROM)
159 addi a2, a2, 12 # next entry
160 beq a4, a5, 1b # skip, empty entry
161 beq a4, a6, 1b # skip, source and destination are the same
162
163 /* If there's memory protection option with 512MB TLB regions and
164 * cache attributes in TLB entries and caching is not inhibited,
165 * enable data/instruction cache for relocated image.
166 */
167 #if XCHAL_HAVE_SPANNING_WAY && \
168 (!defined(CONFIG_SYS_DCACHE_OFF) || \
169 !defined(CONFIG_SYS_ICACHE_OFF))
170 srli a7, a4, 29
171 slli a7, a7, 29
172 addi a7, a7, XCHAL_SPANNING_WAY
173 #ifndef CONFIG_SYS_DCACHE_OFF
174 rdtlb1 a8, a7
175 srli a8, a8, 4
176 slli a8, a8, 4
177 addi a8, a8, CA_WRITEBACK
178 wdtlb a8, a7
179 #endif
180 #ifndef CONFIG_SYS_ICACHE_OFF
181 ritlb1 a8, a7
182 srli a8, a8, 4
183 slli a8, a8, 4
184 addi a8, a8, CA_WRITEBACK
185 witlb a8, a7
186 #endif
187 isync
188 #endif
189
190 2: l32i a7, a6, 0
191 addi a6, a6, 4
192 s32i a7, a4, 0
193 addi a4, a4, 4
194 bltu a4, a5, 2b
195 j 1b
196
197 3: /* All code and initalized data segments have been copied */
198
199 /* Setup PS, PS.WOE = 1, PS.EXCM = 0, PS.INTLEVEL = EXCM level. */
200
201 #if __XTENSA_CALL0_ABI__
202 movi a2, XCHAL_EXCM_LEVEL
203 #else
204 movi a2, (1<<PS_WOE_BIT) | XCHAL_EXCM_LEVEL
205 #endif
206 wsr a2, PS
207 rsync
208
209 /* Writeback */
210
211 ___flush_dcache_all a2, a3
212
213 #ifdef __XTENSA_WINDOWED_ABI__
214 /*
215 * In windowed ABI caller and call target need to be within the same
216 * gigabyte. Put the rest of the code into the text segment and jump
217 * there.
218 */
219
220 movi a4, .Lboard_init_code
221 jx a4
222
223 .text
224 .align 4
225 .Lboard_init_code:
226 #endif
227
228 movi a0, 0
229 movi sp, (CONFIG_SYS_TEXT_ADDR - 16) & 0xfffffff0
230
231 #ifdef CONFIG_DEBUG_UART
232 movi a4, debug_uart_init
233 #ifdef __XTENSA_CALL0_ABI__
234 callx0 a4
235 #else
236 callx4 a4
237 #endif
238 #endif
239
240 movi a4, board_init_f_alloc_reserve
241
242 #ifdef __XTENSA_CALL0_ABI__
243 mov a2, sp
244 callx0 a4
245 mov sp, a2
246 #else
247 mov a6, sp
248 callx4 a4
249 movsp sp, a6
250 #endif
251
252 movi a4, board_init_f_init_reserve
253
254 #ifdef __XTENSA_CALL0_ABI__
255 callx0 a4
256 #else
257 callx4 a4
258 #endif
259
260 /*
261 * Call board initialization routine (never returns).
262 */
263
264 movi a4, board_init_f
265
266 #ifdef __XTENSA_CALL0_ABI__
267 movi a2, 0
268 callx0 a4
269 #else
270 movi a6, 0
271 callx4 a4
272 #endif
273 /* Never Returns */
274 ill
275
276 /*
277 * void relocate_code (addr_sp, gd, addr_moni)
278 *
279 * This "function" does not return, instead it continues in RAM
280 * after relocating the monitor code.
281 *
282 * a2 = addr_sp
283 * a3 = gd
284 * a4 = destination address
285 */
286 .text
287 .globl relocate_code
288 .align 4
289 relocate_code:
290 abi_entry
291
292 #ifdef __XTENSA_CALL0_ABI__
293 mov a1, a2
294 mov a2, a3
295 mov a3, a4
296 movi a0, board_init_r
297 callx0 a0
298 #else
299 /* We can't movsp here, because the chain of stack frames may cross
300 * the now reserved memory. We need to toss all window frames except
301 * the current, create new pristine stack frame and start from scratch.
302 */
303 rsr a0, windowbase
304 ssl a0
305 movi a0, 1
306 sll a0, a0
307 wsr a0, windowstart
308 rsync
309
310 movi a0, 0
311
312 /* Reserve 16-byte save area */
313 addi sp, a2, -16
314 mov a6, a3
315 mov a7, a4
316 movi a4, board_init_r
317 callx4 a4
318 #endif
319 ill
320
321 #if XCHAL_HAVE_EXCEPTIONS
322
323 /*
324 * Exception vectors.
325 *
326 * Various notes:
327 * - We currently don't use the user exception vector (PS.UM is always 0),
328 * but do define such a vector, just in case. They both jump to the
329 * same exception handler, though.
330 * - We currently only save the bare minimum number of registers:
331 * a0...a15, sar, loop-registers, exception register (epc1, excvaddr,
332 * exccause, depc)
333 * - WINDOWSTART is only saved to identify if registers have been spilled
334 * to the wrong stack (exception stack) while executing the exception
335 * handler.
336 */
337
338 .section .KernelExceptionVector.text, "ax"
339 .global _KernelExceptionVector
340 _KernelExceptionVector:
341
342 wsr a2, EXCSAVE1
343 movi a2, ExceptionHandler
344 jx a2
345
346 .section .UserExceptionVector.text, "ax"
347 .global _UserExceptionVector
348 _UserExceptionVector:
349
350 wsr a2, EXCSAVE1
351 movi a2, ExceptionHandler
352 jx a2
353
354 #if !XCHAL_HAVE_XEA1
355 .section .DoubleExceptionVector.text, "ax"
356 .global _DoubleExceptionVector
357 _DoubleExceptionVector:
358
359 #ifdef __XTENSA_CALL0_ABI__
360 wsr a0, EXCSAVE1
361 movi a0, hang # report and ask user to reset board
362 callx0 a0
363 #else
364 wsr a4, EXCSAVE1
365 movi a4, hang # report and ask user to reset board
366 callx4 a4
367 #endif
368 #endif
369 /* Does not return here */
370
371
372 .text
373 .align 4
374 ExceptionHandler:
375
376 rsr a2, EXCCAUSE # find handler
377
378 #if XCHAL_HAVE_WINDOWED
379 /* Special case for alloca handler */
380
381 bnei a2, 5, 1f # jump if not alloca exception
382
383 addi a1, a1, -16 - 4 # create a small stack frame
384 s32i a3, a1, 0 # and save a3 (a2 still in excsave1)
385 movi a2, fast_alloca_exception
386 jx a2 # jump to fast_alloca_exception
387 #endif
388 /* All other exceptions go here: */
389
390 /* Create ptrace stack and save a0...a3 */
391
392 1: addi a2, a1, - PT_SIZE - 16
393 s32i a0, a2, PT_AREG + 0 * 4
394 s32i a1, a2, PT_AREG + 1 * 4
395 s32i a3, a2, PT_AREG + 3 * 4
396 rsr a3, EXCSAVE1
397 s32i a3, a2, PT_AREG + 2 * 4
398 mov a1, a2
399
400 /* Save remaining AR registers */
401
402 s32i a4, a1, PT_AREG + 4 * 4
403 s32i a5, a1, PT_AREG + 5 * 4
404 s32i a6, a1, PT_AREG + 6 * 4
405 s32i a7, a1, PT_AREG + 7 * 4
406 s32i a8, a1, PT_AREG + 8 * 4
407 s32i a9, a1, PT_AREG + 9 * 4
408 s32i a10, a1, PT_AREG + 10 * 4
409 s32i a11, a1, PT_AREG + 11 * 4
410 s32i a12, a1, PT_AREG + 12 * 4
411 s32i a13, a1, PT_AREG + 13 * 4
412 s32i a14, a1, PT_AREG + 14 * 4
413 s32i a15, a1, PT_AREG + 15 * 4
414
415 /* Save SRs */
416
417 #if XCHAL_HAVE_WINDOWED
418 rsr a2, WINDOWSTART
419 s32i a2, a1, PT_WINDOWSTART
420 #endif
421
422 rsr a2, SAR
423 rsr a3, EPC1
424 rsr a4, EXCVADDR
425 s32i a2, a1, PT_SAR
426 s32i a3, a1, PT_PC
427 s32i a4, a1, PT_EXCVADDR
428
429 #if XCHAL_HAVE_LOOPS
430 movi a2, 0
431 rsr a3, LBEG
432 xsr a2, LCOUNT
433 s32i a3, a1, PT_LBEG
434 rsr a3, LEND
435 s32i a2, a1, PT_LCOUNT
436 s32i a3, a1, PT_LEND
437 #endif
438
439 /* Set up C environment and call registered handler */
440 /* Setup stack, PS.WOE = 1, PS.EXCM = 0, PS.INTLEVEL = EXCM level. */
441
442 rsr a2, EXCCAUSE
443 #if XCHAL_HAVE_XEA1
444 movi a3, (1<<PS_WOE_BIT) | 1
445 #elif __XTENSA_CALL0_ABI__
446 movi a3, XCHAL_EXCM_LEVEL
447 #else
448 movi a3, (1<<PS_WOE_BIT) | XCHAL_EXCM_LEVEL
449 #endif
450 xsr a3, PS
451 rsync
452 s32i a2, a1, PT_EXCCAUSE
453 s32i a3, a1, PT_PS
454
455 movi a0, exc_table
456 addx4 a0, a2, a0
457 l32i a0, a0, 0
458 #ifdef __XTENSA_CALL0_ABI__
459 mov a2, a1 # Provide stack frame as only argument
460 callx0 a0
461 l32i a3, a1, PT_PS
462 #else
463 mov a6, a1 # Provide stack frame as only argument
464 callx4 a0
465 #endif
466
467 /* Restore PS and go to exception mode (PS.EXCM=1) */
468
469 wsr a3, PS
470
471 /* Restore SR registers */
472
473 #if XCHAL_HAVE_LOOPS
474 l32i a2, a1, PT_LBEG
475 l32i a3, a1, PT_LEND
476 l32i a4, a1, PT_LCOUNT
477 wsr a2, LBEG
478 wsr a3, LEND
479 wsr a4, LCOUNT
480 #endif
481
482 l32i a2, a1, PT_SAR
483 l32i a3, a1, PT_PC
484 wsr a2, SAR
485 wsr a3, EPC1
486
487 #if XCHAL_HAVE_WINDOWED
488 /* Do we need to simulate a MOVSP? */
489
490 l32i a2, a1, PT_WINDOWSTART
491 addi a3, a2, -1
492 and a2, a2, a3
493 beqz a2, 1f # Skip if regs were spilled before exc.
494
495 rsr a2, WINDOWSTART
496 addi a3, a2, -1
497 and a2, a2, a3
498 bnez a2, 1f # Skip if registers aren't spilled now
499
500 addi a2, a1, -16
501 l32i a4, a2, 0
502 l32i a5, a2, 4
503 s32i a4, a1, PT_SIZE + 0
504 s32i a5, a1, PT_SIZE + 4
505 l32i a4, a2, 8
506 l32i a5, a2, 12
507 s32i a4, a1, PT_SIZE + 8
508 s32i a5, a1, PT_SIZE + 12
509 #endif
510
511 /* Restore address register */
512
513 1: l32i a15, a1, PT_AREG + 15 * 4
514 l32i a14, a1, PT_AREG + 14 * 4
515 l32i a13, a1, PT_AREG + 13 * 4
516 l32i a12, a1, PT_AREG + 12 * 4
517 l32i a11, a1, PT_AREG + 11 * 4
518 l32i a10, a1, PT_AREG + 10 * 4
519 l32i a9, a1, PT_AREG + 9 * 4
520 l32i a8, a1, PT_AREG + 8 * 4
521 l32i a7, a1, PT_AREG + 7 * 4
522 l32i a6, a1, PT_AREG + 6 * 4
523 l32i a5, a1, PT_AREG + 5 * 4
524 l32i a4, a1, PT_AREG + 4 * 4
525 l32i a3, a1, PT_AREG + 3 * 4
526 l32i a2, a1, PT_AREG + 2 * 4
527 l32i a0, a1, PT_AREG + 0 * 4
528
529 l32i a1, a1, PT_AREG + 1 * 4 # Remove ptrace stack frame
530
531 rfe
532
533 #endif /* XCHAL_HAVE_EXCEPTIONS */
534
535 #if XCHAL_HAVE_WINDOWED
536
537 /*
538 * Window overflow and underflow handlers.
539 * The handlers must be 64 bytes apart, first starting with the underflow
540 * handlers underflow-4 to underflow-12, then the overflow handlers
541 * overflow-4 to overflow-12.
542 *
543 * Note: We rerun the underflow handlers if we hit an exception, so
544 * we try to access any page that would cause a page fault early.
545 */
546
547 .section .WindowVectors.text, "ax"
548
549 /* 4-Register Window Overflow Vector (Handler) */
550
551 .align 64
552 .global _WindowOverflow4
553 _WindowOverflow4:
554 s32e a0, a5, -16
555 s32e a1, a5, -12
556 s32e a2, a5, -8
557 s32e a3, a5, -4
558 rfwo
559
560
561 /* 4-Register Window Underflow Vector (Handler) */
562
563 .align 64
564 .global _WindowUnderflow4
565 _WindowUnderflow4:
566 l32e a0, a5, -16
567 l32e a1, a5, -12
568 l32e a2, a5, -8
569 l32e a3, a5, -4
570 rfwu
571
572 /*
573 * a0: a0
574 * a1: new stack pointer = a1 - 16 - 4
575 * a2: available, saved in excsave1
576 * a3: available, saved on stack *a1
577 */
578
579 /* 15*/ .byte 0xff
580
581 fast_alloca_exception: /* must be at _WindowUnderflow4 + 16 */
582
583 /* 16*/ rsr a2, PS
584 /* 19*/ rsr a3, WINDOWBASE
585 /* 22*/ extui a2, a2, PS_OWB_SHIFT, PS_OWB_SHIFT
586 /* 25*/ xor a2, a2, a3
587 /* 28*/ rsr a3, PS
588 /* 31*/ slli a2, a2, PS_OWB_SHIFT
589 /* 34*/ xor a2, a3, a2
590 /* 37*/ wsr a2, PS
591
592 /* 40*/ _l32i a3, a1, 0
593 /* 43*/ addi a1, a1, 16 + 4
594 /* 46*/ rsr a2, EXCSAVE1
595
596 /* 49*/ rotw -1
597 /* 52*/ _bbci.l a4, 31, _WindowUnderflow4 /* 0x: call4 */
598 /* 55*/ rotw -1
599 /* 58*/ _bbci.l a8, 30, _WindowUnderflow8 /* 10: call8 */
600 /* 61*/ _j __WindowUnderflow12 /* 11: call12 */
601 /* 64*/
602
603 /* 8-Register Window Overflow Vector (Handler) */
604
605 .align 64
606 .global _WindowOverflow8
607 _WindowOverflow8:
608 s32e a0, a9, -16
609 l32e a0, a1, -12
610 s32e a2, a9, -8
611 s32e a1, a9, -12
612 s32e a3, a9, -4
613 s32e a4, a0, -32
614 s32e a5, a0, -28
615 s32e a6, a0, -24
616 s32e a7, a0, -20
617 rfwo
618
619 /* 8-Register Window Underflow Vector (Handler) */
620
621 .align 64
622 .global _WindowUnderflow8
623 _WindowUnderflow8:
624 l32e a1, a9, -12
625 l32e a0, a9, -16
626 l32e a7, a1, -12
627 l32e a2, a9, -8
628 l32e a4, a7, -32
629 l32e a3, a9, -4
630 l32e a5, a7, -28
631 l32e a6, a7, -24
632 l32e a7, a7, -20
633 rfwu
634
635 /* 12-Register Window Overflow Vector (Handler) */
636
637 .align 64
638 .global _WindowOverflow12
639 _WindowOverflow12:
640 s32e a0, a13, -16
641 l32e a0, a1, -12
642 s32e a1, a13, -12
643 s32e a2, a13, -8
644 s32e a3, a13, -4
645 s32e a4, a0, -48
646 s32e a5, a0, -44
647 s32e a6, a0, -40
648 s32e a7, a0, -36
649 s32e a8, a0, -32
650 s32e a9, a0, -28
651 s32e a10, a0, -24
652 s32e a11, a0, -20
653 rfwo
654
655 /* 12-Register Window Underflow Vector (Handler) */
656
657 .org _WindowOverflow12 + 64 - 3
658 __WindowUnderflow12:
659 rotw -1
660 .global _WindowUnderflow12
661 _WindowUnderflow12:
662 l32e a1, a13, -12
663 l32e a0, a13, -16
664 l32e a11, a1, -12
665 l32e a2, a13, -8
666 l32e a4, a11, -48
667 l32e a8, a11, -32
668 l32e a3, a13, -4
669 l32e a5, a11, -44
670 l32e a6, a11, -40
671 l32e a7, a11, -36
672 l32e a9, a11, -28
673 l32e a10, a11, -24
674 l32e a11, a11, -20
675 rfwu
676
677 #endif /* XCHAL_HAVE_WINDOWED */