URL
https://opencores.org/ocsvn/or1k/or1k/trunk
Subversion Repositories or1k
[/] [or1k/] [trunk/] [rtems-20020807/] [c/] [src/] [lib/] [libbsp/] [powerpc/] [shared/] [bootloader/] [head.S] - Rev 1765
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.** head.S,v 1.2 2002/04/18 20:55:13 joel Exp*/#include <asm.h>#include <rtems/score/cpu.h>#include "bootldr.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 ; \scSTART_GOTGOT_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_CALLSGOT_ENTRY(banner_start)GOT_ENTRY(banner_end)#endifEND_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_PPCBUGMONITOR_ENTER#endifbl 1f1: mflr r1li r0,0stwu r0,start-1b-0x400+0x1b0-FRAME_SIZE(r1)stmw r26,FRAME_SIZE-24(r1)GET_GOTmfmsr r28 /* Turn off interrupts */ori r0,r28,MSR_EExori r0,r0,MSR_EEmtmsr r0/* Enable the caches, from now on cr2.eq set means processor is 601 */mfpvr r0mfspr r29,HID0srwi r0,r0,16cmplwi cr2,r0,1beq 2,2f#ifndef USE_PPCBUGori r0,r29,ENBL_CACHES|INVL_CACHES|LOCK_CACHESxori r0,r0,INVL_CACHES|LOCK_CACHESsyncisyncmtspr HID0,r0#endif2: 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@hastw r7,16(bd)stw r8,20(bd)addi r3,r3,__size@sectoff@lstw 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_codemovelwz r3,mover(bd)lwz r6,cache_lsize(bd)bl codemovemtctr r3 # Where the temporary codemove is.lwz r3,image(bd)lis r5,_edata@sectoff@halwz r4,GOT(0) # Our own addressaddi r5,r5,_edata@sectoff@llwz r6,cache_lsize(bd)lwz r8,GOT(moved)sub r7,r3,r4 # Difference to adjust pointers.add r8,r8,r7add r30,r30,r7add bd,bd,r7/* Call the copy routine but return to the new area. */mtlr r8 # for the return addressbctr # returns to the moved instruction/* Establish the new top stack frame. */moved: lwz r1,stack(bd)li r0,0stwu r0,-16(r1)/* relocate again */bl reloc/* Clear all of BSS */lwz r10,GOT(.bss)li r0,__bss_words@sectoff@lsubi r10,r10,4cmpwi r0,0mtctr r0li r0,0beq 4f3: 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_PPCBUG4: bl MMUoff#endifbl 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,0beq cr2,5fmtdbatu 0,r3mtdbatu 1,r3mtdbatu 2,r3mtdbatu 3,r35: mtibatu 0,r3mtibatl 0,r3mtibatu 1,r3mtibatl 1,r3mtibatu 2,r3mtibatl 2,r3mtibatu 3,r3mtibatl 3,r3lis r3,__size@sectoff@haaddi r3,r3,__size@sectoff@lsync # We are going to touch SDR1 !bl mm_initbl 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 # .OUTLNlwz r3,GOT(banner_start)lwz r4,GOT(banner_end)sc#endifbl setup_hwlwz r4,GOT(_binary_rtems_gz_start)lis r5,_rtems_gz_size@sectoff@halwz r6,GOT(_binary_initrd_gz_start)lis r3,_rtems_size@sectoff@halwz r7,GOT(_binary_initrd_gz_end)addi r5,r5,_rtems_gz_size@sectoff@laddi r3,r3,_rtems_size@sectoff@lsub r7,r7,r6bl 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_tlblwz 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 againlis r30,0xdeadc0de@haaddi r30,r30,0xdeadc0de@lstw 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,1fmfspr r0,HID0ori r0,r0,HID0_DCI|HID0_DCEsyncmtspr HID0,r0xori r0,r0,HID0_DCI|HID0_DCEmtspr HID0,r0/* Provisional return to FW, works for PPCBug */#if 0MONITOR_ENTER#else1: 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@lla r12,GOT(_GOT2_TABLE_)lwz r11,GOT(_GOT2_TABLE_)mtctr r0sub r11,r12,r11addi r12,r12,-41: lwzu r0,4(r12)add r0,r0,r11stw 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@llwz r12,GOT(_FIXUP_TABLE_)cmpwi r0,0mtctr r0addi r12,r12,-4beqlr3: lwzu r10,4(r12)lwzux r0,r10,r11add r0,r0,r11stw r10,0(r12)stw r0,0(r10)bdnz 3bblr/* 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,@functionMMUon: mfmsr r0ori r0,r0,MSR_IR|MSR_DR|MSR_IPmflr r11xori r0,r0,MSR_IPmtsrr0 r11mtsrr1 r0rfi.globl MMUoff.type MMUoff,@functionMMUoff: mfmsr r0ori r0,r0,MSR_IR|MSR_DR|MSR_IPmflr r11xori r0,r0,MSR_IR|MSR_DRmtsrr0 r11mtsrr1 r0rfi/* 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,0x10001: addic. r11,r11,-0x1000tlbie r11bnl 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*/syncblr.globl codemovecodemove:.type codemove,@function/* r3 dest, r4 src, r5 length in bytes, r6 cachelinesize */cmplw cr1,r3,r4addi r0,r5,3srwi. r0,r0,2beq cr1,4f /* In place copy is not necessary */beq 7f /* Protect against 0 count */mtctr r0bge cr1,2fla r8,-4(r4)la r7,-4(r3)1: lwzu r0,4(r8)stwu r0,4(r7)bdnz 1bb 4f2: slwi r0,r0,2add r8,r4,r0add r7,r3,r03: 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,0add r5,r3,r5beq 7f /* Always flush prefetch queue in any case */subi r0,r6,1andc r3,r3,r0mr r4,r35: cmplw r4,r5dcbst 0,r4add r4,r4,r6blt 5bsync /* Wait for all dcbst to complete on bus */mr r4,r36: cmplw r4,r5icbi 0,r4add r4,r4,r6blt 6b7: sync /* Wait for all icbi to complete on bus */isyncblr.size codemove,.-codemove_size_codemove=.-codemove.section ".data" # .rodata.align 2#ifdef TEST_PPCBUG_CALLSbanner_start:.ascii "This message was printed by PPCBug with MMU enabled"banner_end:#endif
