diff options
author | Gerd Hoffmann <kraxel@suse.de> | 2006-06-26 07:56:16 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-06-26 13:48:14 -0400 |
commit | d167a51877e94dda73dd656c51f363502309f713 (patch) | |
tree | eb02c2974b61777f575dfdc07d4c2adf83bde434 /arch/x86_64/kernel/module.c | |
parent | 240cd6a80642da528bfa382ec2ae4e3cb8991ea7 (diff) |
[PATCH] x86_64: x86_64 version of the smp alternative patch.
Changes are largely identical to the i386 version:
* alternative #define are moved to the new alternative.h file.
* one new elf section with pointers to the lock prefixes which can be
nop'ed out for non-smp.
* two new elf sections simliar to the "classic" alternatives to
replace SMP code with simpler UP code.
* fixup headers to use alternative.h instead of defining their own
LOCK / LOCK_PREFIX macros.
The patch reuses the i386 version of the alternatives code to avoid code
duplication. The code in alternatives.c was shuffled around a bit to
reduce the number of #ifdefs needed. It also got some tweaks needed for
x86_64 (vsyscall page handling) and new features (noreplacement option
which was x86_64 only up to now). Debug printk's are changed from
compile-time to runtime.
Loosely based on a early version from Bastian Blank <waldi@debian.org>
Signed-off-by: Gerd Hoffmann <kraxel@suse.de>
Signed-off-by: Andi Kleen <ak@suse.de>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/x86_64/kernel/module.c')
-rw-r--r-- | arch/x86_64/kernel/module.c | 38 |
1 files changed, 25 insertions, 13 deletions
diff --git a/arch/x86_64/kernel/module.c b/arch/x86_64/kernel/module.c index bac195c74bcc..9d0958ff547f 100644 --- a/arch/x86_64/kernel/module.c +++ b/arch/x86_64/kernel/module.c | |||
@@ -145,26 +145,38 @@ int apply_relocate(Elf_Shdr *sechdrs, | |||
145 | return -ENOSYS; | 145 | return -ENOSYS; |
146 | } | 146 | } |
147 | 147 | ||
148 | extern void apply_alternatives(void *start, void *end); | ||
149 | |||
150 | int module_finalize(const Elf_Ehdr *hdr, | 148 | int module_finalize(const Elf_Ehdr *hdr, |
151 | const Elf_Shdr *sechdrs, | 149 | const Elf_Shdr *sechdrs, |
152 | struct module *me) | 150 | struct module *me) |
153 | { | 151 | { |
154 | const Elf_Shdr *s; | 152 | const Elf_Shdr *s, *text = NULL, *alt = NULL, *locks = NULL; |
155 | char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; | 153 | char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; |
156 | 154 | ||
157 | /* look for .altinstructions to patch */ | 155 | for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) { |
158 | for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) { | 156 | if (!strcmp(".text", secstrings + s->sh_name)) |
159 | void *seg; | 157 | text = s; |
160 | if (strcmp(".altinstructions", secstrings + s->sh_name)) | 158 | if (!strcmp(".altinstructions", secstrings + s->sh_name)) |
161 | continue; | 159 | alt = s; |
162 | seg = (void *)s->sh_addr; | 160 | if (!strcmp(".smp_locks", secstrings + s->sh_name)) |
163 | apply_alternatives(seg, seg + s->sh_size); | 161 | locks= s; |
164 | } | 162 | } |
163 | |||
164 | if (alt) { | ||
165 | /* patch .altinstructions */ | ||
166 | void *aseg = (void *)alt->sh_addr; | ||
167 | apply_alternatives(aseg, aseg + alt->sh_size); | ||
168 | } | ||
169 | if (locks && text) { | ||
170 | void *lseg = (void *)locks->sh_addr; | ||
171 | void *tseg = (void *)text->sh_addr; | ||
172 | alternatives_smp_module_add(me, me->name, | ||
173 | lseg, lseg + locks->sh_size, | ||
174 | tseg, tseg + text->sh_size); | ||
175 | } | ||
165 | return 0; | 176 | return 0; |
166 | } | 177 | } |
167 | 178 | ||
168 | void module_arch_cleanup(struct module *mod) | 179 | void module_arch_cleanup(struct module *mod) |
169 | { | 180 | { |
181 | alternatives_smp_module_del(mod); | ||
170 | } | 182 | } |