diff options
author | Roman Zippel <zippel@linux-m68k.org> | 2007-05-31 00:40:50 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-05-31 07:58:13 -0700 |
commit | fbe9c9612930e0604dc99ef2da7e063fa3278817 (patch) | |
tree | b11a5a03edd4a61fc5c71b2b38402cdfe914de22 | |
parent | 1fc799e1b4efdbc405d87d9f154d64d9bc299e5c (diff) |
m68k: runtime patching infrastructure
Add the basic infrastructure to allow runtime patching of kernel and modules
to optimize a few functions with parameters, which are only calculated once
during bootup and are otherwise constant. Use this for the conversion between
virtual and physical addresses.
Signed-off-by: Roman Zippel <zippel@linux-m68k.org>
Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | arch/m68k/Makefile | 1 | ||||
-rw-r--r-- | arch/m68k/kernel/Makefile | 3 | ||||
-rw-r--r-- | arch/m68k/kernel/module.c | 28 | ||||
-rw-r--r-- | arch/m68k/kernel/module.lds | 7 | ||||
-rw-r--r-- | arch/m68k/kernel/vmlinux-std.lds | 5 | ||||
-rw-r--r-- | arch/m68k/kernel/vmlinux-sun3.lds | 5 | ||||
-rw-r--r-- | arch/m68k/mm/motorola.c | 3 | ||||
-rw-r--r-- | include/asm-m68k/module.h | 33 | ||||
-rw-r--r-- | include/asm-m68k/page.h | 29 |
9 files changed, 107 insertions, 7 deletions
diff --git a/arch/m68k/Makefile b/arch/m68k/Makefile index c20831a7e1a..aa383a5ea7a 100644 --- a/arch/m68k/Makefile +++ b/arch/m68k/Makefile @@ -19,6 +19,7 @@ COMPILE_ARCH = $(shell uname -m) # override top level makefile AS += -m68020 LDFLAGS := -m m68kelf +LDFLAGS_MODULE += -T $(srctree)/arch/m68k/kernel/module.lds ifneq ($(COMPILE_ARCH),$(ARCH)) # prefix for cross-compiling binaries CROSS_COMPILE = m68k-linux-gnu- diff --git a/arch/m68k/kernel/Makefile b/arch/m68k/kernel/Makefile index 0b68ab8d63d..a806208c7fb 100644 --- a/arch/m68k/kernel/Makefile +++ b/arch/m68k/kernel/Makefile @@ -9,13 +9,12 @@ else endif extra-y += vmlinux.lds -obj-y := entry.o process.o traps.o ints.o signal.o ptrace.o \ +obj-y := entry.o process.o traps.o ints.o signal.o ptrace.o module.o \ sys_m68k.o time.o semaphore.o setup.o m68k_ksyms.o devres.o devres-y = ../../../kernel/irq/devres.o obj-$(CONFIG_PCI) += bios32.o -obj-$(CONFIG_MODULES) += module.o obj-y$(CONFIG_MMU_SUN3) += dma.o # no, it's not a typo EXTRA_AFLAGS := -traditional diff --git a/arch/m68k/kernel/module.c b/arch/m68k/kernel/module.c index 3b1a2ff61dd..32969d0cecc 100644 --- a/arch/m68k/kernel/module.c +++ b/arch/m68k/kernel/module.c @@ -1,3 +1,9 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + #include <linux/moduleloader.h> #include <linux/elf.h> #include <linux/vmalloc.h> @@ -11,6 +17,8 @@ #define DEBUGP(fmt...) #endif +#ifdef CONFIG_MODULES + void *module_alloc(unsigned long size) { if (size == 0) @@ -118,11 +126,29 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, int module_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, - struct module *me) + struct module *mod) { + module_fixup(mod, mod->arch.fixup_start, mod->arch.fixup_end); + return 0; } void module_arch_cleanup(struct module *mod) { } + +#endif /* CONFIG_MODULES */ + +void module_fixup(struct module *mod, struct m68k_fixup_info *start, + struct m68k_fixup_info *end) +{ + struct m68k_fixup_info *fixup; + + for (fixup = start; fixup < end; fixup++) { + switch (fixup->type) { + case m68k_fixup_memoffset: + *(u32 *)fixup->addr = m68k_memoffset; + break; + } + } +} diff --git a/arch/m68k/kernel/module.lds b/arch/m68k/kernel/module.lds new file mode 100644 index 00000000000..fda94fa3824 --- /dev/null +++ b/arch/m68k/kernel/module.lds @@ -0,0 +1,7 @@ +SECTIONS { + .m68k_fixup : { + __start_fixup = .; + *(.m68k_fixup) + __stop_fixup = .; + } +} diff --git a/arch/m68k/kernel/vmlinux-std.lds b/arch/m68k/kernel/vmlinux-std.lds index 78f139226a1..40f02b128f2 100644 --- a/arch/m68k/kernel/vmlinux-std.lds +++ b/arch/m68k/kernel/vmlinux-std.lds @@ -60,6 +60,11 @@ SECTIONS __con_initcall_start = .; .con_initcall.init : { *(.con_initcall.init) } __con_initcall_end = .; + .m68k_fixup : { + __start_fixup = .; + *(.m68k_fixup) + __stop_fixup = .; + } SECURITY_INIT #ifdef CONFIG_BLK_DEV_INITRD . = ALIGN(8192); diff --git a/arch/m68k/kernel/vmlinux-sun3.lds b/arch/m68k/kernel/vmlinux-sun3.lds index c8999b2db23..f06425b6d20 100644 --- a/arch/m68k/kernel/vmlinux-sun3.lds +++ b/arch/m68k/kernel/vmlinux-sun3.lds @@ -54,6 +54,11 @@ __init_begin = .; __con_initcall_start = .; .con_initcall.init : { *(.con_initcall.init) } __con_initcall_end = .; + .m68k_fixup : { + __start_fixup = .; + *(.m68k_fixup) + __stop_fixup = .; + } SECURITY_INIT #ifdef CONFIG_BLK_DEV_INITRD . = ALIGN(8192); diff --git a/arch/m68k/mm/motorola.c b/arch/m68k/mm/motorola.c index afcccdc6ad4..98ef00547b3 100644 --- a/arch/m68k/mm/motorola.c +++ b/arch/m68k/mm/motorola.c @@ -222,6 +222,9 @@ void __init paging_init(void) pgprot_val(protection_map[i]) |= _PAGE_CACHE040; } + module_fixup(NULL, __start_fixup, __stop_fixup); + flush_icache(); + /* * Map the physical memory available into the kernel virtual * address space. It may allocate some memory for page diff --git a/include/asm-m68k/module.h b/include/asm-m68k/module.h index c6d75af2d8d..71a1f76ac89 100644 --- a/include/asm-m68k/module.h +++ b/include/asm-m68k/module.h @@ -1,7 +1,38 @@ #ifndef _ASM_M68K_MODULE_H #define _ASM_M68K_MODULE_H -struct mod_arch_specific { }; + +struct mod_arch_specific { + struct m68k_fixup_info *fixup_start, *fixup_end; +}; + +#define MODULE_ARCH_INIT { \ + .fixup_start = __start_fixup, \ + .fixup_end = __stop_fixup, \ +} + #define Elf_Shdr Elf32_Shdr #define Elf_Sym Elf32_Sym #define Elf_Ehdr Elf32_Ehdr + + +enum m68k_fixup_type { + m68k_fixup_memoffset, +}; + +struct m68k_fixup_info { + enum m68k_fixup_type type; + void *addr; +}; + +#define m68k_fixup(type, addr) \ + " .section \".m68k_fixup\",\"aw\"\n" \ + " .long " #type "," #addr "\n" \ + " .previous\n" + +extern struct m68k_fixup_info __start_fixup[], __stop_fixup[]; + +struct module; +extern void module_fixup(struct module *mod, struct m68k_fixup_info *start, + struct m68k_fixup_info *end); + #endif /* _ASM_M68K_MODULE_H */ diff --git a/include/asm-m68k/page.h b/include/asm-m68k/page.h index fcc165ddd09..7650b99dcae 100644 --- a/include/asm-m68k/page.h +++ b/include/asm-m68k/page.h @@ -27,6 +27,8 @@ #ifndef __ASSEMBLY__ +#include <asm/module.h> + #define get_user_page(vaddr) __get_free_page(GFP_KERNEL) #define free_user_page(page, addr) free_page(addr) @@ -114,14 +116,35 @@ typedef struct { unsigned long pgprot; } pgprot_t; #ifndef __ASSEMBLY__ +extern unsigned long m68k_memoffset; + #ifndef CONFIG_SUN3 #define WANT_PAGE_VIRTUAL #ifdef CONFIG_SINGLE_MEMORY_CHUNK -extern unsigned long m68k_memoffset; -#define __pa(vaddr) ((unsigned long)(vaddr)+m68k_memoffset) -#define __va(paddr) ((void *)((unsigned long)(paddr)-m68k_memoffset)) +static inline unsigned long ___pa(void *vaddr) +{ + unsigned long paddr; + asm ( + "1: addl #0,%0\n" + m68k_fixup(%c2, 1b+2) + : "=r" (paddr) + : "0" (vaddr), "i" (m68k_fixup_memoffset)); + return paddr; +} +#define __pa(vaddr) ___pa((void *)(vaddr)) +static inline void *__va(unsigned long paddr) +{ + void *vaddr; + asm ( + "1: subl #0,%0\n" + m68k_fixup(%c2, 1b+2) + : "=r" (vaddr) + : "0" (paddr), "i" (m68k_fixup_memoffset)); + return vaddr; +} + #else #define __pa(vaddr) virt_to_phys((void *)(vaddr)) #define __va(paddr) phys_to_virt((unsigned long)(paddr)) |