source: rtems/bsps/powerpc/motorola_powerpc/bootloader/head.S @ eb36d11

5
Last change on this file since eb36d11 was 03e1d837, checked in by Sebastian Huber <sebastian.huber@…>, on 04/24/18 at 05:06:36

bsps/powerpc: Move bootloader to bsps

This bootloader is only used by the motorola_powerpc BSP.

This patch is a part of the BSP source reorganization.

Update #3285.

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