On Tue, 2012-11-27 at 14:39 +1100, Anton Blanchard wrote: > The ppc64 kernel can get loaded at any address which means > our very early init code in prom_init.c must be relocatable. We do > this with a pretty nasty RELOC() macro that we wrap accesses of > variables with. It is very fragile and sometimes we forget to add a > RELOC() to an uncommon path or sometimes a compiler change breaks it. > > 32bit has a much more elegant solution where we build prom_init.c > with -mrelocatable and then process the relocations manually. > Unfortunately we can't do the equivalent on 64bit and we would > have to build the entire kernel relocatable (-pie), resulting in a > large increase in kernel footprint (megabytes of relocation data). > The relocation data will be marked __initdata but it still creates > more pressure on our already tight memory layout at boot. > > Alan Modra pointed out that the 64bit ABI is relocatable even > if we don't build with -pie, we just need to relocate the TOC. > This patch implements that idea and relocates the TOC entries of > prom_init.c. An added bonus is there are very few relocations to > process which helps keep boot times on simulators down. > > gcc does not put 64bit integer constants into the TOC but to be > safe we may want a build time script which passes through the > prom_init.c TOC entries to make sure everything looks reasonable.
My only potential objection was that it might have been cleaner to actually build prom_init.c as a separate binary alltogether and piggy back it... Ben. > Signed-off-by: Anton Blanchard <an...@samba.org> > --- > > To keep the patch small and reviewable, I separated the removal > of the RELOC macro into a follow up patch. > > For simplicity I do the relocation in C but if self brain surgery > keeps people up at night we can move it into assembly. > > Index: b/arch/powerpc/kernel/prom_init.c > =================================================================== > --- a/arch/powerpc/kernel/prom_init.c > +++ b/arch/powerpc/kernel/prom_init.c > @@ -66,8 +66,8 @@ > * is running at whatever address it has been loaded at. > * On ppc32 we compile with -mrelocatable, which means that references > * to extern and static variables get relocated automatically. > - * On ppc64 we have to relocate the references explicitly with > - * RELOC. (Note that strings count as static variables.) > + * ppc64 objects are always relocatable, we just need to relocate the > + * TOC. > * > * Because OF may have mapped I/O devices into the area starting at > * KERNELBASE, particularly on CHRP machines, we can't safely call > @@ -79,13 +79,12 @@ > * On ppc64, 64 bit values are truncated to 32 bits (and > * fortunately don't get interpreted as two arguments). > */ > +#define RELOC(x) (x) > +#define ADDR(x) (u32)(unsigned long)(x) > + > #ifdef CONFIG_PPC64 > -#define RELOC(x) (*PTRRELOC(&(x))) > -#define ADDR(x) (u32) add_reloc_offset((unsigned long)(x)) > #define OF_WORKAROUNDS 0 > #else > -#define RELOC(x) (x) > -#define ADDR(x) (u32) (x) > #define OF_WORKAROUNDS of_workarounds > int of_workarounds; > #endif > @@ -334,9 +333,6 @@ static void __init prom_printf(const cha > struct prom_t *_prom = &RELOC(prom); > > va_start(args, format); > -#ifdef CONFIG_PPC64 > - format = PTRRELOC(format); > -#endif > for (p = format; *p != 0; p = q) { > for (q = p; *q != 0 && *q != '\n' && *q != '%'; ++q) > ; > @@ -437,9 +433,6 @@ static unsigned int __init prom_claim(un > > static void __init __attribute__((noreturn)) prom_panic(const char *reason) > { > -#ifdef CONFIG_PPC64 > - reason = PTRRELOC(reason); > -#endif > prom_print(reason); > /* Do not call exit because it clears the screen on pmac > * it also causes some sort of double-fault on early pmacs */ > @@ -929,7 +922,7 @@ static void __init prom_send_capabilitie > * (we assume this is the same for all cores) and use it to > * divide NR_CPUS. > */ > - cores = (u32 > *)PTRRELOC(&ibm_architecture_vec[IBM_ARCH_VEC_NRCORES_OFFSET]); > + cores = (u32 > *)&ibm_architecture_vec[IBM_ARCH_VEC_NRCORES_OFFSET]; > if (*cores != NR_CPUS) { > prom_printf("WARNING ! " > "ibm_architecture_vec structure > inconsistent: %lu!\n", > @@ -2850,6 +2843,53 @@ static void __init prom_check_initrd(uns > #endif /* CONFIG_BLK_DEV_INITRD */ > } > > +#ifdef CONFIG_PPC64 > +#ifdef CONFIG_RELOCATABLE > +static void reloc_toc(void) > +{ > +} > + > +static void unreloc_toc(void) > +{ > +} > +#else > +static void __reloc_toc(void *tocstart, unsigned long offset, > + unsigned long nr_entries) > +{ > + unsigned long i; > + unsigned long *toc_entry = (unsigned long *)tocstart; > + > + for (i = 0; i < nr_entries; i++) { > + *toc_entry = *toc_entry + offset; > + toc_entry++; > + } > +} > + > +static void reloc_toc(void) > +{ > + unsigned long offset = reloc_offset(); > + unsigned long nr_entries = > + (__prom_init_toc_end - __prom_init_toc_start) / sizeof(long); > + > + /* Need to add offset to get at __prom_init_toc_start */ > + __reloc_toc(__prom_init_toc_start + offset, offset, nr_entries); > + > + mb(); > +} > + > +static void unreloc_toc(void) > +{ > + unsigned long offset = reloc_offset(); > + unsigned long nr_entries = > + (__prom_init_toc_end - __prom_init_toc_start) / sizeof(long); > + > + mb(); > + > + /* __prom_init_toc_start has been relocated, no need to add offset */ > + __reloc_toc(__prom_init_toc_start, -offset, nr_entries); > +} > +#endif > +#endif > > /* > * We enter here early on, when the Open Firmware prom is still > @@ -2867,6 +2907,8 @@ unsigned long __init prom_init(unsigned > #ifdef CONFIG_PPC32 > unsigned long offset = reloc_offset(); > reloc_got2(offset); > +#else > + reloc_toc(); > #endif > > _prom = &RELOC(prom); > @@ -3061,6 +3103,8 @@ unsigned long __init prom_init(unsigned > > #ifdef CONFIG_PPC32 > reloc_got2(-offset); > +#else > + unreloc_toc(); > #endif > > #ifdef CONFIG_PPC_EARLY_DEBUG_OPAL > Index: b/arch/powerpc/kernel/prom_init_check.sh > =================================================================== > --- a/arch/powerpc/kernel/prom_init_check.sh > +++ b/arch/powerpc/kernel/prom_init_check.sh > @@ -22,7 +22,7 @@ __secondary_hold_acknowledge __secondary > strcmp strcpy strlcpy strlen strncmp strstr logo_linux_clut224 > reloc_got2 kernstart_addr memstart_addr linux_banner _stext > opal_query_takeover opal_do_takeover opal_enter_rtas opal_secondary_entry > -boot_command_line" > +boot_command_line __prom_init_toc_start __prom_init_toc_end" > > NM="$1" > OBJ="$2" > Index: b/arch/powerpc/kernel/vmlinux.lds.S > =================================================================== > --- a/arch/powerpc/kernel/vmlinux.lds.S > +++ b/arch/powerpc/kernel/vmlinux.lds.S > @@ -218,6 +218,11 @@ SECTIONS > > .got : AT(ADDR(.got) - LOAD_OFFSET) { > __toc_start = .; > +#ifndef CONFIG_RELOCATABLE > + __prom_init_toc_start = .; > + arch/powerpc/kernel/prom_init.o*(.toc .got) > + __prom_init_toc_end = .; > +#endif > *(.got) > *(.toc) > } > Index: b/arch/powerpc/Makefile > =================================================================== > --- a/arch/powerpc/Makefile > +++ b/arch/powerpc/Makefile > @@ -136,6 +136,7 @@ head-$(CONFIG_FSL_BOOKE) := arch/powerpc > head-$(CONFIG_PPC64) += arch/powerpc/kernel/entry_64.o > head-$(CONFIG_PPC_FPU) += arch/powerpc/kernel/fpu.o > head-$(CONFIG_ALTIVEC) += arch/powerpc/kernel/vector.o > +head-$(CONFIG_PPC_OF_BOOT_TRAMPOLINE) += arch/powerpc/kernel/prom_init.o > > core-y += arch/powerpc/kernel/ \ > arch/powerpc/mm/ \ > Index: b/arch/powerpc/kernel/Makefile > =================================================================== > --- a/arch/powerpc/kernel/Makefile > +++ b/arch/powerpc/kernel/Makefile > @@ -91,7 +91,6 @@ obj-$(CONFIG_RELOCATABLE_PPC32) += reloc > obj-$(CONFIG_PPC32) += entry_32.o setup_32.o > obj-$(CONFIG_PPC64) += dma-iommu.o iommu.o > obj-$(CONFIG_KGDB) += kgdb.o > -obj-$(CONFIG_PPC_OF_BOOT_TRAMPOLINE) += prom_init.o > obj-$(CONFIG_MODULES) += ppc_ksyms.o > obj-$(CONFIG_BOOTX_TEXT) += btext.o > obj-$(CONFIG_SMP) += smp.o > @@ -142,6 +141,7 @@ GCOV_PROFILE_kprobes.o := n > extra-$(CONFIG_PPC_FPU) += fpu.o > extra-$(CONFIG_ALTIVEC) += vector.o > extra-$(CONFIG_PPC64) += entry_64.o > +extra-$(CONFIG_PPC_OF_BOOT_TRAMPOLINE) += prom_init.o > > extra-y += systbl_chk.i > $(obj)/systbl.o: systbl_chk > Index: b/arch/powerpc/include/asm/sections.h > =================================================================== > --- a/arch/powerpc/include/asm/sections.h > +++ b/arch/powerpc/include/asm/sections.h > @@ -10,6 +10,9 @@ > > extern char __end_interrupts[]; > > +extern char __prom_init_toc_start[]; > +extern char __prom_init_toc_end[]; > + > static inline int in_kernel_text(unsigned long addr) > { > if (addr >= (unsigned long)_stext && addr < (unsigned long)__init_end) _______________________________________________ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev