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>
This commit is contained in:
Roman Zippel 2007-05-31 00:40:50 -07:00 committed by Linus Torvalds
parent 1fc799e1b4
commit fbe9c96129
9 changed files with 107 additions and 7 deletions

View File

@ -19,6 +19,7 @@ COMPILE_ARCH = $(shell uname -m)
# override top level makefile # override top level makefile
AS += -m68020 AS += -m68020
LDFLAGS := -m m68kelf LDFLAGS := -m m68kelf
LDFLAGS_MODULE += -T $(srctree)/arch/m68k/kernel/module.lds
ifneq ($(COMPILE_ARCH),$(ARCH)) ifneq ($(COMPILE_ARCH),$(ARCH))
# prefix for cross-compiling binaries # prefix for cross-compiling binaries
CROSS_COMPILE = m68k-linux-gnu- CROSS_COMPILE = m68k-linux-gnu-

View File

@ -9,13 +9,12 @@ else
endif endif
extra-y += vmlinux.lds 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 sys_m68k.o time.o semaphore.o setup.o m68k_ksyms.o devres.o
devres-y = ../../../kernel/irq/devres.o devres-y = ../../../kernel/irq/devres.o
obj-$(CONFIG_PCI) += bios32.o obj-$(CONFIG_PCI) += bios32.o
obj-$(CONFIG_MODULES) += module.o
obj-y$(CONFIG_MMU_SUN3) += dma.o # no, it's not a typo obj-y$(CONFIG_MMU_SUN3) += dma.o # no, it's not a typo
EXTRA_AFLAGS := -traditional EXTRA_AFLAGS := -traditional

View File

@ -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/moduleloader.h>
#include <linux/elf.h> #include <linux/elf.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
@ -11,6 +17,8 @@
#define DEBUGP(fmt...) #define DEBUGP(fmt...)
#endif #endif
#ifdef CONFIG_MODULES
void *module_alloc(unsigned long size) void *module_alloc(unsigned long size)
{ {
if (size == 0) if (size == 0)
@ -118,11 +126,29 @@ int apply_relocate_add(Elf32_Shdr *sechdrs,
int module_finalize(const Elf_Ehdr *hdr, int module_finalize(const Elf_Ehdr *hdr,
const Elf_Shdr *sechdrs, const Elf_Shdr *sechdrs,
struct module *me) struct module *mod)
{ {
module_fixup(mod, mod->arch.fixup_start, mod->arch.fixup_end);
return 0; return 0;
} }
void module_arch_cleanup(struct module *mod) 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;
}
}
}

View File

@ -0,0 +1,7 @@
SECTIONS {
.m68k_fixup : {
__start_fixup = .;
*(.m68k_fixup)
__stop_fixup = .;
}
}

View File

@ -60,6 +60,11 @@ SECTIONS
__con_initcall_start = .; __con_initcall_start = .;
.con_initcall.init : { *(.con_initcall.init) } .con_initcall.init : { *(.con_initcall.init) }
__con_initcall_end = .; __con_initcall_end = .;
.m68k_fixup : {
__start_fixup = .;
*(.m68k_fixup)
__stop_fixup = .;
}
SECURITY_INIT SECURITY_INIT
#ifdef CONFIG_BLK_DEV_INITRD #ifdef CONFIG_BLK_DEV_INITRD
. = ALIGN(8192); . = ALIGN(8192);

View File

@ -54,6 +54,11 @@ __init_begin = .;
__con_initcall_start = .; __con_initcall_start = .;
.con_initcall.init : { *(.con_initcall.init) } .con_initcall.init : { *(.con_initcall.init) }
__con_initcall_end = .; __con_initcall_end = .;
.m68k_fixup : {
__start_fixup = .;
*(.m68k_fixup)
__stop_fixup = .;
}
SECURITY_INIT SECURITY_INIT
#ifdef CONFIG_BLK_DEV_INITRD #ifdef CONFIG_BLK_DEV_INITRD
. = ALIGN(8192); . = ALIGN(8192);

View File

@ -222,6 +222,9 @@ void __init paging_init(void)
pgprot_val(protection_map[i]) |= _PAGE_CACHE040; 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 * Map the physical memory available into the kernel virtual
* address space. It may allocate some memory for page * address space. It may allocate some memory for page

View File

@ -1,7 +1,38 @@
#ifndef _ASM_M68K_MODULE_H #ifndef _ASM_M68K_MODULE_H
#define _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_Shdr Elf32_Shdr
#define Elf_Sym Elf32_Sym #define Elf_Sym Elf32_Sym
#define Elf_Ehdr Elf32_Ehdr #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 */ #endif /* _ASM_M68K_MODULE_H */

View File

@ -27,6 +27,8 @@
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
#include <asm/module.h>
#define get_user_page(vaddr) __get_free_page(GFP_KERNEL) #define get_user_page(vaddr) __get_free_page(GFP_KERNEL)
#define free_user_page(page, addr) free_page(addr) #define free_user_page(page, addr) free_page(addr)
@ -114,14 +116,35 @@ typedef struct { unsigned long pgprot; } pgprot_t;
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
extern unsigned long m68k_memoffset;
#ifndef CONFIG_SUN3 #ifndef CONFIG_SUN3
#define WANT_PAGE_VIRTUAL #define WANT_PAGE_VIRTUAL
#ifdef CONFIG_SINGLE_MEMORY_CHUNK #ifdef CONFIG_SINGLE_MEMORY_CHUNK
extern unsigned long m68k_memoffset;
#define __pa(vaddr) ((unsigned long)(vaddr)+m68k_memoffset) static inline unsigned long ___pa(void *vaddr)
#define __va(paddr) ((void *)((unsigned long)(paddr)-m68k_memoffset)) {
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 #else
#define __pa(vaddr) virt_to_phys((void *)(vaddr)) #define __pa(vaddr) virt_to_phys((void *)(vaddr))
#define __va(paddr) phys_to_virt((unsigned long)(paddr)) #define __va(paddr) phys_to_virt((unsigned long)(paddr))