Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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