aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
authorSuzuki Poulose <suzuki@in.ibm.com>2011-12-14 17:58:12 -0500
committerJosh Boyer <jwboyer@gmail.com>2011-12-20 10:21:08 -0500
commit9c5f7d39a86316cd13baf973c90ed27f9f1cc979 (patch)
tree615117060a4b8b87cf1496abca0fe0365e845388 /arch/powerpc
parent239132454583d474932d8835f87a244f6f1bff9e (diff)
powerpc: Process dynamic relocations for kernel
The following patch implements the dynamic relocation processing for PPC32 kernel. relocate() accepts the target virtual address and relocates the kernel image to the same. Currently the following relocation types are handled : R_PPC_RELATIVE R_PPC_ADDR16_LO R_PPC_ADDR16_HI R_PPC_ADDR16_HA The last 3 relocations in the above list depends on value of Symbol indexed whose index is encoded in the Relocation entry. Hence we need the Symbol Table for processing such relocations. Note: The GNU ld for ppc32 produces buggy relocations for relocation types that depend on symbols. The value of the symbols with STB_LOCAL scope should be assumed to be zero. - Alan Modra Signed-off-by: Suzuki K. Poulose <suzuki@in.ibm.com> Signed-off-by: Josh Poimboeuf <jpoimboe@linux.vnet.ibm.com> Cc: Paul Mackerras <paulus@samba.org> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Alan Modra <amodra@au1.ibm.com> Cc: Kumar Gala <galak@kernel.crashing.org> Cc: linuxppc-dev <linuxppc-dev@lists.ozlabs.org> Signed-off-by: Josh Boyer <jwboyer@gmail.com>
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/Kconfig41
-rw-r--r--arch/powerpc/Makefile6
-rw-r--r--arch/powerpc/kernel/Makefile2
-rw-r--r--arch/powerpc/kernel/reloc_32.S208
-rw-r--r--arch/powerpc/kernel/vmlinux.lds.S8
-rwxr-xr-xarch/powerpc/relocs_check.pl14
6 files changed, 256 insertions, 23 deletions
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 8b323b7b0a61..2ad5ea827820 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -847,23 +847,30 @@ config DYNAMIC_MEMSTART
847 load address. When this option is enabled, the compile time physical 847 load address. When this option is enabled, the compile time physical
848 address CONFIG_PHYSICAL_START is ignored. 848 address CONFIG_PHYSICAL_START is ignored.
849 849
850# Mapping based RELOCATABLE is moved to DYNAMIC_MEMSTART 850 This option is overridden by CONFIG_RELOCATABLE
851# config RELOCATABLE 851
852# bool "Build a relocatable kernel (EXPERIMENTAL)" 852config RELOCATABLE
853# depends on EXPERIMENTAL && ADVANCED_OPTIONS && FLATMEM && (FSL_BOOKE || PPC_47x) 853 bool "Build a relocatable kernel (EXPERIMENTAL)"
854# help 854 depends on EXPERIMENTAL && ADVANCED_OPTIONS && FLATMEM
855# This builds a kernel image that is capable of running at the 855 select NONSTATIC_KERNEL
856# location the kernel is loaded at, without any alignment restrictions. 856 help
857# 857 This builds a kernel image that is capable of running at the
858# One use is for the kexec on panic case where the recovery kernel 858 location the kernel is loaded at, without any alignment restrictions.
859# must live at a different physical address than the primary 859 This feature is a superset of DYNAMIC_MEMSTART and hence overrides it.
860# kernel. 860
861# 861 One use is for the kexec on panic case where the recovery kernel
862# Note: If CONFIG_RELOCATABLE=y, then the kernel runs from the address 862 must live at a different physical address than the primary
863# it has been loaded at and the compile time physical addresses 863 kernel.
864# CONFIG_PHYSICAL_START is ignored. However CONFIG_PHYSICAL_START 864
865# setting can still be useful to bootwrappers that need to know the 865 Note: If CONFIG_RELOCATABLE=y, then the kernel runs from the address
866# load location of the kernel (eg. u-boot/mkimage). 866 it has been loaded at and the compile time physical addresses
867 CONFIG_PHYSICAL_START is ignored. However CONFIG_PHYSICAL_START
868 setting can still be useful to bootwrappers that need to know the
869 load address of the kernel (eg. u-boot/mkimage).
870
871config RELOCATABLE_PPC32
872 def_bool y
873 depends on PPC32 && RELOCATABLE
867 874
868config PAGE_OFFSET_BOOL 875config PAGE_OFFSET_BOOL
869 bool "Set custom page offset address" 876 bool "Set custom page offset address"
diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile
index ffe4d88f5a8a..b8b105c01c64 100644
--- a/arch/powerpc/Makefile
+++ b/arch/powerpc/Makefile
@@ -63,9 +63,9 @@ override CC += -m$(CONFIG_WORD_SIZE)
63override AR := GNUTARGET=elf$(CONFIG_WORD_SIZE)-powerpc $(AR) 63override AR := GNUTARGET=elf$(CONFIG_WORD_SIZE)-powerpc $(AR)
64endif 64endif
65 65
66LDFLAGS_vmlinux-yy := -Bstatic 66LDFLAGS_vmlinux-y := -Bstatic
67LDFLAGS_vmlinux-$(CONFIG_PPC64)$(CONFIG_RELOCATABLE) := -pie 67LDFLAGS_vmlinux-$(CONFIG_RELOCATABLE) := -pie
68LDFLAGS_vmlinux := $(LDFLAGS_vmlinux-yy) 68LDFLAGS_vmlinux := $(LDFLAGS_vmlinux-y)
69 69
70CFLAGS-$(CONFIG_PPC64) := -mminimal-toc -mtraceback=no -mcall-aixdesc 70CFLAGS-$(CONFIG_PPC64) := -mminimal-toc -mtraceback=no -mcall-aixdesc
71CFLAGS-$(CONFIG_PPC32) := -ffixed-r2 -mmultiple 71CFLAGS-$(CONFIG_PPC32) := -ffixed-r2 -mmultiple
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index ce4f7f179117..ee728e433aa2 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -85,6 +85,8 @@ extra-$(CONFIG_FSL_BOOKE) := head_fsl_booke.o
85extra-$(CONFIG_8xx) := head_8xx.o 85extra-$(CONFIG_8xx) := head_8xx.o
86extra-y += vmlinux.lds 86extra-y += vmlinux.lds
87 87
88obj-$(CONFIG_RELOCATABLE_PPC32) += reloc_32.o
89
88obj-$(CONFIG_PPC32) += entry_32.o setup_32.o 90obj-$(CONFIG_PPC32) += entry_32.o setup_32.o
89obj-$(CONFIG_PPC64) += dma-iommu.o iommu.o 91obj-$(CONFIG_PPC64) += dma-iommu.o iommu.o
90obj-$(CONFIG_KGDB) += kgdb.o 92obj-$(CONFIG_KGDB) += kgdb.o
diff --git a/arch/powerpc/kernel/reloc_32.S b/arch/powerpc/kernel/reloc_32.S
new file mode 100644
index 000000000000..ef46ba6e094f
--- /dev/null
+++ b/arch/powerpc/kernel/reloc_32.S
@@ -0,0 +1,208 @@
1/*
2 * Code to process dynamic relocations for PPC32.
3 *
4 * Copyrights (C) IBM Corporation, 2011.
5 * Author: Suzuki Poulose <suzuki@in.ibm.com>
6 *
7 * - Based on ppc64 code - reloc_64.S
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version
12 * 2 of the License, or (at your option) any later version.
13 */
14
15#include <asm/ppc_asm.h>
16
17/* Dynamic section table entry tags */
18DT_RELA = 7 /* Tag for Elf32_Rela section */
19DT_RELASZ = 8 /* Size of the Rela relocs */
20DT_RELAENT = 9 /* Size of one Rela reloc entry */
21
22STN_UNDEF = 0 /* Undefined symbol index */
23STB_LOCAL = 0 /* Local binding for the symbol */
24
25R_PPC_ADDR16_LO = 4 /* Lower half of (S+A) */
26R_PPC_ADDR16_HI = 5 /* Upper half of (S+A) */
27R_PPC_ADDR16_HA = 6 /* High Adjusted (S+A) */
28R_PPC_RELATIVE = 22
29
30/*
31 * r3 = desired final address
32 */
33
34_GLOBAL(relocate)
35
36 mflr r0 /* Save our LR */
37 bl 0f /* Find our current runtime address */
380: mflr r12 /* Make it accessible */
39 mtlr r0
40
41 lwz r11, (p_dyn - 0b)(r12)
42 add r11, r11, r12 /* runtime address of .dynamic section */
43 lwz r9, (p_rela - 0b)(r12)
44 add r9, r9, r12 /* runtime address of .rela.dyn section */
45 lwz r10, (p_st - 0b)(r12)
46 add r10, r10, r12 /* runtime address of _stext section */
47 lwz r13, (p_sym - 0b)(r12)
48 add r13, r13, r12 /* runtime address of .dynsym section */
49
50 /*
51 * Scan the dynamic section for RELA, RELASZ entries
52 */
53 li r6, 0
54 li r7, 0
55 li r8, 0
561: lwz r5, 0(r11) /* ELF_Dyn.d_tag */
57 cmpwi r5, 0 /* End of ELF_Dyn[] */
58 beq eodyn
59 cmpwi r5, DT_RELA
60 bne relasz
61 lwz r7, 4(r11) /* r7 = rela.link */
62 b skip
63relasz:
64 cmpwi r5, DT_RELASZ
65 bne relaent
66 lwz r8, 4(r11) /* r8 = Total Rela relocs size */
67 b skip
68relaent:
69 cmpwi r5, DT_RELAENT
70 bne skip
71 lwz r6, 4(r11) /* r6 = Size of one Rela reloc */
72skip:
73 addi r11, r11, 8
74 b 1b
75eodyn: /* End of Dyn Table scan */
76
77 /* Check if we have found all the entries */
78 cmpwi r7, 0
79 beq done
80 cmpwi r8, 0
81 beq done
82 cmpwi r6, 0
83 beq done
84
85
86 /*
87 * Work out the current offset from the link time address of .rela
88 * section.
89 * cur_offset[r7] = rela.run[r9] - rela.link [r7]
90 * _stext.link[r12] = _stext.run[r10] - cur_offset[r7]
91 * final_offset[r3] = _stext.final[r3] - _stext.link[r12]
92 */
93 subf r7, r7, r9 /* cur_offset */
94 subf r12, r7, r10
95 subf r3, r12, r3 /* final_offset */
96
97 subf r8, r6, r8 /* relaz -= relaent */
98 /*
99 * Scan through the .rela table and process each entry
100 * r9 - points to the current .rela table entry
101 * r13 - points to the symbol table
102 */
103
104 /*
105 * Check if we have a relocation based on symbol
106 * r5 will hold the value of the symbol.
107 */
108applyrela:
109 lwz r4, 4(r9) /* r4 = rela.r_info */
110 srwi r5, r4, 8 /* ELF32_R_SYM(r_info) */
111 cmpwi r5, STN_UNDEF /* sym == STN_UNDEF ? */
112 beq get_type /* value = 0 */
113 /* Find the value of the symbol at index(r5) */
114 slwi r5, r5, 4 /* r5 = r5 * sizeof(Elf32_Sym) */
115 add r12, r13, r5 /* r12 = &__dyn_sym[Index] */
116
117 /*
118 * GNU ld has a bug, where dynamic relocs based on
119 * STB_LOCAL symbols, the value should be assumed
120 * to be zero. - Alan Modra
121 */
122 /* XXX: Do we need to check if we are using GNU ld ? */
123 lbz r5, 12(r12) /* r5 = dyn_sym[Index].st_info */
124 extrwi r5, r5, 4, 24 /* r5 = ELF32_ST_BIND(r5) */
125 cmpwi r5, STB_LOCAL /* st_value = 0, ld bug */
126 beq get_type /* We have r5 = 0 */
127 lwz r5, 4(r12) /* r5 = __dyn_sym[Index].st_value */
128
129get_type:
130 /* Load the relocation type to r4 */
131 extrwi r4, r4, 8, 24 /* r4 = ELF32_R_TYPE(r_info) = ((char*)r4)[3] */
132
133 /* R_PPC_RELATIVE */
134 cmpwi r4, R_PPC_RELATIVE
135 bne hi16
136 lwz r4, 0(r9) /* r_offset */
137 lwz r0, 8(r9) /* r_addend */
138 add r0, r0, r3 /* final addend */
139 stwx r0, r4, r7 /* memory[r4+r7]) = (u32)r0 */
140 b nxtrela /* continue */
141
142 /* R_PPC_ADDR16_HI */
143hi16:
144 cmpwi r4, R_PPC_ADDR16_HI
145 bne ha16
146 lwz r4, 0(r9) /* r_offset */
147 lwz r0, 8(r9) /* r_addend */
148 add r0, r0, r3
149 add r0, r0, r5 /* r0 = (S+A+Offset) */
150 extrwi r0, r0, 16, 0 /* r0 = (r0 >> 16) */
151 b store_half
152
153 /* R_PPC_ADDR16_HA */
154ha16:
155 cmpwi r4, R_PPC_ADDR16_HA
156 bne lo16
157 lwz r4, 0(r9) /* r_offset */
158 lwz r0, 8(r9) /* r_addend */
159 add r0, r0, r3
160 add r0, r0, r5 /* r0 = (S+A+Offset) */
161 extrwi r5, r0, 1, 16 /* Extract bit 16 */
162 extrwi r0, r0, 16, 0 /* r0 = (r0 >> 16) */
163 add r0, r0, r5 /* Add it to r0 */
164 b store_half
165
166 /* R_PPC_ADDR16_LO */
167lo16:
168 cmpwi r4, R_PPC_ADDR16_LO
169 bne nxtrela
170 lwz r4, 0(r9) /* r_offset */
171 lwz r0, 8(r9) /* r_addend */
172 add r0, r0, r3
173 add r0, r0, r5 /* r0 = (S+A+Offset) */
174 extrwi r0, r0, 16, 16 /* r0 &= 0xffff */
175 /* Fall through to */
176
177 /* Store half word */
178store_half:
179 sthx r0, r4, r7 /* memory[r4+r7] = (u16)r0 */
180
181nxtrela:
182 /*
183 * We have to flush the modified instructions to the
184 * main storage from the d-cache. And also, invalidate the
185 * cached instructions in i-cache which has been modified.
186 *
187 * We delay the sync / isync operation till the end, since
188 * we won't be executing the modified instructions until
189 * we return from here.
190 */
191 dcbst r4,r7
192 sync /* Ensure the data is flushed before icbi */
193 icbi r4,r7
194 cmpwi r8, 0 /* relasz = 0 ? */
195 ble done
196 add r9, r9, r6 /* move to next entry in the .rela table */
197 subf r8, r6, r8 /* relasz -= relaent */
198 b applyrela
199
200done:
201 sync /* Wait for the flush to finish */
202 isync /* Discard prefetched instructions */
203 blr
204
205p_dyn: .long __dynamic_start - 0b
206p_rela: .long __rela_dyn_start - 0b
207p_sym: .long __dynamic_symtab - 0b
208p_st: .long _stext - 0b
diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S
index 920276c0f6a1..710a54005dfb 100644
--- a/arch/powerpc/kernel/vmlinux.lds.S
+++ b/arch/powerpc/kernel/vmlinux.lds.S
@@ -170,7 +170,13 @@ SECTIONS
170 } 170 }
171#ifdef CONFIG_RELOCATABLE 171#ifdef CONFIG_RELOCATABLE
172 . = ALIGN(8); 172 . = ALIGN(8);
173 .dynsym : AT(ADDR(.dynsym) - LOAD_OFFSET) { *(.dynsym) } 173 .dynsym : AT(ADDR(.dynsym) - LOAD_OFFSET)
174 {
175#ifdef CONFIG_RELOCATABLE_PPC32
176 __dynamic_symtab = .;
177#endif
178 *(.dynsym)
179 }
174 .dynstr : AT(ADDR(.dynstr) - LOAD_OFFSET) { *(.dynstr) } 180 .dynstr : AT(ADDR(.dynstr) - LOAD_OFFSET) { *(.dynstr) }
175 .dynamic : AT(ADDR(.dynamic) - LOAD_OFFSET) 181 .dynamic : AT(ADDR(.dynamic) - LOAD_OFFSET)
176 { 182 {
diff --git a/arch/powerpc/relocs_check.pl b/arch/powerpc/relocs_check.pl
index d2571096c3e9..7f5b83808862 100755
--- a/arch/powerpc/relocs_check.pl
+++ b/arch/powerpc/relocs_check.pl
@@ -32,8 +32,18 @@ while (<FD>) {
32 next if (!/\s+R_/); 32 next if (!/\s+R_/);
33 33
34 # These relocations are okay 34 # These relocations are okay
35 next if (/R_PPC64_RELATIVE/ or /R_PPC64_NONE/ or 35 # On PPC64:
36 /R_PPC64_ADDR64\s+mach_/); 36 # R_PPC64_RELATIVE, R_PPC64_NONE, R_PPC64_ADDR64
37 # On PPC:
38 # R_PPC_RELATIVE, R_PPC_ADDR16_HI,
39 # R_PPC_ADDR16_HA,R_PPC_ADDR16_LO,
40 # R_PPC_NONE
41
42 next if (/\bR_PPC64_RELATIVE\b/ or /\bR_PPC64_NONE\b/ or
43 /\bR_PPC64_ADDR64\s+mach_/);
44 next if (/\bR_PPC_ADDR16_LO\b/ or /\bR_PPC_ADDR16_HI\b/ or
45 /\bR_PPC_ADDR16_HA\b/ or /\bR_PPC_RELATIVE\b/ or
46 /\bR_PPC_NONE\b/);
37 47
38 # If we see this type of relcoation it's an idication that 48 # If we see this type of relcoation it's an idication that
39 # we /may/ be using an old version of binutils. 49 # we /may/ be using an old version of binutils.