Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 | /* * 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). * * 2001-2004 (c) MontaVista, Software, Inc. This file is licensed under * the terms of the GNU General Public License version 2. This program * is licensed "as is" without any warranty of any kind, whether express * or implied. */ #include <linux/config.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) * 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 */ mr r7,r25 /* Validated OFW interface */ bl load_kernel /* * Make sure the kernel knows we don't have things set in * registers. -- Tom */ li r4,0 li r5,0 li r6,0 /* * Start at the begining. */ #ifdef CONFIG_PPC_MULTIPLATFORM li r9,0xc mtlr r9 /* tell kernel we're prep, by putting 0xdeadc0de at KERNELLOAD, * and tell the kernel to start on the 4th instruction since we * overwrite the first 3 sometimes (which are 'nop'). */ lis r10,0xdeadc0de@h ori r10,r10,0xdeadc0de@l li r9,0 stw r10,0(r9) #else li r9,0 mtlr r9 #endif blr .comm .stack,4096*2,4 |