* Patch by Gleb Natapov, 14 Sep 2003:
[platform/kernel/u-boot.git] / cpu / mpc5xxx / 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 - 2003 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 /*
26  *  U-Boot - Startup Code for MPC5xxx CPUs
27  */
28 #include <config.h>
29 #include <mpc5xxx.h>
30 #include <version.h>
31
32 #define CONFIG_MPC5XXX 1        /* needed for Linux kernel header files */
33 #define _LINUX_CONFIG_H 1       /* avoid reading Linux autoconf.h file  */
34
35 #include <ppc_asm.tmpl>
36 #include <ppc_defs.h>
37
38 #include <asm/cache.h>
39 #include <asm/mmu.h>
40
41 #ifndef  CONFIG_IDENT_STRING
42 #define  CONFIG_IDENT_STRING ""
43 #endif
44
45 /* We don't want the  MMU yet.
46 */
47 #undef  MSR_KERNEL
48 /* Floating Point enable, Machine Check and Recoverable Interr. */
49 #ifdef DEBUG
50 #define MSR_KERNEL (MSR_FP|MSR_RI)
51 #else
52 #define MSR_KERNEL (MSR_FP|MSR_ME|MSR_RI)
53 #endif
54
55 /*
56  * Set up GOT: Global Offset Table
57  *
58  * Use r14 to access the GOT
59  */
60         START_GOT
61         GOT_ENTRY(_GOT2_TABLE_)
62         GOT_ENTRY(_FIXUP_TABLE_)
63
64         GOT_ENTRY(_start)
65         GOT_ENTRY(_start_of_vectors)
66         GOT_ENTRY(_end_of_vectors)
67         GOT_ENTRY(transfer_to_handler)
68
69         GOT_ENTRY(__init_end)
70         GOT_ENTRY(_end)
71         GOT_ENTRY(__bss_start)
72         END_GOT
73
74 /*
75  * Version string
76  */
77         .data
78         .globl  version_string
79 version_string:
80         .ascii U_BOOT_VERSION
81         .ascii " (", __DATE__, " - ", __TIME__, ")"
82         .ascii CONFIG_IDENT_STRING, "\0"
83
84 /*
85  * Exception vectors
86  */
87         .text
88         . = EXC_OFF_SYS_RESET
89         .globl  _start
90 _start:
91         li      r21, BOOTFLAG_COLD      /* Normal Power-On              */
92         nop
93         b       boot_cold
94
95         . = EXC_OFF_SYS_RESET + 0x10
96
97         .globl  _start_warm
98 _start_warm:
99         li      r21, BOOTFLAG_WARM      /* Software reboot              */
100         b       boot_warm
101
102 boot_cold:
103 boot_warm:
104         mfmsr   r5                      /* save msr contents            */
105
106 #if defined(CFG_DEFAULT_MBAR) && !defined(CFG_RAMBOOT)
107         lis     r3, CFG_MBAR@h
108         ori     r3, r3, CFG_MBAR@l
109 #if defined(CONFIG_MPC5200)
110         rlwinm  r3, r3, 16, 16, 31
111 #endif
112 #if defined(CONFIG_MGT5100)
113         rlwinm  r3, r3, 17, 15, 31
114 #endif
115         lis     r4, CFG_DEFAULT_MBAR@h
116         stw     r3, 0(r4)
117 #endif /* CFG_DEFAULT_MBAR */
118
119         /* Initialise the MPC5xxx processor core                        */
120         /*--------------------------------------------------------------*/
121
122         bl      init_5xxx_core
123
124         /* initialize some things that are hard to access from C        */
125         /*--------------------------------------------------------------*/
126
127         /* set up stack in on-chip SRAM */
128         lis     r3, CFG_INIT_RAM_ADDR@h
129         ori     r3, r3, CFG_INIT_RAM_ADDR@l
130         ori     r1, r3, CFG_INIT_SP_OFFSET
131         li      r0, 0                   /* Make room for stack frame header and */
132         stwu    r0, -4(r1)              /* clear final stack frame so that      */
133         stwu    r0, -4(r1)              /* stack backtraces terminate cleanly   */
134
135         /* let the C-code set up the rest                               */
136         /*                                                              */
137         /* Be careful to keep code relocatable !                        */
138         /*--------------------------------------------------------------*/
139
140         GET_GOT                 /* initialize GOT access                */
141
142         /* r3: IMMR */
143         bl      cpu_init_f      /* run low-level CPU init code (in Flash)*/
144
145         mr      r3, r21
146         /* r3: BOOTFLAG */
147         bl      board_init_f    /* run 1st part of board init code (in Flash)*/
148
149 /*
150  * Vector Table
151  */
152
153         .globl  _start_of_vectors
154 _start_of_vectors:
155
156 /* Machine check */
157         STD_EXCEPTION(0x200, MachineCheck, MachineCheckException)
158
159 /* Data Storage exception. */
160         STD_EXCEPTION(0x300, DataStorage, UnknownException)
161
162 /* Instruction Storage exception. */
163         STD_EXCEPTION(0x400, InstStorage, UnknownException)
164
165 /* External Interrupt exception. */
166         STD_EXCEPTION(0x500, ExtInterrupt, external_interrupt)
167
168 /* Alignment exception. */
169         . = 0x600
170 Alignment:
171         EXCEPTION_PROLOG
172         mfspr   r4,DAR
173         stw     r4,_DAR(r21)
174         mfspr   r5,DSISR
175         stw     r5,_DSISR(r21)
176         addi    r3,r1,STACK_FRAME_OVERHEAD
177         li      r20,MSR_KERNEL
178         rlwimi  r20,r23,0,16,16         /* copy EE bit from saved MSR */
179         rlwimi  r20,r23,0,25,25         /* copy IP bit from saved MSR */
180         lwz     r6,GOT(transfer_to_handler)
181         mtlr    r6
182         blrl
183 .L_Alignment:
184         .long   AlignmentException - _start + EXC_OFF_SYS_RESET
185         .long   int_return - _start + EXC_OFF_SYS_RESET
186
187 /* Program check exception */
188         . = 0x700
189 ProgramCheck:
190         EXCEPTION_PROLOG
191         addi    r3,r1,STACK_FRAME_OVERHEAD
192         li      r20,MSR_KERNEL
193         rlwimi  r20,r23,0,16,16         /* copy EE bit from saved MSR */
194         rlwimi  r20,r23,0,25,25         /* copy IP bit from saved MSR */
195         lwz     r6,GOT(transfer_to_handler)
196         mtlr    r6
197         blrl
198 .L_ProgramCheck:
199         .long   ProgramCheckException - _start + EXC_OFF_SYS_RESET
200         .long   int_return - _start + EXC_OFF_SYS_RESET
201
202         STD_EXCEPTION(0x800, FPUnavailable, UnknownException)
203
204         /* I guess we could implement decrementer, and may have
205          * to someday for timekeeping.
206          */
207         STD_EXCEPTION(0x900, Decrementer, timer_interrupt)
208
209         STD_EXCEPTION(0xa00, Trap_0a, UnknownException)
210         STD_EXCEPTION(0xb00, Trap_0b, UnknownException)
211         STD_EXCEPTION(0xc00, SystemCall, UnknownException)
212         STD_EXCEPTION(0xd00, SingleStep, UnknownException)
213
214         STD_EXCEPTION(0xe00, Trap_0e, UnknownException)
215         STD_EXCEPTION(0xf00, Trap_0f, UnknownException)
216
217         STD_EXCEPTION(0x1000, InstructionTLBMiss, UnknownException)
218         STD_EXCEPTION(0x1100, DataLoadTLBMiss, UnknownException)
219         STD_EXCEPTION(0x1200, DataStoreTLBMiss, UnknownException)
220 #ifdef DEBUG
221         . = 0x1300
222         /*
223          * This exception occurs when the program counter matches the
224          * Instruction Address Breakpoint Register (IABR).
225          *
226          * I want the cpu to halt if this occurs so I can hunt around
227          * with the debugger and look at things.
228          *
229          * When DEBUG is defined, both machine check enable (in the MSR)
230          * and checkstop reset enable (in the reset mode register) are
231          * turned off and so a checkstop condition will result in the cpu
232          * halting.
233          *
234          * I force the cpu into a checkstop condition by putting an illegal
235          * instruction here (at least this is the theory).
236          *
237          * well - that didnt work, so just do an infinite loop!
238          */
239 1:      b       1b
240 #else
241         STD_EXCEPTION(0x1300, InstructionBreakpoint, DebugException)
242 #endif
243         STD_EXCEPTION(0x1400, SMI, UnknownException)
244
245         STD_EXCEPTION(0x1500, Trap_15, UnknownException)
246         STD_EXCEPTION(0x1600, Trap_16, UnknownException)
247         STD_EXCEPTION(0x1700, Trap_17, UnknownException)
248         STD_EXCEPTION(0x1800, Trap_18, UnknownException)
249         STD_EXCEPTION(0x1900, Trap_19, UnknownException)
250         STD_EXCEPTION(0x1a00, Trap_1a, UnknownException)
251         STD_EXCEPTION(0x1b00, Trap_1b, UnknownException)
252         STD_EXCEPTION(0x1c00, Trap_1c, UnknownException)
253         STD_EXCEPTION(0x1d00, Trap_1d, UnknownException)
254         STD_EXCEPTION(0x1e00, Trap_1e, UnknownException)
255         STD_EXCEPTION(0x1f00, Trap_1f, UnknownException)
256         STD_EXCEPTION(0x2000, Trap_20, UnknownException)
257         STD_EXCEPTION(0x2100, Trap_21, UnknownException)
258         STD_EXCEPTION(0x2200, Trap_22, UnknownException)
259         STD_EXCEPTION(0x2300, Trap_23, UnknownException)
260         STD_EXCEPTION(0x2400, Trap_24, UnknownException)
261         STD_EXCEPTION(0x2500, Trap_25, UnknownException)
262         STD_EXCEPTION(0x2600, Trap_26, UnknownException)
263         STD_EXCEPTION(0x2700, Trap_27, UnknownException)
264         STD_EXCEPTION(0x2800, Trap_28, UnknownException)
265         STD_EXCEPTION(0x2900, Trap_29, UnknownException)
266         STD_EXCEPTION(0x2a00, Trap_2a, UnknownException)
267         STD_EXCEPTION(0x2b00, Trap_2b, UnknownException)
268         STD_EXCEPTION(0x2c00, Trap_2c, UnknownException)
269         STD_EXCEPTION(0x2d00, Trap_2d, UnknownException)
270         STD_EXCEPTION(0x2e00, Trap_2e, UnknownException)
271         STD_EXCEPTION(0x2f00, Trap_2f, UnknownException)
272
273
274         .globl  _end_of_vectors
275 _end_of_vectors:
276
277         . = 0x3000
278
279 /*
280  * This code finishes saving the registers to the exception frame
281  * and jumps to the appropriate handler for the exception.
282  * Register r21 is pointer into trap frame, r1 has new stack pointer.
283  */
284         .globl  transfer_to_handler
285 transfer_to_handler:
286         stw     r22,_NIP(r21)
287         lis     r22,MSR_POW@h
288         andc    r23,r23,r22
289         stw     r23,_MSR(r21)
290         SAVE_GPR(7, r21)
291         SAVE_4GPRS(8, r21)
292         SAVE_8GPRS(12, r21)
293         SAVE_8GPRS(24, r21)
294         mflr    r23
295         andi.   r24,r23,0x3f00          /* get vector offset */
296         stw     r24,TRAP(r21)
297         li      r22,0
298         stw     r22,RESULT(r21)
299         lwz     r24,0(r23)              /* virtual address of handler */
300         lwz     r23,4(r23)              /* where to go when done */
301         mtspr   SRR0,r24
302         mtspr   SRR1,r20
303         mtlr    r23
304         SYNC
305         rfi                             /* jump to handler, enable MMU */
306
307 int_return:
308         mfmsr   r28             /* Disable interrupts */
309         li      r4,0
310         ori     r4,r4,MSR_EE
311         andc    r28,r28,r4
312         SYNC                    /* Some chip revs need this... */
313         mtmsr   r28
314         SYNC
315         lwz     r2,_CTR(r1)
316         lwz     r0,_LINK(r1)
317         mtctr   r2
318         mtlr    r0
319         lwz     r2,_XER(r1)
320         lwz     r0,_CCR(r1)
321         mtspr   XER,r2
322         mtcrf   0xFF,r0
323         REST_10GPRS(3, r1)
324         REST_10GPRS(13, r1)
325         REST_8GPRS(23, r1)
326         REST_GPR(31, r1)
327         lwz     r2,_NIP(r1)     /* Restore environment */
328         lwz     r0,_MSR(r1)
329         mtspr   SRR0,r2
330         mtspr   SRR1,r0
331         lwz     r0,GPR0(r1)
332         lwz     r2,GPR2(r1)
333         lwz     r1,GPR1(r1)
334         SYNC
335         rfi
336
337 /*
338  * This code initialises the MPC5xxx processor core
339  * (conforms to PowerPC 603e spec)
340  * Note: expects original MSR contents to be in r5.
341  */
342
343         .globl  init_5xx_core
344 init_5xxx_core:
345
346         /* Initialize machine status; enable machine check interrupt    */
347         /*--------------------------------------------------------------*/
348
349         li      r3, MSR_KERNEL          /* Set ME and RI flags */
350         rlwimi  r3, r5, 0, 25, 25       /* preserve IP bit set by HRCW */
351 #ifdef DEBUG
352         rlwimi  r3, r5, 0, 21, 22       /* debugger might set SE & BE bits */
353 #endif
354         SYNC                            /* Some chip revs need this... */
355         mtmsr   r3
356         SYNC
357         mtspr   SRR1, r3                /* Make SRR1 match MSR */
358
359         /* Initialize the Hardware Implementation-dependent Registers   */
360         /* HID0 also contains cache control                             */
361         /*--------------------------------------------------------------*/
362
363         lis     r3, CFG_HID0_INIT@h
364         ori     r3, r3, CFG_HID0_INIT@l
365         SYNC
366         mtspr   HID0, r3
367
368         lis     r3, CFG_HID0_FINAL@h
369         ori     r3, r3, CFG_HID0_FINAL@l
370         SYNC
371         mtspr   HID0, r3
372
373         /* clear all BAT's                                              */
374         /*--------------------------------------------------------------*/
375
376         li      r0, 0
377         mtspr   DBAT0U, r0
378         mtspr   DBAT0L, r0
379         mtspr   DBAT1U, r0
380         mtspr   DBAT1L, r0
381         mtspr   DBAT2U, r0
382         mtspr   DBAT2L, r0
383         mtspr   DBAT3U, r0
384         mtspr   DBAT3L, r0
385         mtspr   DBAT4U, r0
386         mtspr   DBAT4L, r0
387         mtspr   DBAT5U, r0
388         mtspr   DBAT5L, r0
389         mtspr   DBAT6U, r0
390         mtspr   DBAT6L, r0
391         mtspr   DBAT7U, r0
392         mtspr   DBAT7L, r0
393         mtspr   IBAT0U, r0
394         mtspr   IBAT0L, r0
395         mtspr   IBAT1U, r0
396         mtspr   IBAT1L, r0
397         mtspr   IBAT2U, r0
398         mtspr   IBAT2L, r0
399         mtspr   IBAT3U, r0
400         mtspr   IBAT3L, r0
401         mtspr   IBAT4U, r0
402         mtspr   IBAT4L, r0
403         mtspr   IBAT5U, r0
404         mtspr   IBAT5L, r0
405         mtspr   IBAT6U, r0
406         mtspr   IBAT6L, r0
407         mtspr   IBAT7U, r0
408         mtspr   IBAT7L, r0
409         SYNC
410
411         /* invalidate all tlb's                                         */
412         /*                                                              */
413         /* From the 603e User Manual: "The 603e provides the ability to */
414         /* invalidate a TLB entry. The TLB Invalidate Entry (tlbie)     */
415         /* instruction invalidates the TLB entry indexed by the EA, and */
416         /* operates on both the instruction and data TLBs simultaneously*/
417         /* invalidating four TLB entries (both sets in each TLB). The   */
418         /* index corresponds to bits 15-19 of the EA. To invalidate all */
419         /* entries within both TLBs, 32 tlbie instructions should be    */
420         /* issued, incrementing this field by one each time."           */
421         /*                                                              */
422         /* "Note that the tlbia instruction is not implemented on the   */
423         /* 603e."                                                       */
424         /*                                                              */
425         /* bits 15-19 correspond to addresses 0x00000000 to 0x0001F000  */
426         /* incrementing by 0x1000 each time. The code below is sort of  */
427         /* based on code in "flush_tlbs" from arch/ppc/kernel/head.S    */
428         /*                                                              */
429         /*--------------------------------------------------------------*/
430
431         li      r3, 32
432         mtctr   r3
433         li      r3, 0
434 1:      tlbie   r3
435         addi    r3, r3, 0x1000
436         bdnz    1b
437         SYNC
438
439         /* Done!                                                        */
440         /*--------------------------------------------------------------*/
441
442         blr
443
444 /* Cache functions.
445  *
446  * Note: requires that all cache bits in
447  * HID0 are in the low half word.
448  */
449         .globl  icache_enable
450 icache_enable:
451         mfspr   r3, HID0
452         ori     r3, r3, HID0_ICE
453         lis     r4, 0
454         ori     r4, r4, HID0_ILOCK
455         andc    r3, r3, r4
456         ori     r4, r3, HID0_ICFI
457         isync
458         mtspr   HID0, r4        /* sets enable and invalidate, clears lock */
459         isync
460         mtspr   HID0, r3        /* clears invalidate */
461         blr
462
463         .globl  icache_disable
464 icache_disable:
465         mfspr   r3, HID0
466         lis     r4, 0
467         ori     r4, r4, HID0_ICE|HID0_ILOCK
468         andc    r3, r3, r4
469         ori     r4, r3, HID0_ICFI
470         isync
471         mtspr   HID0, r4        /* sets invalidate, clears enable and lock */
472         isync
473         mtspr   HID0, r3        /* clears invalidate */
474         blr
475
476         .globl  icache_status
477 icache_status:
478         mfspr   r3, HID0
479         rlwinm  r3, r3, HID0_ICE_BITPOS + 1, 31, 31
480         blr
481
482         .globl  dcache_enable
483 dcache_enable:
484         mfspr   r3, HID0
485         ori     r3, r3, HID0_DCE
486         lis     r4, 0
487         ori     r4, r4, HID0_DLOCK
488         andc    r3, r3, r4
489         ori     r4, r3, HID0_DCI
490         sync
491         mtspr   HID0, r4        /* sets enable and invalidate, clears lock */
492         sync
493         mtspr   HID0, r3        /* clears invalidate */
494         blr
495
496         .globl  dcache_disable
497 dcache_disable:
498         mfspr   r3, HID0
499         lis     r4, 0
500         ori     r4, r4, HID0_DCE|HID0_DLOCK
501         andc    r3, r3, r4
502         ori     r4, r3, HID0_DCI
503         sync
504         mtspr   HID0, r4        /* sets invalidate, clears enable and lock */
505         sync
506         mtspr   HID0, r3        /* clears invalidate */
507         blr
508
509         .globl  dcache_status
510 dcache_status:
511         mfspr   r3, HID0
512         rlwinm  r3, r3, HID0_DCE_BITPOS + 1, 31, 31
513         blr
514
515         .globl get_pvr
516 get_pvr:
517         mfspr   r3, PVR
518         blr
519
520 /*------------------------------------------------------------------------------*/
521
522 /*
523  * void relocate_code (addr_sp, gd, addr_moni)
524  *
525  * This "function" does not return, instead it continues in RAM
526  * after relocating the monitor code.
527  *
528  * r3 = dest
529  * r4 = src
530  * r5 = length in bytes
531  * r6 = cachelinesize
532  */
533         .globl  relocate_code
534 relocate_code:
535         mr      r1,  r3         /* Set new stack pointer                */
536         mr      r9,  r4         /* Save copy of Global Data pointer     */
537         mr      r10, r5         /* Save copy of Destination Address     */
538
539         mr      r3,  r5                         /* Destination Address  */
540         lis     r4, CFG_MONITOR_BASE@h          /* Source      Address  */
541         ori     r4, r4, CFG_MONITOR_BASE@l
542         lwz     r5, GOT(__init_end)
543         sub     r5, r5, r4
544         li      r6, CFG_CACHELINE_SIZE          /* Cache Line Size      */
545
546         /*
547          * Fix GOT pointer:
548          *
549          * New GOT-PTR = (old GOT-PTR - CFG_MONITOR_BASE) + Destination Address
550          *
551          * Offset:
552          */
553         sub     r15, r10, r4
554
555         /* First our own GOT */
556         add     r14, r14, r15
557         /* then the one used by the C code */
558         add     r30, r30, r15
559
560         /*
561          * Now relocate code
562          */
563
564         cmplw   cr1,r3,r4
565         addi    r0,r5,3
566         srwi.   r0,r0,2
567         beq     cr1,4f          /* In place copy is not necessary       */
568         beq     7f              /* Protect against 0 count              */
569         mtctr   r0
570         bge     cr1,2f
571
572         la      r8,-4(r4)
573         la      r7,-4(r3)
574 1:      lwzu    r0,4(r8)
575         stwu    r0,4(r7)
576         bdnz    1b
577         b       4f
578
579 2:      slwi    r0,r0,2
580         add     r8,r4,r0
581         add     r7,r3,r0
582 3:      lwzu    r0,-4(r8)
583         stwu    r0,-4(r7)
584         bdnz    3b
585
586 /*
587  * Now flush the cache: note that we must start from a cache aligned
588  * address. Otherwise we might miss one cache line.
589  */
590 4:      cmpwi   r6,0
591         add     r5,r3,r5
592         beq     7f              /* Always flush prefetch queue in any case */
593         subi    r0,r6,1
594         andc    r3,r3,r0
595         mfspr   r7,HID0         /* don't do dcbst if dcache is disabled */
596         rlwinm  r7,r7,HID0_DCE_BITPOS+1,31,31
597         cmpwi   r7,0
598         beq     9f
599         mr      r4,r3
600 5:      dcbst   0,r4
601         add     r4,r4,r6
602         cmplw   r4,r5
603         blt     5b
604         sync                    /* Wait for all dcbst to complete on bus */
605 9:      mfspr   r7,HID0         /* don't do icbi if icache is disabled */
606         rlwinm  r7,r7,HID0_ICE_BITPOS+1,31,31
607         cmpwi   r7,0
608         beq     7f
609         mr      r4,r3
610 6:      icbi    0,r4
611         add     r4,r4,r6
612         cmplw   r4,r5
613         blt     6b
614 7:      sync                    /* Wait for all icbi to complete on bus */
615         isync
616
617 /*
618  * We are done. Do not return, instead branch to second part of board
619  * initialization, now running from RAM.
620  */
621
622         addi    r0, r10, in_ram - _start + EXC_OFF_SYS_RESET
623         mtlr    r0
624         blr
625
626 in_ram:
627
628         /*
629          * Relocation Function, r14 point to got2+0x8000
630          *
631          * Adjust got2 pointers, no need to check for 0, this code
632          * already puts a few entries in the table.
633          */
634         li      r0,__got2_entries@sectoff@l
635         la      r3,GOT(_GOT2_TABLE_)
636         lwz     r11,GOT(_GOT2_TABLE_)
637         mtctr   r0
638         sub     r11,r3,r11
639         addi    r3,r3,-4
640 1:      lwzu    r0,4(r3)
641         add     r0,r0,r11
642         stw     r0,0(r3)
643         bdnz    1b
644
645         /*
646          * Now adjust the fixups and the pointers to the fixups
647          * in case we need to move ourselves again.
648          */
649 2:      li      r0,__fixup_entries@sectoff@l
650         lwz     r3,GOT(_FIXUP_TABLE_)
651         cmpwi   r0,0
652         mtctr   r0
653         addi    r3,r3,-4
654         beq     4f
655 3:      lwzu    r4,4(r3)
656         lwzux   r0,r4,r11
657         add     r0,r0,r11
658         stw     r10,0(r3)
659         stw     r0,0(r4)
660         bdnz    3b
661 4:
662 clear_bss:
663         /*
664          * Now clear BSS segment
665          */
666         lwz     r3,GOT(__bss_start)
667         lwz     r4,GOT(_end)
668
669         cmplw   0, r3, r4
670         beq     6f
671
672         li      r0, 0
673 5:
674         stw     r0, 0(r3)
675         addi    r3, r3, 4
676         cmplw   0, r3, r4
677         bne     5b
678 6:
679
680         mr      r3, r9          /* Global Data pointer          */
681         mr      r4, r10         /* Destination Address          */
682         bl      board_init_r
683
684         /*
685          * Copy exception vector code to low memory
686          *
687          * r3: dest_addr
688          * r7: source address, r8: end address, r9: target address
689          */
690         .globl  trap_init
691 trap_init:
692         lwz     r7, GOT(_start)
693         lwz     r8, GOT(_end_of_vectors)
694
695         li      r9, 0x100               /* reset vector always at 0x100 */
696
697         cmplw   0, r7, r8
698         bgelr                           /* return if r7>=r8 - just in case */
699
700         mflr    r4                      /* save link register           */
701 1:
702         lwz     r0, 0(r7)
703         stw     r0, 0(r9)
704         addi    r7, r7, 4
705         addi    r9, r9, 4
706         cmplw   0, r7, r8
707         bne     1b
708
709         /*
710          * relocate `hdlr' and `int_return' entries
711          */
712         li      r7, .L_MachineCheck - _start + EXC_OFF_SYS_RESET
713         li      r8, Alignment - _start + EXC_OFF_SYS_RESET
714 2:
715         bl      trap_reloc
716         addi    r7, r7, 0x100           /* next exception vector        */
717         cmplw   0, r7, r8
718         blt     2b
719
720         li      r7, .L_Alignment - _start + EXC_OFF_SYS_RESET
721         bl      trap_reloc
722
723         li      r7, .L_ProgramCheck - _start + EXC_OFF_SYS_RESET
724         bl      trap_reloc
725
726         li      r7, .L_FPUnavailable - _start + EXC_OFF_SYS_RESET
727         li      r8, SystemCall - _start + EXC_OFF_SYS_RESET
728 3:
729         bl      trap_reloc
730         addi    r7, r7, 0x100           /* next exception vector        */
731         cmplw   0, r7, r8
732         blt     3b
733
734         li      r7, .L_SingleStep - _start + EXC_OFF_SYS_RESET
735         li      r8, _end_of_vectors - _start + EXC_OFF_SYS_RESET
736 4:
737         bl      trap_reloc
738         addi    r7, r7, 0x100           /* next exception vector        */
739         cmplw   0, r7, r8
740         blt     4b
741
742         mfmsr   r3                      /* now that the vectors have    */
743         lis     r7, MSR_IP@h            /* relocated into low memory    */
744         ori     r7, r7, MSR_IP@l        /* MSR[IP] can be turned off    */
745         andc    r3, r3, r7              /* (if it was on)               */
746         SYNC                            /* Some chip revs need this... */
747         mtmsr   r3
748         SYNC
749
750         mtlr    r4                      /* restore link register    */
751         blr
752
753         /*
754          * Function: relocate entries for one exception vector
755          */
756 trap_reloc:
757         lwz     r0, 0(r7)               /* hdlr ...                     */
758         add     r0, r0, r3              /*  ... += dest_addr            */
759         stw     r0, 0(r7)
760
761         lwz     r0, 4(r7)               /* int_return ...               */
762         add     r0, r0, r3              /*  ... += dest_addr            */
763         stw     r0, 4(r7)
764
765         blr