aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/cputable.c
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2006-10-19 21:47:18 -0400
committerPaul Mackerras <paulus@samba.org>2006-10-24 21:54:07 -0400
commit0909c8c2d547e45ca50e2492b08ec93a37b35237 (patch)
tree23e66e1dc9a5bd674ba1375b5fccd2cb0d5787a8 /arch/powerpc/kernel/cputable.c
parent7aeb732428fc8e2ecae6d432873770c12f04a979 (diff)
[POWERPC] Support feature fixups in vdso's
This patch reworks the feature fixup mecanism so vdso's can be fixed up. The main issue was that the construct: .long label (or .llong on 64 bits) will not work in the case of a shared library like the vdso. It will generate an empty placeholder in the fixup table along with a reloc, which is not something we can deal with in the vdso. The idea here (thanks Alan Modra !) is to instead use something like: 1: .long label - 1b That is, the feature fixup tables no longer contain addresses of bits of code to patch, but offsets of such code from the fixup table entry itself. That is properly resolved by ld when building the .so's. I've modified the fixup mecanism generically to use that method for the rest of the kernel as well. Another trick is that the 32 bits vDSO included in the 64 bits kernel need to have a table in the 64 bits format. However, gas does not support 32 bits code with a statement of the form: .llong label - 1b (Or even just .llong label) That is, it cannot emit the right fixup/relocation for the linker to use to assign a 32 bits address to an .llong field. Thus, in the specific case of the 32 bits vdso built as part of the 64 bits kernel, we are using a modified macro that generates: .long 0xffffffff .llong label - 1b Note that is assumes that the value is negative which is enforced by the .lds (those offsets are always negative as the .text is always before the fixup table and gas doesn't support emiting the reloc the other way around). Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/kernel/cputable.c')
-rw-r--r--arch/powerpc/kernel/cputable.c11
1 files changed, 5 insertions, 6 deletions
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c
index 6fdfaa4a82b8..bfd499ee3753 100644
--- a/arch/powerpc/kernel/cputable.c
+++ b/arch/powerpc/kernel/cputable.c
@@ -1202,14 +1202,13 @@ struct cpu_spec *identify_cpu(unsigned long offset)
1202 return NULL; 1202 return NULL;
1203} 1203}
1204 1204
1205void do_feature_fixups(unsigned long offset, unsigned long value, 1205void do_feature_fixups(unsigned long value, void *fixup_start, void *fixup_end)
1206 void *fixup_start, void *fixup_end)
1207{ 1206{
1208 struct fixup_entry { 1207 struct fixup_entry {
1209 unsigned long mask; 1208 unsigned long mask;
1210 unsigned long value; 1209 unsigned long value;
1211 unsigned int *start; 1210 long start_off;
1212 unsigned int *end; 1211 long end_off;
1213 } *fcur, *fend; 1212 } *fcur, *fend;
1214 1213
1215 fcur = fixup_start; 1214 fcur = fixup_start;
@@ -1224,8 +1223,8 @@ void do_feature_fixups(unsigned long offset, unsigned long value,
1224 /* These PTRRELOCs will disappear once the new scheme for 1223 /* These PTRRELOCs will disappear once the new scheme for
1225 * modules and vdso is implemented 1224 * modules and vdso is implemented
1226 */ 1225 */
1227 pstart = PTRRELOC(fcur->start); 1226 pstart = ((unsigned int *)fcur) + (fcur->start_off / 4);
1228 pend = PTRRELOC(fcur->end); 1227 pend = ((unsigned int *)fcur) + (fcur->end_off / 4);
1229 1228
1230 for (p = pstart; p < pend; p++) { 1229 for (p = pstart; p < pend; p++) {
1231 *p = 0x60000000u; 1230 *p = 0x60000000u;