relocate.S
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:5k
- /*
- * arch/ppc/boot/simple/relocate.S
- *
- * This is the common part of the loader relocation and initialization
- * process. All of the board/processor specific initialization is
- * done before we get here.
- *
- * Author: Tom Rini
- * trini@mvista.com
- * Derived from arch/ppc/boot/prep/head.S (Cort Dougan, many others).
- *
- * Copyright 2001 MontaVista Software Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
- #include <linux/config.h>
- #include <asm/processor.h>
- #include <asm/cache.h>
- #include <asm/ppc_asm.h>
- #define GETSYM(reg, sym)
- lis reg, sym@h; ori reg, reg, sym@l
-
- .text
- /* We get called from the early initialization code.
- * Register 3 has the address where we were loaded,
- * Register 4 contains any residual data passed from the
- * boot rom.
- */
- .globl relocate
- relocate:
- /* Save r3, r4 for later.
- * The r8/r11 are legacy registers so I don't have to
- * rewrite the code below :-).
- */
- mr r8, r3
- mr r11, r4
- /* compute the size of the whole image in words. */
- GETSYM(r4,start)
- GETSYM(r5,end)
- addi r5,r5,3 /* round up */
- sub r5,r5,r4 /* end - start */
- srwi r5,r5,2
- mr r7,r5 /* Save for later use. */
- /*
- * Check if we need to relocate ourselves to the link addr or were
- * we loaded there to begin with.
- */
- cmp cr0,r3,r4
- beq start_ldr /* If 0, we don't need to relocate */
- /* Move this code somewhere safe. This is max(load + size, end)
- * BIG ASSUMPTION: Addresses below 0x80000000 are assumed to be
- * in RAM, and addresses above 0x80000000 are assumed to be in
- * Flash. The cmpw instruction below does a signed integer
- * comparison, so when comparing a RAM address to a Flash address
- * the RAM address will always be greater. This allows the
- * relocation to work when the load address is in Flash.
- * r8 == load address
- */
- GETSYM(r4, start)
- GETSYM(r5, end)
- sub r6,r5,r4
- add r6,r8,r6 /* r6 == phys(load + size) */
- cmpw r5,r6
- bgt 1f
- b 2f
- 1:
- mr r6, r5
- 2:
- /* dest is in r6 */
- /* Ensure alignment --- this code is precautionary */
- addi r6,r6,4
- li r5,0x0003
- andc r6,r6,r5
- /* Find physical address and size of do_relocate */
- GETSYM(r5, __relocate_start)
- GETSYM(r4, __relocate_end)
- GETSYM(r3, start)
- /* Size to copy */
- sub r4,r4,r5
- srwi r4,r4,2
-
- /* Src addr to copy (= __relocate_start - start + where_loaded) */
- sub r3,r5,r3
- add r5,r8,r3
- /* Save dest */
- mr r3, r6
- /* Do the copy */
- mtctr r4
- 3: lwz r4,0(r5)
- stw r4,0(r3)
- addi r3,r3,4
- addi r5,r5,4
- bdnz 3b
- GETSYM(r4, __relocate_start)
- GETSYM(r5, do_relocate)
- sub r4,r5,r4 /* Get entry point for do_relocate in */
- add r6,r6,r4 /* relocated section */
- /* This will return to the relocated do_relocate */
- mtlr r6
- b flush_instruction_cache
- .section ".relocate_code","xa"
-
- do_relocate:
- /* We have 2 cases --- start < load, or start > load
- * This determines whether we copy from the end, or the start.
- * Its easier to have 2 loops than to have paramaterised
- * loops. Sigh.
- */
- li r6,0 /* Clear checksum */
- mtctr r7 /* Setup for a loop */
-
- GETSYM(r4, start)
- mr r3,r8 /* Get the load addr */
- cmp cr0,r4,r3 /* If we need to copy from the end, do so */
- bgt do_relocate_from_end
-
- do_relocate_from_start:
- 1: lwz r5,0(r3) /* Load and decrement */
- stw r5,0(r4) /* Store and decrement */
- addi r3,r3,4
- addi r4,r4,4
- xor r6,r6,r5 /* Update checksum */
- bdnz 1b /* Are we done? */
- b do_relocate_out /* Finished */
- do_relocate_from_end:
- GETSYM(r3, end)
- slwi r4,r7,2
- add r4,r8,r4 /* Get the physical end */
- 1: lwzu r5,-4(r4)
- stwu r5, -4(r3)
- xor r6,r6,r5
- bdnz 1b
- do_relocate_out:
- GETSYM(r3,start_ldr)
- mtlr r3 /* Easiest way to do an absolute jump */
- /* Some boards don't boot up with the I-cache enabled. Do that
- * now because the decompress runs much faster that way.
- * As a side effect, we have to ensure the data cache is not enabled
- * so we can access the serial I/O without trouble.
- */
- b flush_instruction_cache
- .previous
-
- start_ldr:
- /* Clear all of BSS and set up stack for C calls */
- lis r3,edata@h
- ori r3,r3,edata@l
- lis r4,end@h
- ori r4,r4,end@l
- subi r3,r3,4
- subi r4,r4,4
- li r0,0
- 50: stwu r0,4(r3)
- cmp cr0,r3,r4
- bne 50b
- 90: mr r9,r1 /* Save old stack pointer (in case it matters) */
- lis r1,.stack@h
- ori r1,r1,.stack@l
- addi r1,r1,4096*2
- subi r1,r1,256
- li r2,0x000F /* Mask pointer to 16-byte boundary */
- andc r1,r1,r2
- /*
- * Exec kernel loader
- */
- mr r3,r8 /* Load point */
- mr r4,r7 /* Program length */
- mr r5,r6 /* Checksum */
- mr r6,r11 /* Residual data */
- bl decompress_kernel
- /*
- * Make sure the kernel knows we don't have things set in
- * registers. -- Tom
- */
- li r4,0
- li r6,0
- /*
- * Start at the begining.
- */
- li r9,0x0000
- mtlr r9
- blr
- .comm .stack,4096*2,4