Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:54

0001 /*
0002  *  head.S -- Bootloader Entry point
0003  *
0004  *  Copyright (C) 1998, 1999 Gabriel Paubert, paubert@iram.es
0005  *
0006  *  Modified to compile in RTEMS development environment
0007  *  by Eric Valette
0008  *
0009  *  Copyright (C) 1999 Eric Valette. valette@crf.canon.fr
0010  *
0011  *  The license and distribution terms for this file may be
0012  *  found in the file LICENSE in this distribution or at
0013  *  http://www.rtems.org/license/LICENSE.
0014  */
0015 
0016 #include <rtems/asm.h>
0017 #include <rtems/score/cpu.h>
0018 #include "bootldr.h"
0019 #include <bspopts.h>
0020 
0021 #define TEST_PPCBUG_CALLS
0022 #undef TEST_PPCBUG_CALLS
0023 
0024 #define FRAME_SIZE 32
0025 #define LOCK_CACHES (HID0_DLOCK | HID0_ILOCK)
0026 #define INVL_CACHES (HID0_DCI | HID0_ICFI)
0027 #define ENBL_CACHES (HID0_DCE | HID0_ICE)
0028 
0029 #ifndef qemu
0030 #define USE_PPCBUG
0031 #endif
0032 
0033 #define PRINT_CHAR(c)       \
0034     addi    r20,r3,0    ; \
0035     li  r3,c        ; \
0036     li  r10,0x20    ; \
0037     sc          ; \
0038     addi    r3,r20,0    ; \
0039     li  r10,0x26    ; \
0040     sc
0041 
0042 #define MONITOR_ENTER           \
0043     mfmsr   r10     ;   \
0044     ori r10,r10,MSR_IP  ;   \
0045     mtmsr   r10     ;   \
0046     li  r10,0x63    ;   \
0047     sc
0048 
0049     START_GOT
0050     GOT_ENTRY(_GOT2_TABLE_)
0051     GOT_ENTRY(_FIXUP_TABLE_)
0052     GOT_ENTRY(.bss)
0053     GOT_ENTRY(codemove)
0054     GOT_ENTRY(0)
0055     GOT_ENTRY(__bd)
0056     GOT_ENTRY(moved)
0057     GOT_ENTRY(_binary_rtems_gz_start)
0058     GOT_ENTRY(_binary_initrd_gz_start)
0059     GOT_ENTRY(_binary_initrd_gz_end)
0060 #ifdef TEST_PPCBUG_CALLS
0061     GOT_ENTRY(banner_start)
0062     GOT_ENTRY(banner_end)
0063 #endif
0064 #ifdef USE_PPCBUG
0065     GOT_ENTRY(nioc_reset_packet)
0066 #endif
0067     END_GOT
0068     .globl  start
0069     .type   start,@function
0070 
0071 /* Point the stack into the PreP partition header in the x86 reserved
0072  * code area, so that simple C routines can be called.
0073  */
0074 start:
0075 #if defined(USE_PPCBUG) && defined(DEBUG) && defined(REENTER_MONITOR)
0076     MONITOR_ENTER
0077 #endif
0078     bl  1f
0079 1:  mflr    r1
0080     li  r0,0
0081     stwu    r0,start-1b-0x400+0x1b0-FRAME_SIZE(r1)
0082     stmw    r26,FRAME_SIZE-24(r1)
0083     GET_GOT
0084     mfmsr   r28         /* Turn off interrupts */
0085     ori r0,r28,MSR_EE
0086     xori    r0,r0,MSR_EE
0087     mtmsr   r0
0088 
0089 /* Enable the caches, from now on cr2.eq set means processor is 601 */
0090 
0091     mfpvr   r0
0092     mfspr   r29,HID0
0093     srwi    r0,r0,16
0094     cmplwi  cr2,r0,1
0095     beq 2,2f
0096 
0097 /*
0098  * commented out, 11/7/2002, gregm.  This instruction sequence seems to
0099  * be pathological on the 603e.
0100  *
0101 
0102 #ifndef USE_PPCBUG
0103     ori r0,r29,ENBL_CACHES|INVL_CACHES|LOCK_CACHES
0104     xori    r0,r0,INVL_CACHES|LOCK_CACHES
0105     sync
0106     isync
0107     mtspr   HID0,r0
0108 #endif
0109 */
0110 
0111 2:  bl  reloc
0112 
0113 /* save all the parameters and the orginal msr/hid0/r31 */
0114     lwz bd,GOT(__bd)
0115     stw r3,0(bd)
0116     stw r4,4(bd)
0117     stw r5,8(bd)
0118     stw r6,12(bd)
0119     stw r7,16(bd)
0120     stw r8,20(bd)
0121     stw r9,24(bd)
0122     stw r10,28(bd)
0123     stw r28,o_msr(bd)
0124     stw r29,o_hid0(bd)
0125     stw r31,o_r31(bd)
0126 
0127 #ifdef USE_PPCBUG
0128 /* Stop the network interface - otherwise, memory can get
0129  * corrupted by the IF DMAing data into its old buffers or
0130  * by writing descriptors...
0131  */
0132     lwz r3,GOT(nioc_reset_packet)
0133     li  r10, 0x1d /* .NETCTRL */
0134     sc
0135 #endif
0136 
0137 /* Call the routine to fill boot_data structure from residual data.
0138  * And to find where the code has to be moved.
0139  */
0140     lis r3,__size@sectoff@ha
0141     addi    r3,r3,__size@sectoff@l
0142     bl  early_setup
0143 
0144 /* Now we need to relocate ourselves, where we are told to. First put a
0145  * copy of the codemove routine to some place in memory.
0146  * (which may be where the 0x41 partition was loaded, so size is critical).
0147  */
0148     lwz r4,GOT(codemove)
0149     li  r5,_size_codemove
0150     lwz r3,mover(bd)
0151     lwz r6,cache_lsize(bd)
0152 
0153     bl  codemove
0154 
0155     mtctr   r3      # Where the temporary codemove is.
0156     lwz r3,image(bd)
0157     lis r5,_edata@sectoff@ha
0158     lwz r4,GOT(0)   # Our own address
0159     addi    r5,r5,_edata@sectoff@l
0160     lwz r6,cache_lsize(bd)
0161     lwz r8,GOT(moved)
0162 
0163     sub r7,r3,r4    # Difference to adjust pointers.
0164     add r8,r8,r7
0165     add r30,r30,r7
0166     add bd,bd,r7
0167 
0168 /* Call the copy routine but return to the new area. */
0169 
0170     mtlr    r8      # for the return address
0171     bctr            # returns to the moved instruction
0172 
0173 /* Establish the new top stack frame. */
0174 moved:  lwz r1,stack(bd)
0175     li  r0,0
0176     stwu    r0,-16(r1)
0177 
0178 /* relocate again */
0179     bl  reloc
0180 /* Clear all of BSS */
0181     lwz r10,GOT(.bss)
0182     li  r0,__bss_words@sectoff@l
0183     subi    r10,r10,4
0184     cmpwi   r0,0
0185     mtctr   r0
0186     li  r0,0
0187     beq 4f
0188 3:  stwu    r0,4(r10)
0189     bdnz    3b
0190 
0191 /* Final memory initialization. First switch to unmapped mode
0192  * in case the FW had set the MMU on, and flush the TLB to avoid
0193  * stale entries from interfering. No I/O access is allowed
0194  * during this time!
0195  */
0196 4:
0197 #if defined(USE_PPCBUG) && defined(DEBUG)
0198     PRINT_CHAR('M')
0199 #endif
0200     bl  MMUoff
0201 
0202 #if defined(USE_PPCBUG) && defined(DEBUG)
0203     PRINT_CHAR('B')
0204 #endif
0205     bl  flush_tlb
0206 
0207 /* Some firmware versions leave stale values in the BATs, it's time
0208  * to invalidate them to avoid interferences with our own mappings.
0209  * But the 601 valid bit is in the BATL (IBAT only) and others are in
0210  * the [ID]BATU. Bloat, bloat.. fortunately thrown away later.
0211  */
0212 #if defined(USE_PPCBUG) && defined(DEBUG)
0213     PRINT_CHAR('T')
0214 #endif
0215     li  r3,0
0216     beq cr2,5f
0217     mtdbatu 0,r3
0218     mtdbatu 1,r3
0219     mtdbatu 2,r3
0220     mtdbatu 3,r3
0221 5:  mtibatu 0,r3
0222     mtibatl 0,r3
0223     mtibatu 1,r3
0224     mtibatl 1,r3
0225     mtibatu 2,r3
0226     mtibatl 2,r3
0227     mtibatu 3,r3
0228     mtibatl 3,r3
0229     lis r3,__size@sectoff@ha
0230     addi    r3,r3,__size@sectoff@l
0231     sync                # We are going to touch SDR1 !
0232 #if defined(USE_PPCBUG) && defined(DEBUG)
0233     PRINT_CHAR('i')
0234 #endif
0235     bl  mm_init
0236 
0237 #if defined(USE_PPCBUG) && defined(DEBUG)
0238     PRINT_CHAR('M')
0239 #endif
0240     bl  MMUon
0241 
0242 /* Now we are mapped and can perform I/O if we want */
0243 #ifdef TEST_PPCBUG_CALLS
0244 /* Experience seems to show that PPCBug can only be called with the
0245  * data cache disabled and with MMU disabled. Bummer.
0246  */
0247     li  r10,0x22        # .OUTLN
0248     lwz r3,GOT(banner_start)
0249     lwz r4,GOT(banner_end)
0250     sc
0251 #endif
0252 #if defined(USE_PPCBUG) && defined(DEBUG)
0253     PRINT_CHAR('H')
0254 #endif
0255     bl  setup_hw
0256     lwz r4,GOT(_binary_rtems_gz_start)
0257     lis r5,_rtems_gz_size@sectoff@ha
0258     lwz r6,GOT(_binary_initrd_gz_start)
0259     lis r3,_rtems_size@sectoff@ha
0260     lwz r7,GOT(_binary_initrd_gz_end)
0261     addi    r5,r5,_rtems_gz_size@sectoff@l
0262     addi    r3,r3,_rtems_size@sectoff@l
0263     sub r7,r7,r6
0264     bl  decompress_kernel
0265 
0266 /* Back here we are unmapped and we start the kernel, passing up to eight
0267  * parameters just in case, only r3 to r7 used for now. Flush the tlb so
0268  * that the loaded image starts in a clean state.
0269  */
0270     bl  flush_tlb
0271     lwz r3,0(bd)
0272     lwz r4,4(bd)
0273     lwz r5,8(bd)
0274     lwz r6,12(bd)
0275     lwz r7,16(bd)
0276     lwz r8,20(bd)
0277     lwz r9,24(bd)
0278     lwz r10,28(bd)
0279 
0280     lwz r30,0(0)
0281     mtctr   r30
0282 /*
0283  *  Linux code again
0284  *
0285     lis r30,0xdeadc0de@ha
0286     addi    r30,r30,0xdeadc0de@l
0287     stw r30,0(0)
0288     li  r30,0
0289 */
0290     dcbst   0,r30   /* Make sure it's in memory ! */
0291 
0292 /* We just flash invalidate and disable the dcache, unless it's a 601,
0293  * critical areas have been flushed and we don't care about the stack
0294  * and other scratch areas.
0295  */
0296     beq cr2,1f
0297     mfspr   r0,HID0
0298     ori r0,r0,HID0_DCI|HID0_DCE
0299     sync
0300     mtspr   HID0,r0
0301     xori    r0,r0,HID0_DCI|HID0_DCE
0302     mtspr   HID0,r0
0303 
0304 /* Provisional return to FW, works for PPCBug */
0305 #if 0 && defined(REENTER_MONITOR)
0306     MONITOR_ENTER
0307 #else
0308 1:  bctr
0309 #endif
0310 
0311 /* relocation function, r30 must point to got2+0x8000 */
0312 reloc:
0313 /* Adjust got2 pointers, no need to check for 0, this code already puts
0314  * a few entries in the table.
0315  */
0316     li  r0,__got2_entries@sectoff@l
0317     la  r12,GOT(_GOT2_TABLE_)
0318     lwz r11,GOT(_GOT2_TABLE_)
0319     mtctr   r0
0320     sub r11,r12,r11
0321     addi    r12,r12,-4
0322 1:  lwzu    r0,4(r12)
0323     add r0,r0,r11
0324     stw r0,0(r12)
0325     bdnz    1b
0326 
0327 /* Now adjust the fixups and the pointers to the fixups in case we need
0328  * to move ourselves again.
0329  */
0330 2:  li  r0,__fixup_entries@sectoff@l
0331     lwz r12,GOT(_FIXUP_TABLE_)
0332     cmpwi   r0,0
0333     mtctr   r0
0334     addi    r12,r12,-4
0335     beqlr
0336 3:  lwzu    r10,4(r12)
0337     lwzux   r0,r10,r11
0338     add r0,r0,r11
0339     stw r10,0(r12)
0340     stw r0,0(r10)
0341     bdnz    3b
0342     blr
0343 
0344 /* Set the MMU on and off: code is always mapped 1:1 and does not need MMU,
0345  * but it does not cost so much to map it also and it catches calls through
0346  * NULL function pointers.
0347  */
0348     .globl  MMUon
0349     .type   MMUon,@function
0350 MMUon:  blr
0351     nop
0352 
0353 /*
0354     mfmsr   r0
0355     ori r0,r0,MSR_IR|MSR_DR|MSR_IP
0356     mflr    r11
0357     xori    r0,r0,MSR_IP
0358     mtsrr0  r11
0359     mtsrr1  r0
0360     rfi
0361 */
0362     .globl  MMUoff
0363     .type   MMUoff,@function
0364 MMUoff: blr
0365     nop
0366 
0367 /*
0368     mfmsr   r0
0369     ori r0,r0,MSR_IR|MSR_DR|MSR_IP
0370     mflr    r11
0371     xori    r0,r0,MSR_IR|MSR_DR
0372     mtsrr0  r11
0373     mtsrr1  r0
0374     rfi
0375 */
0376 
0377 /* Due to the PPC architecture (and according to the specifications), a
0378  * series of tlbie which goes through a whole 256 MB segment always flushes
0379  * the whole TLB. This is obviously overkill and slow, but who cares ?
0380  * It takes about 1 ms on a 200 MHz 603e and works even if residual data
0381  * get the number of TLB entries wrong.
0382  */
0383 flush_tlb:
0384     lis r11,0x1000
0385 1:  addic.  r11,r11,-0x1000
0386     tlbie   r11, 0
0387     bnl 1b
0388 /* tlbsync is not implemented on 601, so use sync which seems to be a superset
0389  * of tlbsync in all cases and do not bother with CPU dependant code
0390  */
0391     sync
0392     blr
0393 
0394     .globl  codemove
0395 codemove:
0396     .type   codemove,@function
0397 /* r3 dest, r4 src, r5 length in bytes, r6 cachelinesize */
0398     cmplw   cr1,r3,r4
0399     addi    r0,r5,3
0400     srwi.   r0,r0,2
0401     beq cr1,4f  /* In place copy is not necessary */
0402     beq 7f  /* Protect against 0 count */
0403     mtctr   r0
0404     bge cr1,2f
0405 
0406     la  r8,-4(r4)
0407     la  r7,-4(r3)
0408 1:  lwzu    r0,4(r8)
0409     stwu    r0,4(r7)
0410     bdnz    1b
0411     b   4f
0412 
0413 2:  slwi    r0,r0,2
0414     add r8,r4,r0
0415     add r7,r3,r0
0416 3:  lwzu    r0,-4(r8)
0417     stwu    r0,-4(r7)
0418     bdnz    3b
0419 
0420 /* Now flush the cache: note that we must start from a cache aligned
0421  * address. Otherwise we might miss one cache line.
0422  */
0423 4:  cmpwi   r6,0
0424     add r5,r3,r5
0425     beq 7f  /* Always flush prefetch queue in any case */
0426     subi    r0,r6,1
0427     andc    r3,r3,r0
0428     mr  r4,r3
0429 5:  cmplw   r4,r5
0430     dcbst   0,r4
0431     add r4,r4,r6
0432     blt 5b
0433     sync        /* Wait for all dcbst to complete on bus */
0434     mr  r4,r3
0435 6:  cmplw   r4,r5
0436     icbi    0,r4
0437     add r4,r4,r6
0438     blt 6b
0439 7:  sync        /* Wait for all icbi to complete on bus */
0440     isync
0441     blr
0442     .size   codemove,.-codemove
0443 _size_codemove=.-codemove
0444 
0445     .section        ".data" # .rodata
0446     .align 4
0447 #ifdef USE_PPCBUG
0448 /* A control 'packet' for the .NETCTRL PPCBug syscall to
0449  * reset a network interface. Let's hope they used the
0450  * first one for booting!! (CLUN/DLUN == 0/0)
0451  * Must be 4-byte aligned...
0452  */
0453 nioc_reset_packet:
0454     .byte   0   /* Contoller LUN                                   */
0455     .byte   0   /* Device LUN                                      */
0456     .word   0   /* status return                                   */
0457     .long   5   /* Command (5=RESET)                               */
0458     .long   0   /* Mem. Addr. for real data (unused for reset)     */
0459     .long   0   /* Number of bytes                                 */
0460     .long   0   /* Status/Control Flags (unused for reset)         */
0461 #endif
0462 #ifdef TEST_PPCBUG_CALLS
0463 banner_start:
0464     .ascii "This message was printed by PPCBug with MMU enabled"
0465 banner_end:
0466 #endif