source: rtems/c/src/lib/libbsp/powerpc/shared/bootloader/head.S @ 98afe31

4.104.114.84.95
Last change on this file since 98afe31 was f05b2ac, checked in by Ralf Corsepius <ralf.corsepius@…>, on 04/21/04 at 16:01:48

Remove duplicate white lines.

  • Property mode set to 100644
File size: 10.0 KB
Line 
1/*
2 *  head.S -- Bootloader Entry point
3 *
4 *  Copyright (C) 1998, 1999 Gabriel Paubert, paubert@iram.es
5 *
6 *  Modified to compile in RTEMS development environment
7 *  by Eric Valette
8 *
9 *  Copyright (C) 1999 Eric Valette. valette@crf.canon.fr
10 *
11 *  The license and distribution terms for this file may be
12 *  found in found in the file LICENSE in this distribution or at
13 *  http://www.rtems.com/license/LICENSE.
14 *
15 * $Id$
16 */
17
18#include <rtems/asm.h>
19#include <rtems/score/cpu.h>
20#include "bootldr.h"
21
22#define TEST_PPCBUG_CALLS
23#undef TEST_PPCBUG_CALLS
24
25#define FRAME_SIZE 32
26#define LOCK_CACHES (HID0_DLOCK | HID0_ILOCK)
27#define INVL_CACHES (HID0_DCI | HID0_ICFI)
28#define ENBL_CACHES (HID0_DCE | HID0_ICE)
29
30#define USE_PPCBUG
31
32#define PRINT_CHAR(c)           \
33        addi    r20,r3,0        ; \
34        li      r3,c            ; \
35        li      r10,0x20        ; \
36        sc                      ; \
37        addi    r3,r20,0        ; \
38        li      r10,0x26        ; \
39        sc
40
41#define MONITOR_ENTER                   \
42        mfmsr   r10             ;       \
43        ori     r10,r10,MSR_IP  ;       \
44        mtmsr   r10             ;       \
45        li      r10,0x63        ;       \
46        sc
47
48        START_GOT
49        GOT_ENTRY(_GOT2_TABLE_)
50        GOT_ENTRY(_FIXUP_TABLE_)
51        GOT_ENTRY(.bss)
52        GOT_ENTRY(codemove)
53        GOT_ENTRY(0)
54        GOT_ENTRY(__bd)
55        GOT_ENTRY(moved)
56        GOT_ENTRY(_binary_rtems_gz_start)
57        GOT_ENTRY(_binary_initrd_gz_start)
58        GOT_ENTRY(_binary_initrd_gz_end)
59#ifdef TEST_PPCBUG_CALLS
60        GOT_ENTRY(banner_start)
61        GOT_ENTRY(banner_end)
62#endif
63#ifdef USE_PPCBUG
64        GOT_ENTRY(nioc_reset_packet)
65#endif
66        END_GOT
67        .globl  start
68        .type   start,@function
69
70/* Point the stack into the PreP partition header in the x86 reserved
71 * code area, so that simple C routines can be called.
72 */
73start:
74#if defined(USE_PPCBUG) && defined(DEBUG) && defined(REENTER_MONITOR)
75        MONITOR_ENTER
76#endif
77        bl      1f
781:      mflr    r1
79        li      r0,0
80        stwu    r0,start-1b-0x400+0x1b0-FRAME_SIZE(r1)
81        stmw    r26,FRAME_SIZE-24(r1)
82        GET_GOT
83        mfmsr   r28                     /* Turn off interrupts */
84        ori     r0,r28,MSR_EE
85        xori    r0,r0,MSR_EE
86        mtmsr   r0
87
88/* Enable the caches, from now on cr2.eq set means processor is 601 */
89
90        mfpvr   r0
91        mfspr   r29,HID0
92        srwi    r0,r0,16
93        cmplwi  cr2,r0,1
94        beq     2,2f
95
96/*
97 * commented out, 11/7/2002, gregm.  This instruction sequence seems to
98 * be pathological on the 603e.
99 *
100
101#ifndef USE_PPCBUG
102        ori     r0,r29,ENBL_CACHES|INVL_CACHES|LOCK_CACHES
103        xori    r0,r0,INVL_CACHES|LOCK_CACHES
104        sync
105        isync
106        mtspr   HID0,r0
107#endif
108*/
109
1102:      bl      reloc
111
112/* save all the parameters and the orginal msr/hid0/r31 */
113        lwz     bd,GOT(__bd)
114        stw     r3,0(bd)
115        stw     r4,4(bd)
116        stw     r5,8(bd)
117        stw     r6,12(bd)
118        stw     r7,16(bd)
119        stw     r8,20(bd)
120        stw     r9,24(bd)
121        stw     r10,28(bd)
122        stw     r28,o_msr(bd)
123        stw     r29,o_hid0(bd)
124        stw     r31,o_r31(bd)
125
126#ifdef USE_PPCBUG
127/* Stop the network interface - otherwise, memory can get
128 * corrupted by the IF DMAing data into its old buffers or
129 * by writing descriptors...
130 */
131        lwz r3,GOT(nioc_reset_packet)
132        li  r10, 0x1d /* .NETCTRL */
133        sc
134#endif
135
136/* Call the routine to fill boot_data structure from residual data.
137 * And to find where the code has to be moved.
138 */
139        lis     r3,__size@sectoff@ha
140        addi    r3,r3,__size@sectoff@l
141        bl      early_setup
142
143/* Now we need to relocate ourselves, where we are told to. First put a
144 * copy of the codemove routine to some place in memory.
145 * (which may be where the 0x41 partition was loaded, so size is critical).
146 */
147        lwz     r4,GOT(codemove)
148        li      r5,_size_codemove
149        lwz     r3,mover(bd)
150        lwz     r6,cache_lsize(bd)
151
152        bl      codemove
153
154        mtctr   r3              # Where the temporary codemove is.
155        lwz     r3,image(bd)
156        lis     r5,_edata@sectoff@ha
157        lwz     r4,GOT(0)       # Our own address
158        addi    r5,r5,_edata@sectoff@l
159        lwz     r6,cache_lsize(bd)
160        lwz     r8,GOT(moved)
161
162        sub     r7,r3,r4        # Difference to adjust pointers.
163        add     r8,r8,r7
164        add     r30,r30,r7
165        add     bd,bd,r7
166
167/* Call the copy routine but return to the new area. */
168
169        mtlr    r8              # for the return address
170        bctr                    # returns to the moved instruction
171
172/* Establish the new top stack frame. */
173moved:  lwz     r1,stack(bd)
174        li      r0,0
175        stwu    r0,-16(r1)
176
177/* relocate again */
178        bl      reloc
179/* Clear all of BSS */
180        lwz     r10,GOT(.bss)
181        li      r0,__bss_words@sectoff@l
182        subi    r10,r10,4
183        cmpwi   r0,0
184        mtctr   r0
185        li      r0,0
186        beq     4f
1873:      stwu    r0,4(r10)
188        bdnz    3b
189
190/* Final memory initialization. First switch to unmapped mode
191 * in case the FW had set the MMU on, and flush the TLB to avoid
192 * stale entries from interfering. No I/O access is allowed
193 * during this time!
194 */
1954:
196#if defined(USE_PPCBUG) && defined(DEBUG)
197        PRINT_CHAR('M')
198#endif
199        bl      MMUoff
200
201#if defined(USE_PPCBUG) && defined(DEBUG)
202        PRINT_CHAR('B')
203#endif
204        bl      flush_tlb
205
206/* Some firmware versions leave stale values in the BATs, it's time
207 * to invalidate them to avoid interferences with our own mappings.
208 * But the 601 valid bit is in the BATL (IBAT only) and others are in
209 * the [ID]BATU. Bloat, bloat.. fortunately thrown away later.
210 */
211#if defined(USE_PPCBUG) && defined(DEBUG)
212        PRINT_CHAR('T')
213#endif
214        li      r3,0
215        beq     cr2,5f
216        mtdbatu 0,r3
217        mtdbatu 1,r3
218        mtdbatu 2,r3
219        mtdbatu 3,r3
2205:      mtibatu 0,r3
221        mtibatl 0,r3
222        mtibatu 1,r3
223        mtibatl 1,r3
224        mtibatu 2,r3
225        mtibatl 2,r3
226        mtibatu 3,r3
227        mtibatl 3,r3
228        lis     r3,__size@sectoff@ha
229        addi    r3,r3,__size@sectoff@l
230        sync                            # We are going to touch SDR1 !
231#if defined(USE_PPCBUG) && defined(DEBUG)
232        PRINT_CHAR('i')
233#endif
234        bl      mm_init
235
236#if defined(USE_PPCBUG) && defined(DEBUG)
237        PRINT_CHAR('M')
238#endif
239        bl      MMUon
240
241/* Now we are mapped and can perform I/O if we want */
242#ifdef TEST_PPCBUG_CALLS
243/* Experience seems to show that PPCBug can only be called with the
244 * data cache disabled and with MMU disabled. Bummer.
245 */
246        li      r10,0x22                # .OUTLN
247        lwz     r3,GOT(banner_start)
248        lwz     r4,GOT(banner_end)
249        sc
250#endif
251#if defined(USE_PPCBUG) && defined(DEBUG)
252        PRINT_CHAR('H')
253#endif
254        bl      setup_hw
255        lwz     r4,GOT(_binary_rtems_gz_start)
256        lis     r5,_rtems_gz_size@sectoff@ha
257        lwz     r6,GOT(_binary_initrd_gz_start)
258        lis     r3,_rtems_size@sectoff@ha
259        lwz     r7,GOT(_binary_initrd_gz_end)
260        addi    r5,r5,_rtems_gz_size@sectoff@l
261        addi    r3,r3,_rtems_size@sectoff@l
262        sub     r7,r7,r6
263        bl      decompress_kernel
264
265/* Back here we are unmapped and we start the kernel, passing up to eight
266 * parameters just in case, only r3 to r7 used for now. Flush the tlb so
267 * that the loaded image starts in a clean state.
268 */
269        bl      flush_tlb
270        lwz     r3,0(bd)
271        lwz     r4,4(bd)
272        lwz     r5,8(bd)
273        lwz     r6,12(bd)
274        lwz     r7,16(bd)
275        lwz     r8,20(bd)
276        lwz     r9,24(bd)
277        lwz     r10,28(bd)
278
279        lwz     r30,0(0)
280        mtctr   r30
281/*
282 *      Linux code again
283 *
284        lis     r30,0xdeadc0de@ha
285        addi    r30,r30,0xdeadc0de@l
286        stw     r30,0(0)
287        li      r30,0
288*/
289        dcbst   0,r30   /* Make sure it's in memory ! */
290
291/* We just flash invalidate and disable the dcache, unless it's a 601,
292 * critical areas have been flushed and we don't care about the stack
293 * and other scratch areas.
294 */
295        beq     cr2,1f
296        mfspr   r0,HID0
297        ori     r0,r0,HID0_DCI|HID0_DCE
298        sync
299        mtspr   HID0,r0
300        xori    r0,r0,HID0_DCI|HID0_DCE
301        mtspr   HID0,r0
302
303/* Provisional return to FW, works for PPCBug */
304#if 0 && defined(REENTER_MONITOR)
305        MONITOR_ENTER
306#else
3071:      bctr
308#endif
309
310/* relocation function, r30 must point to got2+0x8000 */
311reloc:
312/* Adjust got2 pointers, no need to check for 0, this code already puts
313 * a few entries in the table.
314 */
315        li      r0,__got2_entries@sectoff@l
316        la      r12,GOT(_GOT2_TABLE_)
317        lwz     r11,GOT(_GOT2_TABLE_)
318        mtctr   r0
319        sub     r11,r12,r11
320        addi    r12,r12,-4
3211:      lwzu    r0,4(r12)
322        add     r0,r0,r11
323        stw     r0,0(r12)
324        bdnz    1b
325
326/* Now adjust the fixups and the pointers to the fixups in case we need
327 * to move ourselves again.
328 */
3292:      li      r0,__fixup_entries@sectoff@l
330        lwz     r12,GOT(_FIXUP_TABLE_)
331        cmpwi   r0,0
332        mtctr   r0
333        addi    r12,r12,-4
334        beqlr
3353:      lwzu    r10,4(r12)
336        lwzux   r0,r10,r11
337        add     r0,r0,r11
338        stw     r10,0(r12)
339        stw     r0,0(r10)
340        bdnz    3b
341        blr
342
343/* Set the MMU on and off: code is always mapped 1:1 and does not need MMU,
344 * but it does not cost so much to map it also and it catches calls through
345 * NULL function pointers.
346 */
347        .globl  MMUon
348        .type   MMUon,@function
349MMUon:  blr
350        nop
351
352/*
353        mfmsr   r0
354        ori     r0,r0,MSR_IR|MSR_DR|MSR_IP
355        mflr    r11
356        xori    r0,r0,MSR_IP
357        mtsrr0  r11
358        mtsrr1  r0
359        rfi
360*/
361        .globl  MMUoff
362        .type   MMUoff,@function
363MMUoff: blr
364        nop
365
366/*
367        mfmsr   r0
368        ori     r0,r0,MSR_IR|MSR_DR|MSR_IP
369        mflr    r11
370        xori    r0,r0,MSR_IR|MSR_DR
371        mtsrr0  r11
372        mtsrr1  r0
373        rfi
374*/
375
376/* Due to the PPC architecture (and according to the specifications), a
377 * series of tlbie which goes through a whole 256 MB segment always flushes
378 * the whole TLB. This is obviously overkill and slow, but who cares ?
379 * It takes about 1 ms on a 200 MHz 603e and works even if residual data
380 * get the number of TLB entries wrong.
381 */
382flush_tlb:
383        lis     r11,0x1000
3841:      addic.  r11,r11,-0x1000
385        tlbie   r11
386        bnl     1b
387/* tlbsync is not implemented on 601, so use sync which seems to be a superset
388 * of tlbsync in all cases and do not bother with CPU dependant code
389 */
390        sync
391        blr
392
393        .globl  codemove
394codemove:
395        .type   codemove,@function
396/* r3 dest, r4 src, r5 length in bytes, r6 cachelinesize */
397        cmplw   cr1,r3,r4
398        addi    r0,r5,3
399        srwi.   r0,r0,2
400        beq     cr1,4f  /* In place copy is not necessary */
401        beq     7f      /* Protect against 0 count */
402        mtctr   r0
403        bge     cr1,2f
404
405        la      r8,-4(r4)
406        la      r7,-4(r3)
4071:      lwzu    r0,4(r8)
408        stwu    r0,4(r7)
409        bdnz    1b
410        b       4f
411
4122:      slwi    r0,r0,2
413        add     r8,r4,r0
414        add     r7,r3,r0
4153:      lwzu    r0,-4(r8)
416        stwu    r0,-4(r7)
417        bdnz    3b
418
419/* Now flush the cache: note that we must start from a cache aligned
420 * address. Otherwise we might miss one cache line.
421 */
4224:      cmpwi   r6,0
423        add     r5,r3,r5
424        beq     7f      /* Always flush prefetch queue in any case */
425        subi    r0,r6,1
426        andc    r3,r3,r0
427        mr      r4,r3
4285:      cmplw   r4,r5
429        dcbst   0,r4
430        add     r4,r4,r6
431        blt     5b
432        sync            /* Wait for all dcbst to complete on bus */
433        mr      r4,r3
4346:      cmplw   r4,r5
435        icbi    0,r4
436        add     r4,r4,r6
437        blt     6b
4387:      sync            /* Wait for all icbi to complete on bus */
439        isync
440        blr
441        .size   codemove,.-codemove
442_size_codemove=.-codemove
443
444        .section        ".data" # .rodata
445        .align 4
446#ifdef USE_PPCBUG
447/* A control 'packet' for the .NETCTRL PPCBug syscall to
448 * reset a network interface. Let's hope they used the
449 * first one for booting!! (CLUN/DLUN == 0/0)
450 * Must be 4-byte aligned...
451 */
452nioc_reset_packet:
453        .byte   0       /* Contoller LUN                                   */
454        .byte   0       /* Device LUN                                      */
455        .word   0   /* status return                                   */
456        .long   5       /* Command (5=RESET)                               */
457        .long   0   /* Mem. Addr. for real data (unused for reset)     */
458        .long   0   /* Number of bytes                                 */
459        .long   0   /* Status/Control Flags (unused for reset)         */
460#endif
461#ifdef TEST_PPCBUG_CALLS
462banner_start:
463        .ascii "This message was printed by PPCBug with MMU enabled"
464banner_end:
465#endif
Note: See TracBrowser for help on using the repository browser.