1/* 2 * arch/ppc/boot/simple/relocate.S 3 * 4 * This is the common part of the loader relocation and initialization 5 * process. All of the board/processor specific initialization is 6 * done before we get here. 7 * 8 * Author: Tom Rini 9 * trini@mvista.com 10 * Derived from arch/ppc/boot/prep/head.S (Cort Dougan, many others). 11 * 12 * 2001-2002 (c) MontaVista, Software, Inc. This file is licensed under 13 * the terms of the GNU General Public License version 2. This program 14 * is licensed "as is" without any warranty of any kind, whether express 15 * or implied. 16 */ 17 18#include <linux/config.h> 19#include <asm/cache.h> 20#include <asm/ppc_asm.h> 21 22#define GETSYM(reg, sym) \ 23 lis reg, sym@h; ori reg, reg, sym@l 24 25 .text 26 /* We get called from the early initialization code. 27 * Register 3 has the address where we were loaded, 28 * Register 4 contains any residual data passed from the 29 * boot rom. 30 */ 31 .globl relocate 32relocate: 33 /* Save r3, r4 for later. 34 * The r8/r11 are legacy registers so I don't have to 35 * rewrite the code below :-). 36 */ 37 mr r8, r3 38 mr r11, r4 39 40 /* compute the size of the whole image in words. */ 41 GETSYM(r4,start) 42 GETSYM(r5,end) 43 44 addi r5,r5,3 /* round up */ 45 sub r5,r5,r4 /* end - start */ 46 srwi r5,r5,2 47 mr r7,r5 /* Save for later use. */ 48 49 /* 50 * Check if we need to relocate ourselves to the link addr or were 51 * we loaded there to begin with. 52 */ 53 cmp cr0,r3,r4 54 beq start_ldr /* If 0, we don't need to relocate */ 55 56 /* Move this code somewhere safe. This is max(load + size, end) 57 * r8 == load address 58 */ 59 GETSYM(r4, start) 60 GETSYM(r5, end) 61 62 sub r6,r5,r4 63 add r6,r8,r6 /* r6 == phys(load + size) */ 64 65 cmpw r5,r6 66 bgt 1f 67 b 2f 681: 69 mr r6, r5 702: 71 /* dest is in r6 */ 72 /* Ensure alignment --- this code is precautionary */ 73 addi r6,r6,4 74 li r5,0x0003 75 andc r6,r6,r5 76 77 /* Find physical address and size of do_relocate */ 78 GETSYM(r5, __relocate_start) 79 GETSYM(r4, __relocate_end) 80 GETSYM(r3, start) 81 82 /* Size to copy */ 83 sub r4,r4,r5 84 srwi r4,r4,2 85 86 /* Src addr to copy (= __relocate_start - start + where_loaded) */ 87 sub r3,r5,r3 88 add r5,r8,r3 89 90 /* Save dest */ 91 mr r3, r6 92 93 /* Do the copy */ 94 mtctr r4 953: lwz r4,0(r5) 96 stw r4,0(r3) 97 addi r3,r3,4 98 addi r5,r5,4 99 bdnz 3b 100 101 GETSYM(r4, __relocate_start) 102 GETSYM(r5, do_relocate) 103 104 sub r4,r5,r4 /* Get entry point for do_relocate in 105 add r6,r6,r4 * relocated section */ 106 107 /* This will return to the relocated do_relocate */ 108 mtlr r6 109 b flush_instruction_cache 110 111 .section ".relocate_code","xa" 112 113do_relocate: 114 /* We have 2 cases --- start < load, or start > load 115 * This determines whether we copy from the end, or the start. 116 * Its easier to have 2 loops than to have paramaterised 117 * loops. Sigh. 118 */ 119 li r6,0 /* Clear checksum */ 120 mtctr r7 /* Setup for a loop */ 121 122 GETSYM(r4, start) 123 mr r3,r8 /* Get the load addr */ 124 125 cmp cr0,r4,r3 /* If we need to copy from the end, do so */ 126 bgt do_relocate_from_end 127 128do_relocate_from_start: 1291: lwz r5,0(r3) /* Load and decrement */ 130 stw r5,0(r4) /* Store and decrement */ 131 addi r3,r3,4 132 addi r4,r4,4 133 xor r6,r6,r5 /* Update checksum */ 134 bdnz 1b /* Are we done? */ 135 b do_relocate_out /* Finished */ 136 137do_relocate_from_end: 138 GETSYM(r3, end) 139 slwi r4,r7,2 140 add r4,r8,r4 /* Get the physical end */ 1411: lwzu r5,-4(r4) 142 stwu r5, -4(r3) 143 xor r6,r6,r5 144 bdnz 1b 145 146do_relocate_out: 147 GETSYM(r3,start_ldr) 148 mtlr r3 /* Easiest way to do an absolute jump */ 149/* Some boards don't boot up with the I-cache enabled. Do that 150 * now because the decompress runs much faster that way. 151 * As a side effect, we have to ensure the data cache is not enabled 152 * so we can access the serial I/O without trouble. 153 */ 154 b flush_instruction_cache 155 156 .previous 157 158start_ldr: 159/* Clear all of BSS and set up stack for C calls */ 160 lis r3,edata@h 161 ori r3,r3,edata@l 162 lis r4,end@h 163 ori r4,r4,end@l 164 subi r3,r3,4 165 subi r4,r4,4 166 li r0,0 16750: stwu r0,4(r3) 168 cmp cr0,r3,r4 169 bne 50b 17090: mr r9,r1 /* Save old stack pointer (in case it matters) */ 171 lis r1,.stack@h 172 ori r1,r1,.stack@l 173 addi r1,r1,4096*2 174 subi r1,r1,256 175 li r2,0x000F /* Mask pointer to 16-byte boundary */ 176 andc r1,r1,r2 177 178 /* 179 * Exec kernel loader 180 */ 181 mr r3,r8 /* Load point */ 182 mr r4,r7 /* Program length */ 183 mr r5,r6 /* Checksum */ 184 mr r6,r11 /* Residual data */ 185 bl load_kernel 186 187 /* 188 * Make sure the kernel knows we don't have things set in 189 * registers. -- Tom 190 */ 191 li r4,0 192 li r5,0 193 li r6,0 194 195 /* 196 * Start at the begining. 197 */ 198 li r9,0x0000 199 mtlr r9 200 blr 201 202 .comm .stack,4096*2,4 203

