]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - cpu/mpc8xx/start.S
* Get (mostly) rid of CFG_MONITOR_LEN definition; compute real length
[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
213         .globl  _start_of_vectors
214 _start_of_vectors:
215
216 /* Machine check */
217         STD_EXCEPTION(0x200, MachineCheck, MachineCheckException)
218
219 /* Data Storage exception.  "Never" generated on the 860. */
220         STD_EXCEPTION(0x300, DataStorage, UnknownException)
221
222 /* Instruction Storage exception.  "Never" generated on the 860. */
223         STD_EXCEPTION(0x400, InstStorage, UnknownException)
224
225 /* External Interrupt exception. */
226         STD_EXCEPTION(0x500, ExtInterrupt, external_interrupt)
227
228 /* Alignment exception. */
229         . = 0x600
230 Alignment:
231         EXCEPTION_PROLOG
232         mfspr   r4,DAR
233         stw     r4,_DAR(r21)
234         mfspr   r5,DSISR
235         stw     r5,_DSISR(r21)
236         addi    r3,r1,STACK_FRAME_OVERHEAD
237         li      r20,MSR_KERNEL
238         rlwimi  r20,r23,0,16,16         /* copy EE bit from saved MSR */
239         lwz     r6,GOT(transfer_to_handler)
240         mtlr    r6
241         blrl
242 .L_Alignment:
243         .long   AlignmentException - _start + EXC_OFF_SYS_RESET
244         .long   int_return - _start + EXC_OFF_SYS_RESET
245
246 /* Program check exception */
247         . = 0x700
248 ProgramCheck:
249         EXCEPTION_PROLOG
250         addi    r3,r1,STACK_FRAME_OVERHEAD
251         li      r20,MSR_KERNEL
252         rlwimi  r20,r23,0,16,16         /* copy EE bit from saved MSR */
253         lwz     r6,GOT(transfer_to_handler)
254         mtlr    r6
255         blrl
256 .L_ProgramCheck:
257         .long   ProgramCheckException - _start + EXC_OFF_SYS_RESET
258         .long   int_return - _start + EXC_OFF_SYS_RESET
259
260         /* No FPU on MPC8xx.  This exception is not supposed to happen.
261         */
262         STD_EXCEPTION(0x800, FPUnavailable, UnknownException)
263
264         /* I guess we could implement decrementer, and may have
265          * to someday for timekeeping.
266          */
267         STD_EXCEPTION(0x900, Decrementer, timer_interrupt)
268         STD_EXCEPTION(0xa00, Trap_0a, UnknownException)
269         STD_EXCEPTION(0xb00, Trap_0b, UnknownException)
270
271         . = 0xc00
272 /*
273  * r0 - SYSCALL number
274  * r3-... arguments
275  */
276 SystemCall:
277         addis   r11,r0,0                /* get functions table addr */
278         ori     r11,r11,0               /* Note: this code is patched in trap_init */
279         addis   r12,r0,0                /* get number of functions */
280         ori     r12,r12,0
281
282         cmplw   0, r0, r12
283         bge     1f
284
285         rlwinm  r0,r0,2,0,31            /* fn_addr = fn_tbl[r0] */
286         add     r11,r11,r0
287         lwz     r11,0(r11)
288
289         li      r20,0xd00-4             /* Get stack pointer */
290         lwz     r12,0(r20)
291         subi    r12,r12,12              /* Adjust stack pointer */
292         li      r0,0xc00+_end_back-SystemCall
293         cmplw   0, r0, r12              /* Check stack overflow */
294         bgt     1f
295         stw     r12,0(r20)
296
297         mflr    r0
298         stw     r0,0(r12)
299         mfspr   r0,SRR0
300         stw     r0,4(r12)
301         mfspr   r0,SRR1
302         stw     r0,8(r12)
303
304         li      r12,0xc00+_back-SystemCall
305         mtlr    r12
306         mtspr   SRR0,r11
307
308 1:      SYNC
309         rfi
310
311 _back:
312
313         mfmsr   r11                     /* Disable interrupts */
314         li      r12,0
315         ori     r12,r12,MSR_EE
316         andc    r11,r11,r12
317         SYNC                            /* Some chip revs need this... */
318         mtmsr   r11
319         SYNC
320
321         li      r12,0xd00-4             /* restore regs */
322         lwz     r12,0(r12)
323
324         lwz     r11,0(r12)
325         mtlr    r11
326         lwz     r11,4(r12)
327         mtspr   SRR0,r11
328         lwz     r11,8(r12)
329         mtspr   SRR1,r11
330
331         addi    r12,r12,12              /* Adjust stack pointer */
332         li      r20,0xd00-4
333         stw     r12,0(r20)
334
335         SYNC
336         rfi
337 _end_back:
338
339         STD_EXCEPTION(0xd00, SingleStep, UnknownException)
340
341         STD_EXCEPTION(0xe00, Trap_0e, UnknownException)
342         STD_EXCEPTION(0xf00, Trap_0f, UnknownException)
343
344         /* On the MPC8xx, this is a software emulation interrupt.  It occurs
345          * for all unimplemented and illegal instructions.
346          */
347         STD_EXCEPTION(0x1000, SoftEmu, SoftEmuException)
348
349         STD_EXCEPTION(0x1100, InstructionTLBMiss, UnknownException)
350         STD_EXCEPTION(0x1200, DataTLBMiss, UnknownException)
351         STD_EXCEPTION(0x1300, InstructionTLBError, UnknownException)
352         STD_EXCEPTION(0x1400, DataTLBError, UnknownException)
353
354         STD_EXCEPTION(0x1500, Reserved5, UnknownException)
355         STD_EXCEPTION(0x1600, Reserved6, UnknownException)
356         STD_EXCEPTION(0x1700, Reserved7, UnknownException)
357         STD_EXCEPTION(0x1800, Reserved8, UnknownException)
358         STD_EXCEPTION(0x1900, Reserved9, UnknownException)
359         STD_EXCEPTION(0x1a00, ReservedA, UnknownException)
360         STD_EXCEPTION(0x1b00, ReservedB, UnknownException)
361
362         STD_EXCEPTION(0x1c00, DataBreakpoint, UnknownException)
363         STD_EXCEPTION(0x1d00, InstructionBreakpoint, DebugException)
364         STD_EXCEPTION(0x1e00, PeripheralBreakpoint, UnknownException)
365         STD_EXCEPTION(0x1f00, DevPortBreakpoint, UnknownException)
366
367
368         .globl  _end_of_vectors
369 _end_of_vectors:
370
371
372         . = 0x2000
373
374 /*
375  * This code finishes saving the registers to the exception frame
376  * and jumps to the appropriate handler for the exception.
377  * Register r21 is pointer into trap frame, r1 has new stack pointer.
378  */
379         .globl  transfer_to_handler
380 transfer_to_handler:
381         stw     r22,_NIP(r21)
382         lis     r22,MSR_POW@h
383         andc    r23,r23,r22
384         stw     r23,_MSR(r21)
385         SAVE_GPR(7, r21)
386         SAVE_4GPRS(8, r21)
387         SAVE_8GPRS(12, r21)
388         SAVE_8GPRS(24, r21)
389         mflr    r23
390         andi.   r24,r23,0x3f00          /* get vector offset */
391         stw     r24,TRAP(r21)
392         li      r22,0
393         stw     r22,RESULT(r21)
394         mtspr   SPRG2,r22               /* r1 is now kernel sp */
395         lwz     r24,0(r23)              /* virtual address of handler */
396         lwz     r23,4(r23)              /* where to go when done */
397         mtspr   SRR0,r24
398         mtspr   SRR1,r20
399         mtlr    r23
400         SYNC
401         rfi                             /* jump to handler, enable MMU */
402
403 int_return:
404         mfmsr   r28                     /* Disable interrupts */
405         li      r4,0
406         ori     r4,r4,MSR_EE
407         andc    r28,r28,r4
408         SYNC                            /* Some chip revs need this... */
409         mtmsr   r28
410         SYNC
411         lwz     r2,_CTR(r1)
412         lwz     r0,_LINK(r1)
413         mtctr   r2
414         mtlr    r0
415         lwz     r2,_XER(r1)
416         lwz     r0,_CCR(r1)
417         mtspr   XER,r2
418         mtcrf   0xFF,r0
419         REST_10GPRS(3, r1)
420         REST_10GPRS(13, r1)
421         REST_8GPRS(23, r1)
422         REST_GPR(31, r1)
423         lwz     r2,_NIP(r1)             /* Restore environment */
424         lwz     r0,_MSR(r1)
425         mtspr   SRR0,r2
426         mtspr   SRR1,r0
427         lwz     r0,GPR0(r1)
428         lwz     r2,GPR2(r1)
429         lwz     r1,GPR1(r1)
430         SYNC
431         rfi
432
433 /* Cache functions.
434 */
435         .globl  icache_enable
436 icache_enable:
437         SYNC
438         lis     r3, IDC_INVALL@h
439         mtspr   IC_CST, r3
440         lis     r3, IDC_ENABLE@h
441         mtspr   IC_CST, r3
442         blr
443
444         .globl  icache_disable
445 icache_disable:
446         SYNC
447         lis     r3, IDC_DISABLE@h
448         mtspr   IC_CST, r3
449         blr
450
451         .globl  icache_status
452 icache_status:
453         mfspr   r3, IC_CST
454         srwi    r3, r3, 31      /* >>31 => select bit 0 */
455         blr
456
457         .globl  dcache_enable
458 dcache_enable:
459 #if 0
460         SYNC
461 #endif
462 #if 1
463         lis     r3, 0x0400              /* Set cache mode with MMU off */
464         mtspr   MD_CTR, r3
465 #endif
466
467         lis     r3, IDC_INVALL@h
468         mtspr   DC_CST, r3
469 #if 0
470         lis     r3, DC_SFWT@h
471         mtspr   DC_CST, r3
472 #endif
473         lis     r3, IDC_ENABLE@h
474         mtspr   DC_CST, r3
475         blr
476
477         .globl  dcache_disable
478 dcache_disable:
479         SYNC
480         lis     r3, IDC_DISABLE@h
481         mtspr   DC_CST, r3
482         lis     r3, IDC_INVALL@h
483         mtspr   DC_CST, r3
484         blr
485
486         .globl  dcache_status
487 dcache_status:
488         mfspr   r3, DC_CST
489         srwi    r3, r3, 31      /* >>31 => select bit 0 */
490         blr
491
492         .globl  dc_read
493 dc_read:
494         mtspr   DC_ADR, r3
495         mfspr   r3, DC_DAT
496         blr
497
498 /*
499  * unsigned int get_immr (unsigned int mask)
500  *
501  * return (mask ? (IMMR & mask) : IMMR);
502  */
503         .globl  get_immr
504 get_immr:
505         mr      r4,r3           /* save mask */
506         mfspr   r3, IMMR        /* IMMR */
507         cmpwi   0,r4,0          /* mask != 0 ? */
508         beq     4f
509         and     r3,r3,r4        /* IMMR & mask */
510 4:
511         blr
512
513         .globl get_pvr
514 get_pvr:
515         mfspr   r3, PVR
516         blr
517
518
519         .globl wr_ic_cst
520 wr_ic_cst:
521         mtspr   IC_CST, r3
522         blr
523
524         .globl rd_ic_cst
525 rd_ic_cst:
526         mfspr   r3, IC_CST
527         blr
528
529         .globl wr_ic_adr
530 wr_ic_adr:
531         mtspr   IC_ADR, r3
532         blr
533
534
535         .globl wr_dc_cst
536 wr_dc_cst:
537         mtspr   DC_CST, r3
538         blr
539
540         .globl rd_dc_cst
541 rd_dc_cst:
542         mfspr   r3, DC_CST
543         blr
544
545         .globl wr_dc_adr
546 wr_dc_adr:
547         mtspr   DC_ADR, r3
548         blr
549
550 /*------------------------------------------------------------------------------*/
551
552 /*
553  * void relocate_code (addr_sp, gd, addr_moni)
554  *
555  * This "function" does not return, instead it continues in RAM
556  * after relocating the monitor code.
557  *
558  * r3 = dest
559  * r4 = src
560  * r5 = length in bytes
561  * r6 = cachelinesize
562  */
563         .globl  relocate_code
564 relocate_code:
565         mr      r1,  r3         /* Set new stack pointer                */
566         mr      r9,  r4         /* Save copy of Global Data pointer     */
567         mr      r10, r5         /* Save copy of Destination Address     */
568
569         mr      r3,  r5                         /* Destination Address  */
570         lis     r4, CFG_MONITOR_BASE@h          /* Source      Address  */
571         ori     r4, r4, CFG_MONITOR_BASE@l
572         lwz     r5, GOT(__init_end)
573         sub     r5, r5, r4
574         li      r6, CFG_CACHELINE_SIZE          /* Cache Line Size      */
575
576         /*
577          * Fix GOT pointer:
578          *
579          * New GOT-PTR = (old GOT-PTR - CFG_MONITOR_BASE) + Destination Address
580          *
581          * Offset:
582          */
583         sub     r15, r10, r4
584
585         /* First our own GOT */
586         add     r14, r14, r15
587         /* then the one used by the C code */
588         add     r30, r30, r15
589
590         /*
591          * Now relocate code
592          */
593
594         cmplw   cr1,r3,r4
595         addi    r0,r5,3
596         srwi.   r0,r0,2
597         beq     cr1,4f          /* In place copy is not necessary       */
598         beq     7f              /* Protect against 0 count              */
599         mtctr   r0
600         bge     cr1,2f
601
602         la      r8,-4(r4)
603         la      r7,-4(r3)
604 1:      lwzu    r0,4(r8)
605         stwu    r0,4(r7)
606         bdnz    1b
607         b       4f
608
609 2:      slwi    r0,r0,2
610         add     r8,r4,r0
611         add     r7,r3,r0
612 3:      lwzu    r0,-4(r8)
613         stwu    r0,-4(r7)
614         bdnz    3b
615
616 /*
617  * Now flush the cache: note that we must start from a cache aligned
618  * address. Otherwise we might miss one cache line.
619  */
620 4:      cmpwi   r6,0
621         add     r5,r3,r5
622         beq     7f              /* Always flush prefetch queue in any case */
623         subi    r0,r6,1
624         andc    r3,r3,r0
625         mr      r4,r3
626 5:      dcbst   0,r4
627         add     r4,r4,r6
628         cmplw   r4,r5
629         blt     5b
630         sync                    /* Wait for all dcbst to complete on bus */
631         mr      r4,r3
632 6:      icbi    0,r4
633         add     r4,r4,r6
634         cmplw   r4,r5
635         blt     6b
636 7:      sync                    /* Wait for all icbi to complete on bus */
637         isync
638
639 /*
640  * We are done. Do not return, instead branch to second part of board
641  * initialization, now running from RAM.
642  */
643
644         addi    r0, r10, in_ram - _start + EXC_OFF_SYS_RESET
645         mtlr    r0
646         blr
647
648 in_ram:
649
650         /*
651          * Relocation Function, r14 point to got2+0x8000
652          *
653          * Adjust got2 pointers, no need to check for 0, this code
654          * already puts a few entries in the table.
655          */
656         li      r0,__got2_entries@sectoff@l
657         la      r3,GOT(_GOT2_TABLE_)
658         lwz     r11,GOT(_GOT2_TABLE_)
659         mtctr   r0
660         sub     r11,r3,r11
661         addi    r3,r3,-4
662 1:      lwzu    r0,4(r3)
663         add     r0,r0,r11
664         stw     r0,0(r3)
665         bdnz    1b
666
667         /*
668          * Now adjust the fixups and the pointers to the fixups
669          * in case we need to move ourselves again.
670          */
671 2:      li      r0,__fixup_entries@sectoff@l
672         lwz     r3,GOT(_FIXUP_TABLE_)
673         cmpwi   r0,0
674         mtctr   r0
675         addi    r3,r3,-4
676         beq     4f
677 3:      lwzu    r4,4(r3)
678         lwzux   r0,r4,r11
679         add     r0,r0,r11
680         stw     r10,0(r3)
681         stw     r0,0(r4)
682         bdnz    3b
683 4:
684 clear_bss:
685         /*
686          * Now clear BSS segment
687          */
688         lwz     r3,GOT(__bss_start)
689 #if defined(CONFIG_FADS) || defined(CONFIG_ICU862)
690         /*
691          * For the FADS - the environment is the very last item in flash.
692          * The real .bss stops just before environment starts, so only
693          * clear up to that point.
694          */
695         lwz     r4,GOT(environment)
696 #else
697         lwz     r4,GOT(_end)
698 #endif
699
700         cmplw   0, r3, r4
701         beq     6f
702
703         li      r0, 0
704 5:
705         stw     r0, 0(r3)
706         addi    r3, r3, 4
707         cmplw   0, r3, r4
708         bne     5b
709 6:
710
711         mr      r3, r9          /* Global Data pointer          */
712         mr      r4, r10         /* Destination Address          */
713         bl      board_init_r
714
715         /*
716          * Copy exception vector code to low memory
717          *
718          * r3: dest_addr
719          * r7: source address, r8: end address, r9: target address
720          */
721         .globl  trap_init
722 trap_init:
723         lwz     r7, GOT(_start)
724         lwz     r8, GOT(_end_of_vectors)
725
726         rlwinm  r9, r7, 0, 22, 31       /* _start & 0x3FF       */
727
728         cmplw   0, r7, r8
729         bgelr                           /* return if r7>=r8 - just in case */
730
731         mflr    r4                      /* save link register           */
732 1:
733         lwz     r0, 0(r7)
734         stw     r0, 0(r9)
735         addi    r7, r7, 4
736         addi    r9, r9, 4
737         cmplw   0, r7, r8
738         bne     1b
739
740         /*
741          * relocate `hdlr' and `int_return' entries
742          */
743         li      r7, .L_MachineCheck - _start + EXC_OFF_SYS_RESET
744         li      r8, Alignment - _start + EXC_OFF_SYS_RESET
745 2:
746         bl      trap_reloc
747         addi    r7, r7, 0x100           /* next exception vector        */
748         cmplw   0, r7, r8
749         blt     2b
750
751         li      r7, .L_Alignment - _start + EXC_OFF_SYS_RESET
752         bl      trap_reloc
753
754         li      r7, .L_ProgramCheck - _start + EXC_OFF_SYS_RESET
755         bl      trap_reloc
756
757         li      r7, .L_FPUnavailable - _start + EXC_OFF_SYS_RESET
758         li      r8, SystemCall - _start + EXC_OFF_SYS_RESET
759 3:
760         bl      trap_reloc
761         addi    r7, r7, 0x100           /* next exception vector        */
762         cmplw   0, r7, r8
763         blt     3b
764
765         li      r7, .L_SingleStep - _start + EXC_OFF_SYS_RESET
766         li      r8, _end_of_vectors - _start + EXC_OFF_SYS_RESET
767 4:
768         bl      trap_reloc
769         addi    r7, r7, 0x100           /* next exception vector        */
770         cmplw   0, r7, r8
771         blt     4b
772
773         mtlr    r4                      /* restore link register        */
774         blr
775
776         /*
777          * Function: relocate entries for one exception vector
778          */
779 trap_reloc:
780         lwz     r0, 0(r7)               /* hdlr ...                     */
781         add     r0, r0, r3              /*  ... += dest_addr            */
782         stw     r0, 0(r7)
783
784         lwz     r0, 4(r7)               /* int_return ...               */
785         add     r0, r0, r3              /*  ... += dest_addr            */
786         stw     r0, 4(r7)
787
788         sync
789         isync
790
791         blr