aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/prom_init.c
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2008-08-29 21:43:47 -0400
committerPaul Mackerras <paulus@samba.org>2008-09-15 14:08:38 -0400
commit549e8152de8039506f69c677a4546e5427aa6ae7 (patch)
treee03a4f46143a23045e456f96fc08beba12e73073 /arch/powerpc/kernel/prom_init.c
parente31aa453bbc4886a7bd33e5c2afa526d6f55bd7a (diff)
powerpc: Make the 64-bit kernel as a position-independent executable
This implements CONFIG_RELOCATABLE for 64-bit by making the kernel as a position-independent executable (PIE) when it is set. This involves processing the dynamic relocations in the image in the early stages of booting, even if the kernel is being run at the address it is linked at, since the linker does not necessarily fill in words in the image for which there are dynamic relocations. (In fact the linker does fill in such words for 64-bit executables, though not for 32-bit executables, so in principle we could avoid calling relocate() entirely when we're running a 64-bit kernel at the linked address.) The dynamic relocations are processed by a new function relocate(addr), where the addr parameter is the virtual address where the image will be run. In fact we call it twice; once before calling prom_init, and again when starting the main kernel. This means that reloc_offset() returns 0 in prom_init (since it has been relocated to the address it is running at), which necessitated a few adjustments. This also changes __va and __pa to use an equivalent definition that is simpler. With the relocatable kernel, PAGE_OFFSET and MEMORY_START are constants (for 64-bit) whereas PHYSICAL_START is a variable (and KERNELBASE ideally should be too, but isn't yet). With this, relocatable kernels still copy themselves down to physical address 0 and run there. Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/kernel/prom_init.c')
-rw-r--r--arch/powerpc/kernel/prom_init.c11
1 files changed, 7 insertions, 4 deletions
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c
index 1f8988585054..7cf274a2b334 100644
--- a/arch/powerpc/kernel/prom_init.c
+++ b/arch/powerpc/kernel/prom_init.c
@@ -2309,13 +2309,14 @@ static void __init prom_check_initrd(unsigned long r3, unsigned long r4)
2309 2309
2310unsigned long __init prom_init(unsigned long r3, unsigned long r4, 2310unsigned long __init prom_init(unsigned long r3, unsigned long r4,
2311 unsigned long pp, 2311 unsigned long pp,
2312 unsigned long r6, unsigned long r7) 2312 unsigned long r6, unsigned long r7,
2313 unsigned long kbase)
2313{ 2314{
2314 struct prom_t *_prom; 2315 struct prom_t *_prom;
2315 unsigned long hdr; 2316 unsigned long hdr;
2316 unsigned long offset = reloc_offset();
2317 2317
2318#ifdef CONFIG_PPC32 2318#ifdef CONFIG_PPC32
2319 unsigned long offset = reloc_offset();
2319 reloc_got2(offset); 2320 reloc_got2(offset);
2320#endif 2321#endif
2321 2322
@@ -2349,9 +2350,11 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
2349 */ 2350 */
2350 RELOC(of_platform) = prom_find_machine_type(); 2351 RELOC(of_platform) = prom_find_machine_type();
2351 2352
2353#ifndef CONFIG_RELOCATABLE
2352 /* Bail if this is a kdump kernel. */ 2354 /* Bail if this is a kdump kernel. */
2353 if (PHYSICAL_START > 0) 2355 if (PHYSICAL_START > 0)
2354 prom_panic("Error: You can't boot a kdump kernel from OF!\n"); 2356 prom_panic("Error: You can't boot a kdump kernel from OF!\n");
2357#endif
2355 2358
2356 /* 2359 /*
2357 * Check for an initrd 2360 * Check for an initrd
@@ -2371,7 +2374,7 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
2371 * Copy the CPU hold code 2374 * Copy the CPU hold code
2372 */ 2375 */
2373 if (RELOC(of_platform) != PLATFORM_POWERMAC) 2376 if (RELOC(of_platform) != PLATFORM_POWERMAC)
2374 copy_and_flush(0, KERNELBASE + offset, 0x100, 0); 2377 copy_and_flush(0, kbase, 0x100, 0);
2375 2378
2376 /* 2379 /*
2377 * Do early parsing of command line 2380 * Do early parsing of command line
@@ -2474,7 +2477,7 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
2474 reloc_got2(-offset); 2477 reloc_got2(-offset);
2475#endif 2478#endif
2476 2479
2477 __start(hdr, KERNELBASE + offset, 0); 2480 __start(hdr, kbase, 0);
2478 2481
2479 return 0; 2482 return 0;
2480} 2483}