Commit 65d52cc9 authored by Linus Torvalds's avatar Linus Torvalds

Merge git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux-2.6-module-and-param

* git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux-2.6-module-and-param:
  module: cleanup FIXME comments about trimming exception table entries.
  module: trim exception table on init free.
  module: merge module_alloc() finally
  uml module: fix uml build process due to this merge
  x86 module: merge the rest functions with macros
  x86 module: merge the same functions in module_32.c and module_64.c
  uvesafb: improve parameter handling.
  module_param: allow 'bool' module_params to be bool, not just int.
  module_param: add __same_type convenience wrapper for __builtin_types_compatible_p
  module_param: split perm field into flags and perm
  module_param: invbool should take a 'bool', not an 'int'
  cyber2000fb.c: use proper method for stopping unload if CONFIG_ARCH_SHARK
parents d614aec4 5933048c
...@@ -48,6 +48,27 @@ void sort_extable(struct exception_table_entry *start, ...@@ -48,6 +48,27 @@ void sort_extable(struct exception_table_entry *start,
cmp_ex, swap_ex); cmp_ex, swap_ex);
} }
#ifdef CONFIG_MODULES
/*
* Any entry referring to the module init will be at the beginning or
* the end.
*/
void trim_init_extable(struct module *m)
{
/*trim the beginning*/
while (m->num_exentries &&
within_module_init(ex_to_addr(&m->extable[0]), m)) {
m->extable++;
m->num_exentries--;
}
/*trim the end*/
while (m->num_exentries &&
within_module_init(ex_to_addr(&m->extable[m->num_exentries-1]),
m))
m->num_exentries--;
}
#endif /* CONFIG_MODULES */
const struct exception_table_entry * const struct exception_table_entry *
search_extable(const struct exception_table_entry *first, search_extable(const struct exception_table_entry *first,
const struct exception_table_entry *last, const struct exception_table_entry *last,
......
...@@ -32,8 +32,6 @@ void module_free(struct module *mod, void *module_region) ...@@ -32,8 +32,6 @@ void module_free(struct module *mod, void *module_region)
mod->arch.syminfo = NULL; mod->arch.syminfo = NULL;
vfree(module_region); vfree(module_region);
/* FIXME: if module_region == mod->init_region, trim exception
* table entries. */
} }
static inline int check_rela(Elf32_Rela *rela, struct module *module, static inline int check_rela(Elf32_Rela *rela, struct module *module,
......
...@@ -48,8 +48,6 @@ void *module_alloc(unsigned long size) ...@@ -48,8 +48,6 @@ void *module_alloc(unsigned long size)
void module_free(struct module *mod, void *module_region) void module_free(struct module *mod, void *module_region)
{ {
FREE_MODULE(module_region); FREE_MODULE(module_region);
/* FIXME: If module_region == mod->init_region, trim exception
table entries. */
} }
/* We don't need anything special. */ /* We don't need anything special. */
......
...@@ -35,8 +35,6 @@ void *module_alloc(unsigned long size) ...@@ -35,8 +35,6 @@ void *module_alloc(unsigned long size)
void module_free(struct module *mod, void *module_region) void module_free(struct module *mod, void *module_region)
{ {
vfree(module_region); vfree(module_region);
/* FIXME: If module_region == mod->init_region, trim exception
table entries. */
} }
/* We don't need anything special. */ /* We don't need anything special. */
......
...@@ -23,8 +23,6 @@ void *module_alloc(unsigned long size) ...@@ -23,8 +23,6 @@ void *module_alloc(unsigned long size)
void module_free(struct module *mod, void *module_region) void module_free(struct module *mod, void *module_region)
{ {
vfree(module_region); vfree(module_region);
/* FIXME: If module_region == mod->init_region, trim exception
table entries. */
} }
/* We don't need anything special. */ /* We don't need anything special. */
......
...@@ -53,6 +53,32 @@ void sort_extable (struct exception_table_entry *start, ...@@ -53,6 +53,32 @@ void sort_extable (struct exception_table_entry *start,
cmp_ex, swap_ex); cmp_ex, swap_ex);
} }
static inline unsigned long ex_to_addr(const struct exception_table_entry *x)
{
return (unsigned long)&x->insn + x->insn;
}
#ifdef CONFIG_MODULES
/*
* Any entry referring to the module init will be at the beginning or
* the end.
*/
void trim_init_extable(struct module *m)
{
/*trim the beginning*/
while (m->num_exentries &&
within_module_init(ex_to_addr(&m->extable[0]), m)) {
m->extable++;
m->num_exentries--;
}
/*trim the end*/
while (m->num_exentries &&
within_module_init(ex_to_addr(&m->extable[m->num_exentries-1]),
m))
m->num_exentries--;
}
#endif /* CONFIG_MODULES */
const struct exception_table_entry * const struct exception_table_entry *
search_extable (const struct exception_table_entry *first, search_extable (const struct exception_table_entry *first,
const struct exception_table_entry *last, const struct exception_table_entry *last,
......
...@@ -44,8 +44,6 @@ void *module_alloc(unsigned long size) ...@@ -44,8 +44,6 @@ void *module_alloc(unsigned long size)
void module_free(struct module *mod, void *module_region) void module_free(struct module *mod, void *module_region)
{ {
vfree(module_region); vfree(module_region);
/* FIXME: If module_region == mod->init_region, trim exception
table entries. */
} }
/* We don't need anything special. */ /* We don't need anything special. */
......
...@@ -31,8 +31,6 @@ void *module_alloc(unsigned long size) ...@@ -31,8 +31,6 @@ void *module_alloc(unsigned long size)
void module_free(struct module *mod, void *module_region) void module_free(struct module *mod, void *module_region)
{ {
vfree(module_region); vfree(module_region);
/* FIXME: If module_region == mod->init_region, trim exception
table entries. */
} }
/* We don't need anything special. */ /* We don't need anything special. */
......
...@@ -23,8 +23,6 @@ void *module_alloc(unsigned long size) ...@@ -23,8 +23,6 @@ void *module_alloc(unsigned long size)
void module_free(struct module *mod, void *module_region) void module_free(struct module *mod, void *module_region)
{ {
vfree(module_region); vfree(module_region);
/* FIXME: If module_region == mod->init_region, trim exception
table entries. */
} }
/* We don't need anything special. */ /* We don't need anything special. */
......
...@@ -68,8 +68,6 @@ void *module_alloc(unsigned long size) ...@@ -68,8 +68,6 @@ void *module_alloc(unsigned long size)
void module_free(struct module *mod, void *module_region) void module_free(struct module *mod, void *module_region)
{ {
vfree(module_region); vfree(module_region);
/* FIXME: If module_region == mod->init_region, trim exception
table entries. */
} }
int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs, int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
......
...@@ -48,8 +48,6 @@ void *module_alloc(unsigned long size) ...@@ -48,8 +48,6 @@ void *module_alloc(unsigned long size)
void module_free(struct module *mod, void *module_region) void module_free(struct module *mod, void *module_region)
{ {
vfree(module_region); vfree(module_region);
/* FIXME: If module_region == mod->init_region, trim exception
* table entries. */
} }
/* /*
......
...@@ -267,8 +267,6 @@ void module_free(struct module *mod, void *module_region) ...@@ -267,8 +267,6 @@ void module_free(struct module *mod, void *module_region)
mod->arch.section = NULL; mod->arch.section = NULL;
vfree(module_region); vfree(module_region);
/* FIXME: If module_region == mod->init_region, trim exception
table entries. */
} }
/* Additional bytes needed in front of individual sections */ /* Additional bytes needed in front of individual sections */
......
...@@ -43,8 +43,6 @@ void *module_alloc(unsigned long size) ...@@ -43,8 +43,6 @@ void *module_alloc(unsigned long size)
void module_free(struct module *mod, void *module_region) void module_free(struct module *mod, void *module_region)
{ {
vfree(module_region); vfree(module_region);
/* FIXME: If module_region == mod->init_region, trim exception
table entries. */
} }
static const Elf_Shdr *find_section(const Elf_Ehdr *hdr, static const Elf_Shdr *find_section(const Elf_Ehdr *hdr,
......
...@@ -56,8 +56,6 @@ void *module_alloc(unsigned long size) ...@@ -56,8 +56,6 @@ void *module_alloc(unsigned long size)
void module_free(struct module *mod, void *module_region) void module_free(struct module *mod, void *module_region)
{ {
vfree(module_region); vfree(module_region);
/* FIXME: If module_region == mod->init_region, trim exception
table entries. */
} }
static void static void
......
...@@ -46,8 +46,6 @@ void *module_alloc(unsigned long size) ...@@ -46,8 +46,6 @@ void *module_alloc(unsigned long size)
void module_free(struct module *mod, void *module_region) void module_free(struct module *mod, void *module_region)
{ {
vfree(module_region); vfree(module_region);
/* FIXME: If module_region == mod->init_region, trim exception
table entries. */
} }
/* We don't need anything special. */ /* We don't need anything special. */
......
...@@ -17,6 +17,9 @@ ...@@ -17,6 +17,9 @@
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
#define ARCH_HAS_SORT_EXTABLE
#define ARCH_HAS_SEARCH_EXTABLE
/* Sparc is not segmented, however we need to be able to fool access_ok() /* Sparc is not segmented, however we need to be able to fool access_ok()
* when doing system calls from kernel mode legitimately. * when doing system calls from kernel mode legitimately.
* *
......
...@@ -75,8 +75,6 @@ void *module_alloc(unsigned long size) ...@@ -75,8 +75,6 @@ void *module_alloc(unsigned long size)
void module_free(struct module *mod, void *module_region) void module_free(struct module *mod, void *module_region)
{ {
vfree(module_region); vfree(module_region);
/* FIXME: If module_region == mod->init_region, trim exception
table entries. */
} }
/* Make generic code ignore STT_REGISTER dummy undefined symbols. */ /* Make generic code ignore STT_REGISTER dummy undefined symbols. */
......
...@@ -28,6 +28,10 @@ search_extable(const struct exception_table_entry *start, ...@@ -28,6 +28,10 @@ search_extable(const struct exception_table_entry *start,
* word 3: last insn address + 4 bytes * word 3: last insn address + 4 bytes
* word 4: fixup code address * word 4: fixup code address
* *
* Deleted entries are encoded as:
* word 1: unused
* word 2: -1
*
* See asm/uaccess.h for more details. * See asm/uaccess.h for more details.
*/ */
...@@ -39,6 +43,10 @@ search_extable(const struct exception_table_entry *start, ...@@ -39,6 +43,10 @@ search_extable(const struct exception_table_entry *start,
continue; continue;
} }
/* A deleted entry; see trim_init_extable */
if (walk->fixup == -1)
continue;
if (walk->insn == value) if (walk->insn == value)
return walk; return walk;
} }
...@@ -57,6 +65,27 @@ search_extable(const struct exception_table_entry *start, ...@@ -57,6 +65,27 @@ search_extable(const struct exception_table_entry *start,
return NULL; return NULL;
} }
#ifdef CONFIG_MODULES
/* We could memmove them around; easier to mark the trimmed ones. */
void trim_init_extable(struct module *m)
{
unsigned int i;
bool range;
for (i = 0; i < m->num_exentries; i += range ? 2 : 1) {
range = m->extable[i].fixup == 0;
if (within_module_init(m->extable[i].insn, m)) {
m->extable[i].fixup = -1;
if (range)
m->extable[i+1].fixup = -1;
}
if (range)
i++;
}
}
#endif /* CONFIG_MODULES */
/* Special extable search, which handles ranges. Returns fixup */ /* Special extable search, which handles ranges. Returns fixup */
unsigned long search_extables_range(unsigned long addr, unsigned long *g2) unsigned long search_extables_range(unsigned long addr, unsigned long *g2)
{ {
......
...@@ -53,16 +53,21 @@ extern unsigned long end_iomem; ...@@ -53,16 +53,21 @@ extern unsigned long end_iomem;
#else #else
# define VMALLOC_END (FIXADDR_START-2*PAGE_SIZE) # define VMALLOC_END (FIXADDR_START-2*PAGE_SIZE)
#endif #endif
#define MODULES_VADDR VMALLOC_START
#define MODULES_END VMALLOC_END
#define MODULES_LEN (MODULES_VADDR - MODULES_END)
#define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY) #define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY)
#define _KERNPG_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY) #define _KERNPG_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)
#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY) #define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
#define __PAGE_KERNEL_EXEC \
(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
#define PAGE_NONE __pgprot(_PAGE_PROTNONE | _PAGE_ACCESSED) #define PAGE_NONE __pgprot(_PAGE_PROTNONE | _PAGE_ACCESSED)
#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED) #define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED)
#define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED) #define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED) #define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
#define PAGE_KERNEL __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED) #define PAGE_KERNEL __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
#define PAGE_KERNEL_EXEC __pgprot(__PAGE_KERNEL_EXEC)
/* /*
* The i386 can't do page protection for execute, and considers that the same * The i386 can't do page protection for execute, and considers that the same
......
...@@ -8,7 +8,7 @@ obj-y = bug.o bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \ ...@@ -8,7 +8,7 @@ obj-y = bug.o bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \
subarch-obj-y = lib/semaphore_32.o lib/string_32.o subarch-obj-y = lib/semaphore_32.o lib/string_32.o
subarch-obj-$(CONFIG_HIGHMEM) += mm/highmem_32.o subarch-obj-$(CONFIG_HIGHMEM) += mm/highmem_32.o
subarch-obj-$(CONFIG_MODULES) += kernel/module_32.o subarch-obj-$(CONFIG_MODULES) += kernel/module.o
USER_OBJS := bugs.o ptrace_user.o fault.o USER_OBJS := bugs.o ptrace_user.o fault.o
......
...@@ -8,10 +8,8 @@ obj-y = bug.o bugs.o delay.o fault.o ldt.o mem.o ptrace.o ptrace_user.o \ ...@@ -8,10 +8,8 @@ obj-y = bug.o bugs.o delay.o fault.o ldt.o mem.o ptrace.o ptrace_user.o \
setjmp.o signal.o stub.o stub_segv.o syscalls.o syscall_table.o \ setjmp.o signal.o stub.o stub_segv.o syscalls.o syscall_table.o \
sysrq.o ksyms.o tls.o sysrq.o ksyms.o tls.o
obj-$(CONFIG_MODULES) += um_module.o
subarch-obj-y = lib/csum-partial_64.o lib/memcpy_64.o lib/thunk_64.o subarch-obj-y = lib/csum-partial_64.o lib/memcpy_64.o lib/thunk_64.o
subarch-obj-$(CONFIG_MODULES) += kernel/module_64.o subarch-obj-$(CONFIG_MODULES) += kernel/module.o
ldt-y = ../sys-i386/ldt.o ldt-y = ../sys-i386/ldt.o
......
#include <linux/vmalloc.h>
#include <linux/moduleloader.h>
/* Copied from i386 arch/i386/kernel/module.c */
void *module_alloc(unsigned long size)
{
if (size == 0)
return NULL;
return vmalloc_exec(size);
}
/* Free memory returned from module_alloc */
void module_free(struct module *mod, void *module_region)
{
vfree(module_region);
/*
* FIXME: If module_region == mod->init_region, trim exception
* table entries.
*/
}
...@@ -46,6 +46,10 @@ extern bool __vmalloc_start_set; /* set once high_memory is set */ ...@@ -46,6 +46,10 @@ extern bool __vmalloc_start_set; /* set once high_memory is set */
# define VMALLOC_END (FIXADDR_START - 2 * PAGE_SIZE) # define VMALLOC_END (FIXADDR_START - 2 * PAGE_SIZE)
#endif #endif
#define MODULES_VADDR VMALLOC_START
#define MODULES_END VMALLOC_END
#define MODULES_LEN (MODULES_VADDR - MODULES_END)
#define MAXMEM (VMALLOC_END - PAGE_OFFSET - __VMALLOC_RESERVE) #define MAXMEM (VMALLOC_END - PAGE_OFFSET - __VMALLOC_RESERVE)
#endif /* _ASM_X86_PGTABLE_32_DEFS_H */ #endif /* _ASM_X86_PGTABLE_32_DEFS_H */
...@@ -73,7 +73,7 @@ obj-$(CONFIG_KEXEC) += machine_kexec_$(BITS).o ...@@ -73,7 +73,7 @@ obj-$(CONFIG_KEXEC) += machine_kexec_$(BITS).o
obj-$(CONFIG_KEXEC) += relocate_kernel_$(BITS).o crash.o obj-$(CONFIG_KEXEC) += relocate_kernel_$(BITS).o crash.o
obj-$(CONFIG_CRASH_DUMP) += crash_dump_$(BITS).o obj-$(CONFIG_CRASH_DUMP) += crash_dump_$(BITS).o
obj-$(CONFIG_KPROBES) += kprobes.o obj-$(CONFIG_KPROBES) += kprobes.o
obj-$(CONFIG_MODULES) += module_$(BITS).o obj-$(CONFIG_MODULES) += module.o
obj-$(CONFIG_EFI) += efi.o efi_$(BITS).o efi_stub_$(BITS).o obj-$(CONFIG_EFI) += efi.o efi_$(BITS).o efi_stub_$(BITS).o
obj-$(CONFIG_DOUBLEFAULT) += doublefault_32.o obj-$(CONFIG_DOUBLEFAULT) += doublefault_32.o
obj-$(CONFIG_KGDB) += kgdb.o obj-$(CONFIG_KGDB) += kgdb.o
......
/* Kernel module help for x86-64 /* Kernel module help for x86.
Copyright (C) 2001 Rusty Russell. Copyright (C) 2001 Rusty Russell.
Copyright (C) 2002,2003 Andi Kleen, SuSE Labs.
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
...@@ -22,23 +21,18 @@ ...@@ -22,23 +21,18 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/bug.h> #include <linux/bug.h>
#include <linux/mm.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/page.h> #include <asm/page.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
#if 0
#define DEBUGP printk
#else
#define DEBUGP(fmt...) #define DEBUGP(fmt...)
#endif
#ifndef CONFIG_UML
void module_free(struct module *mod, void *module_region)
{
vfree(module_region);
/* FIXME: If module_region == mod->init_region, trim exception
table entries. */
}
void *module_alloc(unsigned long size) void *module_alloc(unsigned long size)
{ {
...@@ -54,9 +48,15 @@ void *module_alloc(unsigned long size) ...@@ -54,9 +48,15 @@ void *module_alloc(unsigned long size)
if (!area) if (!area)
return NULL; return NULL;
return __vmalloc_area(area, GFP_KERNEL, PAGE_KERNEL_EXEC); return __vmalloc_area(area, GFP_KERNEL | __GFP_HIGHMEM,
PAGE_KERNEL_EXEC);
}
/* Free memory returned from module_alloc */
void module_free(struct module *mod, void *module_region)
{
vfree(module_region);
} }
#endif
/* We don't need anything special. */ /* We don't need anything special. */
int module_frob_arch_sections(Elf_Ehdr *hdr, int module_frob_arch_sections(Elf_Ehdr *hdr,
...@@ -67,6 +67,58 @@ int module_frob_arch_sections(Elf_Ehdr *hdr, ...@@ -67,6 +67,58 @@ int module_frob_arch_sections(Elf_Ehdr *hdr,
return 0; return 0;
} }
#ifdef CONFIG_X86_32
int apply_relocate(Elf32_Shdr *sechdrs,
const char *strtab,
unsigned int symindex,
unsigned int relsec,
struct module *me)
{
unsigned int i;
Elf32_Rel *rel = (void *)sechdrs[relsec].sh_addr;
Elf32_Sym *sym;
uint32_t *location;
DEBUGP("Applying relocate section %u to %u\n", relsec,
sechdrs[relsec].sh_info);
for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
/* This is where to make the change */
location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
+ rel[i].r_offset;
/* This is the symbol it is referring to. Note that all
undefined symbols have been resolved. */
sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
+ ELF32_R_SYM(rel[i].r_info);
switch (ELF32_R_TYPE(rel[i].r_info)) {
case R_386_32:
/* We add the value into the location given */
*location += sym->st_value;
break;
case R_386_PC32:
/* Add the value, subtract its postition */
*location += sym->st_value - (uint32_t)location;
break;
default:
printk(KERN_ERR "module %s: Unknown relocation: %u\n",
me->name, ELF32_R_TYPE(rel[i].r_info));
return -ENOEXEC;
}
}
return 0;
}
int apply_relocate_add(Elf32_Shdr *sechdrs,
const char *strtab,
unsigned int symindex,
unsigned int relsec,
struct module *me)
{
printk(KERN_ERR "module %s: ADD RELOCATION unsupported\n",
me->name);
return -ENOEXEC;
}
#else /*X86_64*/
int apply_relocate_add(Elf64_Shdr *sechdrs, int apply_relocate_add(Elf64_Shdr *sechdrs,
const char *strtab, const char *strtab,
unsigned int symindex, unsigned int symindex,
...@@ -147,6 +199,8 @@ int apply_relocate(Elf_Shdr *sechdrs, ...@@ -147,6 +199,8 @@ int apply_relocate(Elf_Shdr *sechdrs,
return -ENOSYS; return -ENOSYS;
} }
#endif
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 *me)
......
/* Kernel module help for i386.
Copyright (C) 2001 Rusty Russell.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/moduleloader.h>
#include <linux/elf.h>
#include <linux/vmalloc.h>
#include <linux/fs.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/bug.h>
#if 0
#define DEBUGP printk
#else
#define DEBUGP(fmt...)
#endif
void *module_alloc(unsigned long size)
{
if (size == 0)
return NULL;
return vmalloc_exec(size);
}
/* Free memory returned from module_alloc */
void module_free(struct module *mod, void *module_region)
{
vfree(module_region);
/* FIXME: If module_region == mod->init_region, trim exception
table entries. */
}
/* We don't need anything special. */
int module_frob_arch_sections(Elf_Ehdr *hdr,
Elf_Shdr *sechdrs,
char *secstrings,
struct module *mod)
{
return 0;
}
int apply_relocate(Elf32_Shdr *sechdrs,
const char *strtab,
unsigned int symindex,
unsigned int relsec,
struct module *me)
{
unsigned int i;
Elf32_Rel *rel = (void *)sechdrs[relsec].sh_addr;
Elf32_Sym *sym;
uint32_t *location;
DEBUGP("Applying relocate section %u to %u\n", relsec,
sechdrs[relsec].sh_info);
for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
/* This is where to make the change */
location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
+ rel[i].r_offset;
/* This is the symbol it is referring to. Note that all
undefined symbols have been resolved. */
sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
+ ELF32_R_SYM(rel[i].r_info);
switch (ELF32_R_TYPE(rel[i].r_info)) {
case R_386_32:
/* We add the value into the location given */
*location += sym->st_value;
break;
case R_386_PC32:
/* Add the value, subtract its postition */
*location += sym->st_value - (uint32_t)location;
break;
default:
printk(KERN_ERR "module %s: Unknown relocation: %u\n",
me->name, ELF32_R_TYPE(rel[i].r_info));
return -ENOEXEC;
}
}
return 0;
}
int apply_relocate_add(Elf32_Shdr *sechdrs,
const char *strtab,
unsigned int symindex,
unsigned int relsec,
struct module *me)
{
printk(KERN_ERR "module %s: ADD RELOCATION unsupported\n",
me->name);
return -ENOEXEC;
}
int module_finalize(const Elf_Ehdr *hdr,
const Elf_Shdr *sechdrs,
struct module *me)
{
const Elf_Shdr *s, *text = NULL, *alt = NULL, *locks = NULL,
*para = NULL;
char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) {
if (!strcmp(".text", secstrings + s->sh_name))
text = s;
if (!strcmp(".altinstructions", secstrings + s->sh_name))
alt = s;
if (!strcmp(".smp_locks", secstrings + s->sh_name))
locks = s;
if (!strcmp(".parainstructions", secstrings + s->sh_name))
para = s;
}
if (alt) {
/* patch .altinstructions */
void *aseg = (void *)alt->sh_addr;
apply_alternatives(aseg, aseg + alt->sh_size);
}
if (locks && text) {
void *lseg = (void *)locks->sh_addr;
void *tseg = (void *)text->sh_addr;
alternatives_smp_module_add(me, me->name,
lseg, lseg + locks->sh_size,
tseg, tseg + text->sh_size);
}
if (para) {
void *pseg = (void *)para->sh_addr;
apply_paravirt(pseg, pseg + para->sh_size);
}
return module_bug_finalize(hdr, sechdrs, me);
}
void module_arch_cleanup(struct module *mod)
{
alternatives_smp_module_del(mod);
module_bug_cleanup(mod);
}
...@@ -34,8 +34,6 @@ void *module_alloc(unsigned long size) ...@@ -34,8 +34,6 @@ void *module_alloc(unsigned long size)
void module_free(struct module *mod, void *module_region) void module_free(struct module *mod, void *module_region)
{ {
vfree(module_region); vfree(module_region);
/* FIXME: If module_region == mod->init_region, trim exception
table entries. */
} }
int module_frob_arch_sections(Elf32_Ehdr *hdr, int module_frob_arch_sections(Elf32_Ehdr *hdr,
......
...@@ -354,7 +354,7 @@ static int default_crt_on __devinitdata = 0; ...@@ -354,7 +354,7 @@ static int default_crt_on __devinitdata = 0;
static int default_lcd_on __devinitdata = 1; static int default_lcd_on __devinitdata = 1;
#ifdef CONFIG_MTRR #ifdef CONFIG_MTRR
static int mtrr = 1; static bool mtrr = true;
#endif #endif
#ifdef CONFIG_PMAC_BACKLIGHT #ifdef CONFIG_PMAC_BACKLIGHT
......
...@@ -1736,10 +1736,8 @@ static int __init cyber2000fb_init(void) ...@@ -1736,10 +1736,8 @@ static int __init cyber2000fb_init(void)
#ifdef CONFIG_ARCH_SHARK #ifdef CONFIG_ARCH_SHARK
err = cyberpro_vl_probe(); err = cyberpro_vl_probe();
if (!err) { if (!err)
ret = 0; ret = 0;
__module_get(THIS_MODULE);
}
#endif #endif
#ifdef CONFIG_PCI #ifdef CONFIG_PCI
err = pci_register_driver(&cyberpro_driver); err = pci_register_driver(&cyberpro_driver);
...@@ -1749,14 +1747,15 @@ static int __init cyber2000fb_init(void) ...@@ -1749,14 +1747,15 @@ static int __init cyber2000fb_init(void)
return ret ? err : 0; return ret ? err : 0;
} }
module_init(cyber2000fb_init);
#ifndef CONFIG_ARCH_SHARK
static void __exit cyberpro_exit(void) static void __exit cyberpro_exit(void)
{ {
pci_unregister_driver(&cyberpro_driver); pci_unregister_driver(&cyberpro_driver);
} }
module_init(cyber2000fb_init);
module_exit(cyberpro_exit); module_exit(cyberpro_exit);
#endif
MODULE_AUTHOR("Russell King"); MODULE_AUTHOR("Russell King");
MODULE_DESCRIPTION("CyberPro 2000, 2010 and 5000 framebuffer driver"); MODULE_DESCRIPTION("CyberPro 2000, 2010 and 5000 framebuffer driver");
......
...@@ -45,7 +45,7 @@ static struct fb_fix_screeninfo uvesafb_fix __devinitdata = { ...@@ -45,7 +45,7 @@ static struct fb_fix_screeninfo uvesafb_fix __devinitdata = {
static int mtrr __devinitdata = 3; /* enable mtrr by default */ static int mtrr __devinitdata = 3; /* enable mtrr by default */
static int blank = 1; /* enable blanking by default */ static int blank = 1; /* enable blanking by default */
static int ypan = 1; /* 0: scroll, 1: ypan, 2: ywrap */ static int ypan = 1; /* 0: scroll, 1: ypan, 2: ywrap */
static int pmi_setpal __devinitdata = 1; /* use PMI for palette changes */ static bool pmi_setpal __devinitdata = true; /* use PMI for palette changes */
static int nocrtc __devinitdata; /* ignore CRTC settings */ static int nocrtc __devinitdata; /* ignore CRTC settings */
static int noedid __devinitdata; /* don't try DDC transfers */ static int noedid __devinitdata; /* don't try DDC transfers */
static int vram_remap __devinitdata; /* set amt. of memory to be used */ static int vram_remap __devinitdata; /* set amt. of memory to be used */
...@@ -2002,11 +2002,7 @@ static void __devexit uvesafb_exit(void) ...@@ -2002,11 +2002,7 @@ static void __devexit uvesafb_exit(void)
module_exit(uvesafb_exit); module_exit(uvesafb_exit);
static int param_get_scroll(char *buffer, struct kernel_param *kp) #define param_get_scroll NULL
{
return 0;
}
static int param_set_scroll(const char *val, struct kernel_param *kp) static int param_set_scroll(const char *val, struct kernel_param *kp)
{ {
ypan = 0; ypan = 0;
...@@ -2017,6 +2013,8 @@ static int param_set_scroll(const char *val, struct kernel_param *kp) ...@@ -2017,6 +2013,8 @@ static int param_set_scroll(const char *val, struct kernel_param *kp)
ypan = 1; ypan = 1;
else if (!strcmp(val, "ywrap")) else if (!strcmp(val, "ywrap"))
ypan = 2; ypan = 2;
else
return -EINVAL;
return 0; return 0;
} }
......
...@@ -261,6 +261,11 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect); ...@@ -261,6 +261,11 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect);
# define __section(S) __attribute__ ((__section__(#S))) # define __section(S) __attribute__ ((__section__(#S)))
#endif #endif
/* Are two types/vars the same type (ignoring qualifiers)? */
#ifndef __same_type
# define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
#endif
/* /*
* Prevent the compiler from merging or refetching accesses. The compiler * Prevent the compiler from merging or refetching accesses. The compiler
* is also forbidden from reordering successive instances of ACCESS_ONCE(), * is also forbidden from reordering successive instances of ACCESS_ONCE(),
......
...@@ -77,6 +77,7 @@ search_extable(const struct exception_table_entry *first, ...@@ -77,6 +77,7 @@ search_extable(const struct exception_table_entry *first,
void sort_extable(struct exception_table_entry *start, void sort_extable(struct exception_table_entry *start,
struct exception_table_entry *finish); struct exception_table_entry *finish);
void sort_main_extable(void); void sort_main_extable(void);
void trim_init_extable(struct module *m);
#ifdef MODULE #ifdef MODULE
#define MODULE_GENERIC_TABLE(gtype,name) \ #define MODULE_GENERIC_TABLE(gtype,name) \
......
...@@ -36,9 +36,14 @@ typedef int (*param_set_fn)(const char *val, struct kernel_param *kp); ...@@ -36,9 +36,14 @@ typedef int (*param_set_fn)(const char *val, struct kernel_param *kp);
/* Returns length written or -errno. Buffer is 4k (ie. be short!) */ /* Returns length written or -errno. Buffer is 4k (ie. be short!) */
typedef int (*param_get_fn)(char *buffer, struct kernel_param *kp); typedef int (*param_get_fn)(char *buffer, struct kernel_param *kp);
/* Flag bits for kernel_param.flags */
#define KPARAM_KMALLOCED 1
#define KPARAM_ISBOOL 2
struct kernel_param { struct kernel_param {
const char *name; const char *name;
unsigned int perm; u16 perm;
u16 flags;
param_set_fn set; param_set_fn set;
param_get_fn get; param_get_fn get;
union { union {
...@@ -79,7 +84,7 @@ struct kparam_array ...@@ -79,7 +84,7 @@ struct kparam_array
parameters. perm sets the visibility in sysfs: 000 means it's parameters. perm sets the visibility in sysfs: 000 means it's
not there, read bits mean it's readable, write bits mean it's not there, read bits mean it's readable, write bits mean it's
writable. */ writable. */
#define __module_param_call(prefix, name, set, get, arg, perm) \ #define __module_param_call(prefix, name, set, get, arg, isbool, perm) \
/* Default value instead of permissions? */ \ /* Default value instead of permissions? */ \
static int __param_perm_check_##name __attribute__((unused)) = \ static int __param_perm_check_##name __attribute__((unused)) = \
BUILD_BUG_ON_ZERO((perm) < 0 || (perm) > 0777 || ((perm) & 2)) \ BUILD_BUG_ON_ZERO((perm) < 0 || (perm) > 0777 || ((perm) & 2)) \
...@@ -88,10 +93,13 @@ struct kparam_array ...@@ -88,10 +93,13 @@ struct kparam_array
static struct kernel_param __moduleparam_const __param_##name \ static struct kernel_param __moduleparam_const __param_##name \
__used \ __used \
__attribute__ ((unused,__section__ ("__param"),aligned(sizeof(void *)))) \ __attribute__ ((unused,__section__ ("__param"),aligned(sizeof(void *)))) \
= { __param_str_##name, perm, set, get, { arg } } = { __param_str_##name, perm, isbool ? KPARAM_ISBOOL : 0, \
set, get, { arg } }
#define module_param_call(name, set, get, arg, perm) \ #define module_param_call(name, set, get, arg, perm) \
__module_param_call(MODULE_PARAM_PREFIX, name, set, get, arg, perm) __module_param_call(MODULE_PARAM_PREFIX, \
name, set, get, arg, \
__same_type(*(arg), bool), perm)
/* Helper functions: type is byte, short, ushort, int, uint, long, /* Helper functions: type is byte, short, ushort, int, uint, long,
ulong, charp, bool or invbool, or XXX if you define param_get_XXX, ulong, charp, bool or invbool, or XXX if you define param_get_XXX,
...@@ -120,15 +128,16 @@ struct kparam_array ...@@ -120,15 +128,16 @@ struct kparam_array
#define core_param(name, var, type, perm) \ #define core_param(name, var, type, perm) \
param_check_##type(name, &(var)); \ param_check_##type(name, &(var)); \
__module_param_call("", name, param_set_##type, param_get_##type, \ __module_param_call("", name, param_set_##type, param_get_##type, \
&var, perm) &var, __same_type(var, bool), perm)
#endif /* !MODULE */ #endif /* !MODULE */
/* Actually copy string: maxlen param is usually sizeof(string). */ /* Actually copy string: maxlen param is usually sizeof(string). */
#define module_param_string(name, string, len, perm) \ #define module_param_string(name, string, len, perm) \
static const struct kparam_string __param_string_##name \ static const struct kparam_string __param_string_##name \
= { len, string }; \ = { len, string }; \
module_param_call(name, param_set_copystring, param_get_string, \ __module_param_call(MODULE_PARAM_PREFIX, name, \
.str = &__param_string_##name, perm); \ param_set_copystring, param_get_string, \
.str = &__param_string_##name, 0, perm); \
__MODULE_PARM_TYPE(name, "string") __MODULE_PARM_TYPE(name, "string")
/* Called on module insert or kernel boot */ /* Called on module insert or kernel boot */
...@@ -186,21 +195,30 @@ extern int param_set_charp(const char *val, struct kernel_param *kp); ...@@ -186,21 +195,30 @@ extern int param_set_charp(const char *val, struct kernel_param *kp);
extern int param_get_charp(char *buffer, struct kernel_param *kp); extern int param_get_charp(char *buffer, struct kernel_param *kp);
#define param_check_charp(name, p) __param_check(name, p, char *) #define param_check_charp(name, p) __param_check(name, p, char *)
/* For historical reasons "bool" parameters can be (unsigned) "int". */
extern int param_set_bool(const char *val, struct kernel_param *kp); extern int param_set_bool(const char *val, struct kernel_param *kp);
extern int param_get_bool(char *buffer, struct kernel_param *kp); extern int param_get_bool(char *buffer, struct kernel_param *kp);
#define param_check_bool(name, p) __param_check(name, p, int) #define param_check_bool(name, p) \
static inline void __check_##name(void) \
{ \
BUILD_BUG_ON(!__same_type(*(p), bool) && \
!__same_type(*(p), unsigned int) && \
!__same_type(*(p), int)); \
}
extern int param_set_invbool(const char *val, struct kernel_param *kp); extern int param_set_invbool(const char *val, struct kernel_param *kp);
extern int param_get_invbool(char *buffer, struct kernel_param *kp); extern int param_get_invbool(char *buffer, struct kernel_param *kp);
#define param_check_invbool(name, p) __param_check(name, p, int) #define param_check_invbool(name, p) __param_check(name, p, bool)
/* Comma-separated array: *nump is set to number they actually specified. */ /* Comma-separated array: *nump is set to number they actually specified. */
#define module_param_array_named(name, array, type, nump, perm) \ #define module_param_array_named(name, array, type, nump, perm) \
static const struct kparam_array __param_arr_##name \ static const struct kparam_array __param_arr_##name \
= { ARRAY_SIZE(array), nump, param_set_##type, param_get_##type,\ = { ARRAY_SIZE(array), nump, param_set_##type, param_get_##type,\
sizeof(array[0]), array }; \ sizeof(array[0]), array }; \
module_param_call(name, param_array_set, param_array_get, \ __module_param_call(MODULE_PARAM_PREFIX, name, \
.arr = &__param_arr_##name, perm); \ param_array_set, param_array_get, \
.arr = &__param_arr_##name, \
__same_type(array[0], bool), perm); \
__MODULE_PARM_TYPE(name, "array of " #type) __MODULE_PARM_TYPE(name, "array of " #type)
#define module_param_array(name, type, nump, perm) \ #define module_param_array(name, type, nump, perm) \
......
...@@ -2455,6 +2455,7 @@ SYSCALL_DEFINE3(init_module, void __user *, umod, ...@@ -2455,6 +2455,7 @@ SYSCALL_DEFINE3(init_module, void __user *, umod,
mutex_lock(&module_mutex); mutex_lock(&module_mutex);
/* Drop initial reference. */ /* Drop initial reference. */
module_put(mod); module_put(mod);
trim_init_extable(mod);
module_free(mod, mod->module_init); module_free(mod, mod->module_init);
mod->module_init = NULL; mod->module_init = NULL;
mod->init_size = 0; mod->init_size = 0;
......
...@@ -24,9 +24,6 @@ ...@@ -24,9 +24,6 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/slab.h> #include <linux/slab.h>
/* We abuse the high bits of "perm" to record whether we kmalloc'ed. */
#define KPARAM_KMALLOCED 0x80000000
#if 0 #if 0
#define DEBUGP printk #define DEBUGP printk
#else #else
...@@ -220,13 +217,13 @@ int param_set_charp(const char *val, struct kernel_param *kp) ...@@ -220,13 +217,13 @@ int param_set_charp(const char *val, struct kernel_param *kp)
return -ENOSPC; return -ENOSPC;
} }
if (kp->perm & KPARAM_KMALLOCED) if (kp->flags & KPARAM_KMALLOCED)
kfree(*(char **)kp->arg); kfree(*(char **)kp->arg);
/* This is a hack. We can't need to strdup in early boot, and we /* This is a hack. We can't need to strdup in early boot, and we
* don't need to; this mangled commandline is preserved. */ * don't need to; this mangled commandline is preserved. */
if (slab_is_available()) { if (slab_is_available()) {
kp->perm |= KPARAM_KMALLOCED; kp->flags |= KPARAM_KMALLOCED;
*(char **)kp->arg = kstrdup(val, GFP_KERNEL); *(char **)kp->arg = kstrdup(val, GFP_KERNEL);
if (!kp->arg) if (!kp->arg)
return -ENOMEM; return -ENOMEM;
...@@ -241,44 +238,63 @@ int param_get_charp(char *buffer, struct kernel_param *kp) ...@@ -241,44 +238,63 @@ int param_get_charp(char *buffer, struct kernel_param *kp)
return sprintf(buffer, "%s", *((char **)kp->arg)); return sprintf(buffer, "%s", *((char **)kp->arg));
} }
/* Actually could be a bool or an int, for historical reasons. */
int param_set_bool(const char *val, struct kernel_param *kp) int param_set_bool(const char *val, struct kernel_param *kp)
{ {
bool v;
/* No equals means "set"... */ /* No equals means "set"... */
if (!val) val = "1"; if (!val) val = "1";
/* One of =[yYnN01] */ /* One of =[yYnN01] */
switch (val[0]) { switch (val[0]) {
case 'y': case 'Y': case '1': case 'y': case 'Y': case '1':
*(int *)kp->arg = 1; v = true;
return 0; break;
case 'n': case 'N': case '0': case 'n': case 'N': case '0':
*(int *)kp->arg = 0; v = false;
return 0; break;
} default:
return -EINVAL; return -EINVAL;
}
if (kp->flags & KPARAM_ISBOOL)
*(bool *)kp->arg = v;
else
*(int *)kp->arg = v;
return 0;
} }
int param_get_bool(char *buffer, struct kernel_param *kp) int param_get_bool(char *buffer, struct kernel_param *kp)
{ {
bool val;
if (kp->flags & KPARAM_ISBOOL)
val = *(bool *)kp->arg;
else
val = *(int *)kp->arg;
/* Y and N chosen as being relatively non-coder friendly */ /* Y and N chosen as being relatively non-coder friendly */
return sprintf(buffer, "%c", (*(int *)kp->arg) ? 'Y' : 'N'); return sprintf(buffer, "%c", val ? 'Y' : 'N');
} }
/* This one must be bool. */
int param_set_invbool(const char *val, struct kernel_param *kp) int param_set_invbool(const char *val, struct kernel_param *kp)
{ {
int boolval, ret; int ret;
bool boolval;
struct kernel_param dummy; struct kernel_param dummy;
dummy.arg = &boolval; dummy.arg = &boolval;
dummy.flags = KPARAM_ISBOOL;
ret = param_set_bool(val, &dummy); ret = param_set_bool(val, &dummy);
if (ret == 0) if (ret == 0)
*(int *)kp->arg = !boolval; *(bool *)kp->arg = !boolval;
return ret; return ret;
} }
int param_get_invbool(char *buffer, struct kernel_param *kp) int param_get_invbool(char *buffer, struct kernel_param *kp)
{ {
return sprintf(buffer, "%c", (*(int *)kp->arg) ? 'N' : 'Y'); return sprintf(buffer, "%c", (*(bool *)kp->arg) ? 'N' : 'Y');
} }
/* We break the rule and mangle the string. */ /* We break the rule and mangle the string. */
...@@ -591,7 +607,7 @@ void destroy_params(const struct kernel_param *params, unsigned num) ...@@ -591,7 +607,7 @@ void destroy_params(const struct kernel_param *params, unsigned num)
unsigned int i; unsigned int i;
for (i = 0; i < num; i++) for (i = 0; i < num; i++)
if (params[i].perm & KPARAM_KMALLOCED) if (params[i].flags & KPARAM_KMALLOCED)
kfree(*(char **)params[i].arg); kfree(*(char **)params[i].arg);
} }
......
...@@ -39,7 +39,26 @@ void sort_extable(struct exception_table_entry *start, ...@@ -39,7 +39,26 @@ void sort_extable(struct exception_table_entry *start,
sort(start, finish - start, sizeof(struct exception_table_entry), sort(start, finish - start, sizeof(struct exception_table_entry),
cmp_ex, NULL); cmp_ex, NULL);
} }
#endif
#ifdef CONFIG_MODULES
/*
* If the exception table is sorted, any referring to the module init
* will be at the beginning or the end.
*/
void trim_init_extable(struct module *m)
{
/*trim the beginning*/
while (m->num_exentries && within_module_init(m->extable[0].insn, m)) {
m->extable++;
m->num_exentries--;
}
/*trim the end*/
while (m->num_exentries &&
within_module_init(m->extable[m->num_exentries-1].insn, m))
m->num_exentries--;
}
#endif /* CONFIG_MODULES */
#endif /* !ARCH_HAS_SORT_EXTABLE */
#ifndef ARCH_HAS_SEARCH_EXTABLE #ifndef ARCH_HAS_SEARCH_EXTABLE
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment