]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - cpu/mpc8xx/start.S
81a4dc07c96ba9bec1b99d3b17242d05e387a5f6
[karo-tx-uboot.git] / cpu / mpc8xx / start.S
1 /*
2  *  Copyright (C) 1998  Dan Malek <dmalek@jlc.net>
3  *  Copyright (C) 1999  Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se>
4  *  Copyright (C) 2000,2001,2002 Wolfgang Denk <wd@denx.de>
5  *
6  * See file CREDITS for list of people who contributed to this
7  * project.
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License as
11  * published by the Free Software Foundation; either version 2 of
12  * the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
22  * MA 02111-1307 USA
23  */
24
25 /*  U-Boot - Startup Code for PowerPC based Embedded Boards
26  *
27  *
28  *  The processor starts at 0x00000100 and the code is executed
29  *  from flash. The code is organized to be at an other address
30  *  in memory, but as long we don't jump around before relocating.
31  *  board_init lies at a quite high address and when the cpu has
32  *  jumped there, everything is ok.
33  *  This works because the cpu gives the FLASH (CS0) the whole
34  *  address space at startup, and board_init lies as a echo of
35  *  the flash somewhere up there in the memorymap.
36  *
37  *  board_init will change CS0 to be positioned at the correct
38  *  address and (s)dram will be positioned at address 0
39  */
40 #include <config.h>
41 #include <mpc8xx.h>
42 #include <version.h>
43
44 #define CONFIG_8xx 1            /* needed for Linux kernel header files */
45 #define _LINUX_CONFIG_H 1       /* avoid reading Linux autoconf.h file  */
46
47 #include <ppc_asm.tmpl>
48 #include <ppc_defs.h>
49
50 #include <asm/cache.h>
51 #include <asm/mmu.h>
52
53 #ifndef  CONFIG_IDENT_STRING
54 #define  CONFIG_IDENT_STRING ""
55 #endif
56
57 /* We don't want the  MMU yet.
58 */
59 #undef  MSR_KERNEL
60 #define MSR_KERNEL ( MSR_ME | MSR_RI )  /* Machine Check and Recoverable Interr. */
61
62 /*
63  * Set up GOT: Global Offset Table
64  *
65  * Use r14 to access the GOT
66  */
67         START_GOT
68         GOT_ENTRY(_GOT2_TABLE_)
69         GOT_ENTRY(_FIXUP_TABLE_)
70
71         GOT_ENTRY(_start)
72         GOT_ENTRY(_start_of_vectors)
73         GOT_ENTRY(_end_of_vectors)
74         GOT_ENTRY(transfer_to_handler)
75
76         GOT_ENTRY(__init_end)
77         GOT_ENTRY(_end)
78         GOT_ENTRY(__bss_start)
79 #if defined(CONFIG_FADS) || defined(CONFIG_ICU862)
80         GOT_ENTRY(environment)
81 #endif
82         END_GOT
83
84 /*
85  * r3 - 1st arg to board_init(): IMMP pointer
86  * r4 - 2nd arg to board_init(): boot flag
87  */
88         .text
89         .long   0x27051956              /* U-Boot Magic Number                  */
90         .globl  version_string
91 version_string:
92         .ascii U_BOOT_VERSION
93         .ascii " (", __DATE__, " - ", __TIME__, ")"
94         .ascii CONFIG_IDENT_STRING, "\0"
95
96         . = EXC_OFF_SYS_RESET
97         .globl  _start
98 _start:
99         lis     r3, CFG_IMMR@h          /* position IMMR */
100         mtspr   638, r3
101         li      r21, BOOTFLAG_COLD      /* Normal Power-On: Boot from FLASH     */
102         b       boot_cold
103
104         . = EXC_OFF_SYS_RESET + 0x10
105
106         .globl  _start_warm
107 _start_warm:
108         li      r21, BOOTFLAG_WARM      /* Software reboot                      */
109         b       boot_warm
110
111 boot_cold:
112 boot_warm:
113
114         /* Initialize machine status; enable machine check interrupt            */
115         /*----------------------------------------------------------------------*/
116         li      r3, MSR_KERNEL          /* Set ME, RI flags */
117         mtmsr   r3
118         mtspr   SRR1, r3                /* Make SRR1 match MSR */
119
120         mfspr   r3, ICR                 /* clear Interrupt Cause Register */
121
122         /* Initialize debug port registers                                      */
123         /*----------------------------------------------------------------------*/
124         xor     r0, r0, r0              /* Clear R0 */
125         mtspr   LCTRL1, r0              /* Initialize debug port regs */
126         mtspr   LCTRL2, r0
127         mtspr   COUNTA, r0
128         mtspr   COUNTB, r0
129
130         /* Reset the caches                                                     */
131         /*----------------------------------------------------------------------*/
132
133         mfspr   r3, IC_CST              /* Clear error bits */
134         mfspr   r3, DC_CST
135
136         lis     r3, IDC_UNALL@h         /* Unlock all */
137         mtspr   IC_CST, r3
138         mtspr   DC_CST, r3
139
140         lis     r3, IDC_INVALL@h        /* Invalidate all */
141         mtspr   IC_CST, r3
142         mtspr   DC_CST, r3
143
144         lis     r3, IDC_DISABLE@h       /* Disable data cache */
145         mtspr   DC_CST, r3
146
147 #if !(defined(CONFIG_IP860) || defined(CONFIG_PCU_E) || defined (CONFIG_FLAGADM))
148                                         /* On IP860 and PCU E,
149                                          * we cannot enable IC yet
150                                          */
151         lis     r3, IDC_ENABLE@h        /* Enable instruction cache */
152 #endif
153         mtspr   IC_CST, r3
154
155         /* invalidate all tlb's                                                 */
156         /*----------------------------------------------------------------------*/
157
158         tlbia
159         isync
160
161         /*
162          * Calculate absolute address in FLASH and jump there
163          *----------------------------------------------------------------------*/
164
165         lis     r3, CFG_MONITOR_BASE@h
166         ori     r3, r3, CFG_MONITOR_BASE@l
167         addi    r3, r3, in_flash - _start + EXC_OFF_SYS_RESET
168         mtlr    r3
169         blr
170
171 in_flash:
172
173         /* initialize some SPRs that are hard to access from C                  */
174         /*----------------------------------------------------------------------*/
175
176         lis     r3, CFG_IMMR@h          /* pass IMMR as arg1 to C routine */
177         ori     r1, r3, CFG_INIT_SP_OFFSET /* set up the stack in internal DPRAM */
178         /* Note: R0 is still 0 here */
179         stwu    r0, -4(r1)              /* clear final stack frame so that      */
180         stwu    r0, -4(r1)              /* stack backtraces terminate cleanly   */
181
182         /*
183          * Disable serialized ifetch and show cycles
184          * (i.e. set processor to normal mode).
185          * This is also a silicon bug workaround, see errata
186          */
187
188         li      r2, 0x0007
189         mtspr   ICTRL, r2
190
191         /* Set up debug mode entry */
192
193         lis     r2, CFG_DER@h
194         ori     r2, r2, CFG_DER@l
195         mtspr   DER, r2
196
197         /* let the C-code set up the rest                                       */
198         /*                                                                      */
199         /* Be careful to keep code relocatable !                                */
200         /*----------------------------------------------------------------------*/
201
202         GET_GOT                 /* initialize GOT access                        */
203
204         /* r3: IMMR */
205         bl      cpu_init_f      /* run low-level CPU init code     (from Flash) */
206
207         mr      r3, r21
208         /* r3: BOOTFLAG */
209         bl      board_init_f    /* run 1st part of board init code (from Flash) */
210
211
212         .globl  _start_of_vectors
213 _start_of_vectors:
214
215 /* Machine check */
216         STD_EXCEPTION(0x200, MachineCheck, MachineCheckException)
217
218 /* Data Storage exception.  "Never" generated on the 860. */
219         STD_EXCEPTION(0x300, DataStorage, UnknownException)
220
221 /* Instruction Storage exception.  "Never" generated on the 860. */
222         STD_EXCEPTION(0x400, InstStorage, UnknownException)
223
224 /* External Interrupt exception. */
225         STD_EXCEPTION(0x500, ExtInterrupt, external_interrupt)
226
227 /* Alignment exception. */
228         . = 0x600
229 Alignment:
230         EXCEPTION_PROLOG
231         mfspr   r4,DAR
232         stw     r4,_DAR(r21)
233         mfspr   r5,DSISR
234         stw     r5,_DSISR(r21)
235         addi    r3,r1,STACK_FRAME_OVERHEAD
236         li      r20,MSR_KERNEL
237         rlwimi  r20,r23,0,16,16         /* copy EE bit from saved MSR */
238         lwz     r6,GOT(transfer_to_handler)
239         mtlr    r6
240         blrl
241 .L_Alignment:
242         .long   AlignmentException - _start + EXC_OFF_SYS_RESET
243         .long   int_return - _start + EXC_OFF_SYS_RESET
244
245 /* Program check exception */
246         . = 0x700
247 ProgramCheck:
248         EXCEPTION_PROLOG
249         addi    r3,r1,STACK_FRAME_OVERHEAD
250         li      r20,MSR_KERNEL
251         rlwimi  r20,r23,0,16,16         /* copy EE bit from saved MSR */
252         lwz     r6,GOT(transfer_to_handler)
253         mtlr    r6
254         blrl
255 .L_ProgramCheck:
256         .long   ProgramCheckException - _start + EXC_OFF_SYS_RESET
257         .long   int_return - _start + EXC_OFF_SYS_RESET
258
259         /* No FPU on MPC8xx.  This exception is not supposed to happen.
260         */
261         STD_EXCEPTION(0x800, FPUnavailable, UnknownException)
262
263         /* I guess we could implement decrementer, and may have
264          * to someday for timekeeping.
265          */
266         STD_EXCEPTION(0x900, Decrementer, timer_interrupt)
267         STD_EXCEPTION(0xa00, Trap_0a, UnknownException)
268         STD_EXCEPTION(0xb00, Trap_0b, UnknownException)
269
270         . = 0xc00
271 /*
272  * r0 - SYSCALL number
273  * r3-... arguments
274  */
275 SystemCall:
276         addis   r11,r0,0                /* get functions table addr */
277         ori     r11,r11,0               /* Note: this code is patched in trap_init */
278         addis   r12,r0,0                /* get number of functions */
279         ori     r12,r12,0
280
281         cmplw   0, r0, r12
282         bge     1f
283
284         rlwinm  r0,r0,2,0,31            /* fn_addr = fn_tbl[r0] */
285         add     r11,r11,r0
286         lwz     r11,0(r11)
287
288         li      r20,0xd00-4             /* Get stack pointer */
289         lwz     r12,0(r20)
290         subi    r12,r12,12              /* Adjust stack pointer */
291         li      r0,0xc00+_end_back-SystemCall
292         cmplw   0, r0, r12              /* Check stack overflow */
293         bgt     1f
294         stw     r12,0(r20)
295
296         mflr    r0
297         stw     r0,0(r12)
298         mfspr   r0,SRR0
299         stw     r0,4(r12)
300         mfspr   r0,SRR1
301         stw     r0,8(r12)
302
303         li      r12,0xc00+_back-SystemCall
304         mtlr    r12
305         mtspr   SRR0,r11
306
307 1:      SYNC
308         rfi
309
310 _back:
311
312         mfmsr   r11                     /* Disable interrupts */
313         li      r12,0
314         ori     r12,r12,MSR_EE
315         andc    r11,r11,r12
316         SYNC                            /* Some chip revs need this... */
317         mtmsr   r11
318         SYNC
319
320         li      r12,0xd00-4             /* restore regs */
321         lwz     r12,0(r12)
322
323         lwz     r11,0(r12)
324         mtlr    r11
325         lwz     r11,4(r12)
326         mtspr   SRR0,r11
327         lwz     r11,8(r12)
328         mtspr   SRR1,r11
329
330         addi    r12,r12,12              /* Adjust stack pointer */
331         li      r20,0xd00-4
332         stw     r12,0(r20)
333
334         SYNC
335         rfi
336 _end_back:
337
338         STD_EXCEPTION(0xd00, SingleStep, UnknownException)
339
340         STD_EXCEPTION(0xe00, Trap_0e, UnknownException)
341         STD_EXCEPTION(0xf00, Trap_0f, UnknownException)
342
343         /* On the MPC8xx, this is a software emulation interrupt.  It occurs
344          * for all unimplemented and illegal instructions.
345          */
346         STD_EXCEPTION(0x1000, SoftEmu, SoftEmuException)
347
348         STD_EXCEPTION(0x1100, InstructionTLBMiss, UnknownException)
349         STD_EXCEPTION(0x1200, DataTLBMiss, UnknownException)
350         STD_EXCEPTION(0x1300, InstructionTLBError, UnknownException)
351         STD_EXCEPTION(0x1400, DataTLBError, UnknownException)
352
353         STD_EXCEPTION(0x1500, Reserved5, UnknownException)
354         STD_EXCEPTION(0x1600, Reserved6, UnknownException)
355         STD_EXCEPTION(0x1700, Reserved7, UnknownException)
356         STD_EXCEPTION(0x1800, Reserved8, UnknownException)
357         STD_EXCEPTION(0x1900, Reserved9, UnknownException)
358         STD_EXCEPTION(0x1a00, ReservedA, UnknownException)
359         STD_EXCEPTION(0x1b00, ReservedB, UnknownException)
360
361         STD_EXCEPTION(0x1c00, DataBreakpoint, UnknownException)
362         STD_EXCEPTION(0x1d00, InstructionBreakpoint, DebugException)
363         STD_EXCEPTION(0x1e00, PeripheralBreakpoint, UnknownException)
364         STD_EXCEPTION(0x1f00, DevPortBreakpoint, UnknownException)
365
366
367         .globl  _end_of_vectors
368 _end_of_vectors:
369
370
371         . = 0x2000
372
373 /*
374  * This code finishes saving the registers to the exception frame
375  * and jumps to the appropriate handler for the exception.
376  * Register r21 is pointer into trap frame, r1 has new stack pointer.
377  */
378         .globl  transfer_to_handler
379 transfer_to_handler:
380         stw     r22,_NIP(r21)
381         lis     r22,MSR_POW@h
382         andc    r23,r23,r22
383         stw     r23,_MSR(r21)
384         SAVE_GPR(7, r21)
385         SAVE_4GPRS(8, r21)
386         SAVE_8GPRS(12, r21)
387         SAVE_8GPRS(24, r21)
388         mflr    r23
389         andi.   r24,r23,0x3f00          /* get vector offset */
390         stw     r24,TRAP(r21)
391         li      r22,0
392         stw     r22,RESULT(r21)
393         mtspr   SPRG2,r22               /* r1 is now kernel sp */
394         lwz     r24,0(r23)              /* virtual address of handler */
395         lwz     r23,4(r23)              /* where to go when done */
396         mtspr   SRR0,r24
397         mtspr   SRR1,r20
398         mtlr    r23
399         SYNC
400         rfi                             /* jump to handler, enable MMU */
401
402 int_return:
403         mfmsr   r28                     /* Disable interrupts */
404         li      r4,0
405         ori     r4,r4,MSR_EE
406         andc    r28,r28,r4
407         SYNC                            /* Some chip revs need this... */
408         mtmsr   r28
409         SYNC
410         lwz     r2,_CTR(r1)
411         lwz     r0,_LINK(r1)
412         mtctr   r2
413         mtlr    r0
414         lwz     r2,_XER(r1)
415         lwz     r0,_CCR(r1)
416         mtspr   XER,r2
417         mtcrf   0xFF,r0
418         REST_10GPRS(3, r1)
419         REST_10GPRS(13, r1)
420         REST_8GPRS(23, r1)
421         REST_GPR(31, r1)
422         lwz     r2,_NIP(r1)             /* Restore environment */
423         lwz     r0,_MSR(r1)
424         mtspr   SRR0,r2
425         mtspr   SRR1,r0
426         lwz     r0,GPR0(r1)
427         lwz     r2,GPR2(r1)
428         lwz     r1,GPR1(r1)
429         SYNC
430         rfi
431
432 /* Cache functions.
433 */
434         .globl  icache_enable
435 icache_enable:
436         SYNC
437         lis     r3, IDC_INVALL@h
438         mtspr   IC_CST, r3
439         lis     r3, IDC_ENABLE@h
440         mtspr   IC_CST, r3
441         blr
442
443         .globl  icache_disable
444 icache_disable:
445         SYNC
446         lis     r3, IDC_DISABLE@h
447         mtspr   IC_CST, r3
448         blr
449
450         .globl  icache_status
451 icache_status:
452         mfspr   r3, IC_CST
453         srwi    r3, r3, 31      /* >>31 => select bit 0 */
454         blr
455
456         .globl  dcache_enable
457 dcache_enable:
458 #if 0
459         SYNC
460 #endif
461 #if 1
462         lis     r3, 0x0400              /* Set cache mode with MMU off */
463         mtspr   MD_CTR, r3
464 #endif
465
466         lis     r3, IDC_INVALL@h
467         mtspr   DC_CST, r3
468 #if 0
469         lis     r3, DC_SFWT@h
470         mtspr   DC_CST, r3
471 #endif
472         lis     r3, IDC_ENABLE@h
473         mtspr   DC_CST, r3
474         blr
475
476         .globl  dcache_disable
477 dcache_disable:
478         SYNC
479         lis     r3, IDC_DISABLE@h
480         mtspr   DC_CST, r3
481         lis     r3, IDC_INVALL@h
482         mtspr   DC_CST, r3
483         blr
484
485         .globl  dcache_status
486 dcache_status:
487         mfspr   r3, DC_CST
488         srwi    r3, r3, 31      /* >>31 => select bit 0 */
489         blr
490
491         .globl  dc_read
492 dc_read:
493         mtspr   DC_ADR, r3
494         mfspr   r3, DC_DAT
495         blr
496
497 /*
498  * unsigned int get_immr (unsigned int mask)
499  *
500  * return (mask ? (IMMR & mask) : IMMR);
501  */
502         .globl  get_immr
503 get_immr:
504         mr      r4,r3           /* save mask */
505         mfspr   r3, IMMR        /* IMMR */
506         cmpwi   0,r4,0          /* mask != 0 ? */
507         beq     4f
508         and     r3,r3,r4        /* IMMR & mask */
509 4:
510         blr
511
512         .globl get_pvr
513 get_pvr:
514         mfspr   r3, PVR
515         blr
516
517
518         .globl wr_ic_cst
519 wr_ic_cst:
520         mtspr   IC_CST, r3
521         blr
522
523         .globl rd_ic_cst
524 rd_ic_cst:
525         mfspr   r3, IC_CST
526         blr
527
528         .globl wr_ic_adr
529 wr_ic_adr:
530         mtspr   IC_ADR, r3
531         blr
532
533
534         .globl wr_dc_cst
535 wr_dc_cst:
536         mtspr   DC_CST, r3
537         blr
538
539         .globl rd_dc_cst
540 rd_dc_cst:
541         mfspr   r3, DC_CST
542         blr
543
544         .globl wr_dc_adr
545 wr_dc_adr:
546         mtspr   DC_ADR, r3
547         blr
548
549 /*------------------------------------------------------------------------------*/
550
551 /*
552  * void relocate_code (addr_sp, gd, addr_moni)
553  *
554  * This "function" does not return, instead it continues in RAM
555  * after relocating the monitor code.
556  *
557  * r3 = dest
558  * r4 = src
559  * r5 = length in bytes
560  * r6 = cachelinesize
561  */
562         .globl  relocate_code
563 relocate_code:
564         mr      r1,  r3         /* Set new stack pointer                */
565         mr      r9,  r4         /* Save copy of Global Data pointer     */
566         mr      r10, r5         /* Save copy of Destination Address     */
567
568         mr      r3,  r5                         /* Destination Address  */
569         lis     r4, CFG_MONITOR_BASE@h          /* Source      Address  */
570         ori     r4, r4, CFG_MONITOR_BASE@l
571         lwz     r5, GOT(__init_end)
572         sub     r5, r5, r4
573         li      r6, CFG_CACHELINE_SIZE          /* Cache Line Size      */
574
575         /*
576          * Fix GOT pointer:
577          *
578          * New GOT-PTR = (old GOT-PTR - CFG_MONITOR_BASE) + Destination Address
579          *
580          * Offset:
581          */
582         sub     r15, r10, r4
583
584         /* First our own GOT */
585         add     r14, r14, r15
586         /* then the one used by the C code */
587         add     r30, r30, r15
588
589         /*
590          * Now relocate code
591          */
592
593         cmplw   cr1,r3,r4
594         addi    r0,r5,3
595         srwi.   r0,r0,2
596         beq     cr1,4f          /* In place copy is not necessary       */
597         beq     7f              /* Protect against 0 count              */
598         mtctr   r0
599         bge     cr1,2f
600
601         la      r8,-4(r4)
602         la      r7,-4(r3)
603 1:      lwzu    r0,4(r8)
604         stwu    r0,4(r7)
605         bdnz    1b
606         b       4f
607
608 2:      slwi    r0,r0,2
609         add     r8,r4,r0
610         add     r7,r3,r0
611 3:      lwzu    r0,-4(r8)
612         stwu    r0,-4(r7)
613         bdnz    3b
614
615 /*
616  * Now flush the cache: note that we must start from a cache aligned
617  * address. Otherwise we might miss one cache line.
618  */
619 4:      cmpwi   r6,0
620         add     r5,r3,r5
621         beq     7f              /* Always flush prefetch queue in any case */
622         subi    r0,r6,1
623         andc    r3,r3,r0
624         mr      r4,r3
625 5:      dcbst   0,r4
626         add     r4,r4,r6
627         cmplw   r4,r5
628         blt     5b
629         sync                    /* Wait for all dcbst to complete on bus */
630         mr      r4,r3
631 6:      icbi    0,r4
632         add     r4,r4,r6
633         cmplw   r4,r5
634         blt     6b
635 7:      sync                    /* Wait for all icbi to complete on bus */
636         isync
637
638 /*
639  * We are done. Do not return, instead branch to second part of board
640  * initialization, now running from RAM.
641  */
642
643         addi    r0, r10, in_ram - _start + EXC_OFF_SYS_RESET
644         mtlr    r0
645         blr
646
647 in_ram:
648
649         /*
650          * Relocation Function, r14 point to got2+0x8000
651          *
652          * Adjust got2 pointers, no need to check for 0, this code
653          * already puts a few entries in the table.
654          */
655         li      r0,__got2_entries@sectoff@l
656         la      r3,GOT(_GOT2_TABLE_)
657         lwz     r11,GOT(_GOT2_TABLE_)
658         mtctr   r0
659         sub     r11,r3,r11
660         addi    r3,r3,-4
661 1:      lwzu    r0,4(r3)
662         add     r0,r0,r11
663         stw     r0,0(r3)
664         bdnz    1b
665
666         /*
667          * Now adjust the fixups and the pointers to the fixups
668          * in case we need to move ourselves again.
669          */
670 2:      li      r0,__fixup_entries@sectoff@l
671         lwz     r3,GOT(_FIXUP_TABLE_)
672         cmpwi   r0,0
673         mtctr   r0
674         addi    r3,r3,-4
675         beq     4f
676 3:      lwzu    r4,4(r3)
677         lwzux   r0,r4,r11
678         add     r0,r0,r11
679         stw     r10,0(r3)
680         stw     r0,0(r4)
681         bdnz    3b
682 4:
683 clear_bss:
684         /*
685          * Now clear BSS segment
686          */
687         lwz     r3,GOT(__bss_start)
688 #if defined(CONFIG_FADS) || defined(CONFIG_ICU862)
689         /*
690          * For the FADS - the environment is the very last item in flash.
691          * The real .bss stops just before environment starts, so only
692          * clear up to that point.
693          */
694         lwz     r4,GOT(environment)
695 #else
696         lwz     r4,GOT(_end)
697 #endif
698
699         cmplw   0, r3, r4
700         beq     6f
701
702         li      r0, 0
703 5:
704         stw     r0, 0(r3)
705         addi    r3, r3, 4
706         cmplw   0, r3, r4
707         bne     5b
708 6:
709
710         mr      r3, r9          /* Global Data pointer          */
711         mr      r4, r10         /* Destination Address          */
712         bl      board_init_r
713
714         /*
715          * Copy exception vector code to low memory
716          *
717          * r3: dest_addr
718          * r7: source address, r8: end address, r9: target address
719          */
720         .globl  trap_init
721 trap_init:
722         lwz     r7, GOT(_start)
723         lwz     r8, GOT(_end_of_vectors)
724
725         li      r9, 0x100               /* reset vector always at 0x100 */
726
727         cmplw   0, r7, r8
728         bgelr                           /* return if r7>=r8 - just in case */
729
730         mflr    r4                      /* save link register           */
731 1:
732         lwz     r0, 0(r7)
733         stw     r0, 0(r9)
734         addi    r7, r7, 4
735         addi    r9, r9, 4
736         cmplw   0, r7, r8
737         bne     1b
738
739         /*
740          * relocate `hdlr' and `int_return' entries
741          */
742         li      r7, .L_MachineCheck - _start + EXC_OFF_SYS_RESET
743         li      r8, Alignment - _start + EXC_OFF_SYS_RESET
744 2:
745         bl      trap_reloc
746         addi    r7, r7, 0x100           /* next exception vector        */
747         cmplw   0, r7, r8
748         blt     2b
749
750         li      r7, .L_Alignment - _start + EXC_OFF_SYS_RESET
751         bl      trap_reloc
752
753         li      r7, .L_ProgramCheck - _start + EXC_OFF_SYS_RESET
754         bl      trap_reloc
755
756         li      r7, .L_FPUnavailable - _start + EXC_OFF_SYS_RESET
757         li      r8, SystemCall - _start + EXC_OFF_SYS_RESET
758 3:
759         bl      trap_reloc
760         addi    r7, r7, 0x100           /* next exception vector        */
761         cmplw   0, r7, r8
762         blt     3b
763
764         li      r7, .L_SingleStep - _start + EXC_OFF_SYS_RESET
765         li      r8, _end_of_vectors - _start + EXC_OFF_SYS_RESET
766 4:
767         bl      trap_reloc
768         addi    r7, r7, 0x100           /* next exception vector        */
769         cmplw   0, r7, r8
770         blt     4b
771
772         mtlr    r4                      /* restore link register        */
773         blr
774
775         /*
776          * Function: relocate entries for one exception vector
777          */
778 trap_reloc:
779         lwz     r0, 0(r7)               /* hdlr ...                     */
780         add     r0, r0, r3              /*  ... += dest_addr            */
781         stw     r0, 0(r7)
782
783         lwz     r0, 4(r7)               /* int_return ...               */
784         add     r0, r0, r3              /*  ... += dest_addr            */
785         stw     r0, 4(r7)
786
787         sync
788         isync
789
790         blr