URL
https://opencores.org/ocsvn/openrisc_me/openrisc_me/trunk
Subversion Repositories openrisc_me
[/] [openrisc/] [trunk/] [rtos/] [rtems/] [c/] [src/] [lib/] [libbsp/] [powerpc/] [shared/] [bootloader/] [head.S] - Rev 173
Compare with Previous | Blame | View Log
/*
* head.S -- Bootloader Entry point
*
* Copyright (C) 1998, 1999 Gabriel Paubert, paubert@iram.es
*
* Modified to compile in RTEMS development environment
* by Eric Valette
*
* Copyright (C) 1999 Eric Valette. valette@crf.canon.fr
*
* The license and distribution terms for this file may be
* found in found in the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
*
* $Id: head.S,v 1.2 2001-09-27 12:01:06 chris Exp $
*/
#include "bootldr.h"
#include <libcpu/cpu.h>
#include <rtems/score/targopts.h>
#include "asm.h"
#undef TEST_PPCBUG_CALLS
#define FRAME_SIZE 32
#define LOCK_CACHES (HID0_DLOCK|HID0_ILOCK)
#define INVL_CACHES (HID0_DCI|HID0_ICFI)
#define ENBL_CACHES (HID0_DCE|HID0_ICE)
#define USE_PPCBUG
#undef USE_PPCBUG
#define MONITOR_ENTER \
mfmsr r10 ; \
ori r10,r10,MSR_IP ; \
mtmsr r10 ; \
li r10,0x63 ; \
sc
START_GOT
GOT_ENTRY(_GOT2_TABLE_)
GOT_ENTRY(_FIXUP_TABLE_)
GOT_ENTRY(.bss)
GOT_ENTRY(codemove)
GOT_ENTRY(0)
GOT_ENTRY(__bd)
GOT_ENTRY(moved)
GOT_ENTRY(_binary_rtems_gz_start)
GOT_ENTRY(_binary_initrd_gz_start)
GOT_ENTRY(_binary_initrd_gz_end)
#ifdef TEST_PPCBUG_CALLS
GOT_ENTRY(banner_start)
GOT_ENTRY(banner_end)
#endif
END_GOT
.globl start
.type start,@function
/* Point the stack into the PreP partition header in the x86 reserved
* code area, so that simple C routines can be called.
*/
start:
#ifdef USE_PPCBUG
MONITOR_ENTER
#endif
bl 1f
1: mflr r1
li r0,0
stwu r0,start-1b-0x400+0x1b0-FRAME_SIZE(r1)
stmw r26,FRAME_SIZE-24(r1)
GET_GOT
mfmsr r28 /* Turn off interrupts */
ori r0,r28,MSR_EE
xori r0,r0,MSR_EE
mtmsr r0
/* Enable the caches, from now on cr2.eq set means processor is 601 */
mfpvr r0
mfspr r29,HID0
srwi r0,r0,16
cmplwi cr2,r0,1
beq 2,2f
#ifndef USE_PPCBUG
ori r0,r29,ENBL_CACHES|INVL_CACHES|LOCK_CACHES
xori r0,r0,INVL_CACHES|LOCK_CACHES
sync
isync
mtspr HID0,r0
#endif
2: bl reloc
/* save all the parameters and the orginal msr/hid0/r31 */
lwz bd,GOT(__bd)
stw r3,0(bd)
stw r4,4(bd)
stw r5,8(bd)
stw r6,12(bd)
lis r3,__size@sectoff@ha
stw r7,16(bd)
stw r8,20(bd)
addi r3,r3,__size@sectoff@l
stw r9,24(bd)
stw r10,28(bd)
stw r28,o_msr(bd)
stw r29,o_hid0(bd)
stw r31,o_r31(bd)
/* Call the routine to fill boot_data structure from residual data.
* And to find where the code has to be moved.
*/
bl early_setup
/* Now we need to relocate ourselves, where we are told to. First put a
* copy of the codemove routine to some place in memory.
* (which may be where the 0x41 partition was loaded, so size is critical).
*/
lwz r4,GOT(codemove)
li r5,_size_codemove
lwz r3,mover(bd)
lwz r6,cache_lsize(bd)
bl codemove
mtctr r3 # Where the temporary codemove is.
lwz r3,image(bd)
lis r5,_edata@sectoff@ha
lwz r4,GOT(0) # Our own address
addi r5,r5,_edata@sectoff@l
lwz r6,cache_lsize(bd)
lwz r8,GOT(moved)
sub r7,r3,r4 # Difference to adjust pointers.
add r8,r8,r7
add r30,r30,r7
add bd,bd,r7
/* Call the copy routine but return to the new area. */
mtlr r8 # for the return address
bctr # returns to the moved instruction
/* Establish the new top stack frame. */
moved: lwz r1,stack(bd)
li r0,0
stwu r0,-16(r1)
/* relocate again */
bl reloc
/* Clear all of BSS */
lwz r10,GOT(.bss)
li r0,__bss_words@sectoff@l
subi r10,r10,4
cmpwi r0,0
mtctr r0
li r0,0
beq 4f
3: stwu r0,4(r10)
bdnz 3b
/* Final memory initialization. First switch to unmapped mode
* in case the FW had set the MMU on, and flush the TLB to avoid
* stale entries from interfering. No I/O access is allowed
* during this time!
*/
#ifndef USE_PPCBUG
4: bl MMUoff
#endif
bl flush_tlb
/* Some firmware versions leave stale values in the BATs, it's time
* to invalidate them to avoid interferences with our own mappings.
* But the 601 valid bit is in the BATL (IBAT only) and others are in
* the [ID]BATU. Bloat, bloat.. fortunately thrown away later.
*/
li r3,0
beq cr2,5f
mtdbatu 0,r3
mtdbatu 1,r3
mtdbatu 2,r3
mtdbatu 3,r3
5: mtibatu 0,r3
mtibatl 0,r3
mtibatu 1,r3
mtibatl 1,r3
mtibatu 2,r3
mtibatl 2,r3
mtibatu 3,r3
mtibatl 3,r3
lis r3,__size@sectoff@ha
addi r3,r3,__size@sectoff@l
sync # We are going to touch SDR1 !
bl mm_init
bl MMUon
/* Now we are mapped and can perform I/O if we want */
#ifdef TEST_PPCBUG_CALLS
/* Experience seems to show that PPCBug can only be called with the
* data cache disabled and with MMU disabled. Bummer.
*/
li r10,0x22 # .OUTLN
lwz r3,GOT(banner_start)
lwz r4,GOT(banner_end)
sc
#endif
bl setup_hw
lwz r4,GOT(_binary_rtems_gz_start)
lis r5,_rtems_gz_size@sectoff@ha
lwz r6,GOT(_binary_initrd_gz_start)
lis r3,_rtems_size@sectoff@ha
lwz r7,GOT(_binary_initrd_gz_end)
addi r5,r5,_rtems_gz_size@sectoff@l
addi r3,r3,_rtems_size@sectoff@l
sub r7,r7,r6
bl decompress_kernel
/* Back here we are unmapped and we start the kernel, passing up to eight
* parameters just in case, only r3 to r7 used for now. Flush the tlb so
* that the loaded image starts in a clean state.
*/
bl flush_tlb
lwz r3,0(bd)
lwz r4,4(bd)
lwz r5,8(bd)
lwz r6,12(bd)
lwz r7,16(bd)
lwz r8,20(bd)
lwz r9,24(bd)
lwz r10,28(bd)
lwz r30,0(0)
mtctr r30
/*
* Linux code again
lis r30,0xdeadc0de@ha
addi r30,r30,0xdeadc0de@l
stw r30,0(0)
li r30,0
*/
dcbst 0,r30 /* Make sure it's in memory ! */
/* We just flash invalidate and disable the dcache, unless it's a 601,
* critical areas have been flushed and we don't care about the stack
* and other scratch areas.
*/
beq cr2,1f
mfspr r0,HID0
ori r0,r0,HID0_DCI|HID0_DCE
sync
mtspr HID0,r0
xori r0,r0,HID0_DCI|HID0_DCE
mtspr HID0,r0
/* Provisional return to FW, works for PPCBug */
#if 0
MONITOR_ENTER
#else
1: bctr
#endif
/* relocation function, r30 must point to got2+0x8000 */
reloc:
/* Adjust got2 pointers, no need to check for 0, this code already puts
* a few entries in the table.
*/
li r0,__got2_entries@sectoff@l
la r12,GOT(_GOT2_TABLE_)
lwz r11,GOT(_GOT2_TABLE_)
mtctr r0
sub r11,r12,r11
addi r12,r12,-4
1: lwzu r0,4(r12)
add r0,r0,r11
stw r0,0(r12)
bdnz 1b
/* Now adjust the fixups and the pointers to the fixups in case we need
* to move ourselves again.
*/
2: li r0,__fixup_entries@sectoff@l
lwz r12,GOT(_FIXUP_TABLE_)
cmpwi r0,0
mtctr r0
addi r12,r12,-4
beqlr
3: lwzu r10,4(r12)
lwzux r0,r10,r11
add r0,r0,r11
stw r10,0(r12)
stw r0,0(r10)
bdnz 3b
blr
/* Set the MMU on and off: code is always mapped 1:1 and does not need MMU,
* but it does not cost so much to map it also and it catches calls through
* NULL function pointers.
*/
.globl MMUon
.type MMUon,@function
MMUon: mfmsr r0
ori r0,r0,MSR_IR|MSR_DR|MSR_IP
mflr r11
xori r0,r0,MSR_IP
mtsrr0 r11
mtsrr1 r0
rfi
.globl MMUoff
.type MMUoff,@function
MMUoff: mfmsr r0
ori r0,r0,MSR_IR|MSR_DR|MSR_IP
mflr r11
xori r0,r0,MSR_IR|MSR_DR
mtsrr0 r11
mtsrr1 r0
rfi
/* Due to the PPC architecture (and according to the specifications), a
* series of tlbie which goes through a whole 256 MB segment always flushes
* the whole TLB. This is obviously overkill and slow, but who cares ?
* It takes about 1 ms on a 200 MHz 603e and works even if residual data
* get the number of TLB entries wrong.
*/
flush_tlb:
lis r11,0x1000
1: addic. r11,r11,-0x1000
tlbie r11
bnl 1b
/* tlbsync is not implemented on 601, so use sync which seems to be a superset
* of tlbsync in all cases and do not bother with CPU dependant code
*/
sync
blr
.globl codemove
codemove:
.type codemove,@function
/* r3 dest, r4 src, r5 length in bytes, r6 cachelinesize */
cmplw cr1,r3,r4
addi r0,r5,3
srwi. r0,r0,2
beq cr1,4f /* In place copy is not necessary */
beq 7f /* Protect against 0 count */
mtctr r0
bge cr1,2f
la r8,-4(r4)
la r7,-4(r3)
1: lwzu r0,4(r8)
stwu r0,4(r7)
bdnz 1b
b 4f
2: slwi r0,r0,2
add r8,r4,r0
add r7,r3,r0
3: lwzu r0,-4(r8)
stwu r0,-4(r7)
bdnz 3b
/* Now flush the cache: note that we must start from a cache aligned
* address. Otherwise we might miss one cache line.
*/
4: cmpwi r6,0
add r5,r3,r5
beq 7f /* Always flush prefetch queue in any case */
subi r0,r6,1
andc r3,r3,r0
mr r4,r3
5: cmplw r4,r5
dcbst 0,r4
add r4,r4,r6
blt 5b
sync /* Wait for all dcbst to complete on bus */
mr r4,r3
6: cmplw r4,r5
icbi 0,r4
add r4,r4,r6
blt 6b
7: sync /* Wait for all icbi to complete on bus */
isync
blr
.size codemove,.-codemove
_size_codemove=.-codemove
.section ".data" # .rodata
.align 2
#ifdef TEST_PPCBUG_CALLS
banner_start:
.ascii "This message was printed by PPCBug with MMU enabled"
banner_end:
#endif