* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
- * This code is currently broken. We need to allocate a jump table
- * for out of range branches. We'd really like to be able to allocate
- * a jump table and share it between modules, thereby reducing the
- * cache overhead associated with the jump tables.
+ * Module allocation method suggested by Andi Kleen.
*/
-#warning FIXME
-
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/elf.h>
#include <linux/vmalloc.h>
+#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/string.h>
+#include <asm/pgtable.h>
+
void *module_alloc(unsigned long size)
{
- return NULL; /* disabled */
+ struct vm_struct *area;
+ struct page **pages;
+ unsigned int array_size, i;
+
+ size = PAGE_ALIGN(size);
+ if (!size)
+ goto out_null;
+
+ area = __get_vm_area(size, VM_ALLOC, MODULE_START, MODULE_END);
+ if (!area)
+ goto out_null;
+
+ area->nr_pages = size >> PAGE_SHIFT;
+ array_size = area->nr_pages * sizeof(struct page *);
+ area->pages = pages = kmalloc(array_size, GFP_KERNEL);
+ if (!area->pages) {
+ remove_vm_area(area->addr);
+ kfree(area);
+ goto out_null;
+ }
+
+ memset(pages, 0, array_size);
+
+ for (i = 0; i < area->nr_pages; i++) {
+ pages[i] = alloc_page(GFP_KERNEL);
+ if (unlikely(!pages[i])) {
+ area->nr_pages = i;
+ goto out_no_pages;
+ }
+ }
+
+ if (map_vm_area(area, PAGE_KERNEL, &pages))
+ goto out_no_pages;
+ return area->addr;
- if (size == 0)
- return NULL;
- return vmalloc(size);
+ out_no_pages:
+ vfree(area->addr);
+ out_null:
+ return NULL;
}
void module_free(struct module *module, void *region)
Elf32_Rel *rel = (void *)relsec->sh_offset;
unsigned int i;
- printk("Applying relocations for section %u\n", relsec->sh_info);
-
for (i = 0; i < relsec->sh_size / sizeof(Elf32_Rel); i++, rel++) {
unsigned long loc;
Elf32_Sym *sym;
}
if (rel->r_offset < 0 || rel->r_offset > dstsec->sh_size - sizeof(u32)) {
- printk(KERN_ERR "%s: out of bounds relocation, section %d reloc %d "
- "offset %d size %d\n",
- module->name, relindex, i, rel->r_offset, dstsec->sh_size);
+ printk(KERN_ERR "%s: out of bounds relocation, "
+ "section %d reloc %d offset %d size %d\n",
+ module->name, relindex, i, rel->r_offset,
+ dstsec->sh_size);
return -ENOEXEC;
}
loc = dstsec->sh_offset + rel->r_offset;
- printk("%s: rel%d: at 0x%08lx [0x%08lx], symbol '%s' value 0x%08lx =>",
- module->name, i, loc, *(u32 *)loc, strtab + sym->st_name,
- sym->st_value);
-
switch (ELF32_R_TYPE(rel->r_info)) {
case R_ARM_ABS32:
*(u32 *)loc += sym->st_value;
offset -= 0x04000000;
offset += sym->st_value - loc;
- if (offset & 3 || offset <= 0xfc000000 || offset >= 0x04000000) {
- printk(KERN_ERR "%s: unable to fixup relocation: out of range\n",
- module->name);
+ if (offset & 3 ||
+ offset <= (s32)0xfc000000 ||
+ offset >= (s32)0x04000000) {
+ printk(KERN_ERR "%s: unable to fixup "
+ "relocation: out of range\n",
+ module->name);
return -ENOEXEC;
}
break;
default:
- printk("\n" KERN_ERR "%s: unknown relocation: %u\n",
- module->name, ELF32_R_TYPE(rel->r_info));
+ printk(KERN_ERR "%s: unknown relocation: %u\n",
+ module->name, ELF32_R_TYPE(rel->r_info));
return -ENOEXEC;
}
- printk("[0x%08lx]\n", *(u32 *)loc);
}
return 0;
}
/*
* Task size: 3GB
*/
-#define TASK_SIZE (0xc0000000UL)
+#define TASK_SIZE (0xbf000000UL)
#define TASK_SIZE_26 (0x04000000UL)
/*
* This decides where the kernel will search for a free chunk of vm
* space during mmap's.
*/
-#define TASK_UNMAPPED_BASE (TASK_SIZE / 3)
+#define TASK_UNMAPPED_BASE (0x40000000)
/*
* Page offset: 3GB
#define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
#define VMALLOC_VMADDR(x) ((unsigned long)(x))
#define VMALLOC_END (0xe8000000)
+
+#define MODULE_START (PAGE_OFFSET - 16*1048576)
+#define MODULE_END (PAGE_OFFSET)
#ifndef __ASM_ARCH_MEMORY_H
#define __ASM_ARCH_MEMORY_H
-#define TASK_SIZE (3u * 1024 * 1024 * 1024)
+#define TASK_SIZE (0xbf000000)
#define TASK_SIZE_26 (64u * 1024 * 1024)
-#define TASK_UNMAPPED_BASE (1u * 1024 * 1024 * 1024)
+#define TASK_UNMAPPED_BASE (0x40000000)
#define PAGE_OFFSET 0xc0000000
#define PHYS_OFFSET 0x20000000
#define VMALLOC_START ((VMALLOC_VMADDR(high_memory) + VMALLOC_ARCH_OFFSET) & ~(VMALLOC_ARCH_OFFSET - 1))
#define VMALLOC_END (PAGE_OFFSET + 0x10000000)
+#define MODULE_START (PAGE_OFFSET - 16*1048576)
+#define MODULE_END (PAGE_OFFSET)
+
#endif
/*
* Task size: 3GB
*/
-#define TASK_SIZE (0xc0000000UL)
+#define TASK_SIZE (0xbf000000UL)
#define TASK_SIZE_26 (0x04000000UL)
/*
* This decides where the kernel will search for a free chunk of vm
* space during mmap's.
*/
-#define TASK_UNMAPPED_BASE (TASK_SIZE / 3)
+#define TASK_UNMAPPED_BASE (0x40000000)
/*
* Page offset: 3GB
#define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
#define VMALLOC_VMADDR(x) ((unsigned long)(x))
#define VMALLOC_END (PAGE_OFFSET + 0x1c000000)
+
+#define MODULE_START (PAGE_OFFSET - 16*1048576)
+#define MODULE_END (PAGE_OFFSET)
+
/*
* Task size: 3GB
*/
-#define TASK_SIZE (0xc0000000UL)
+#define TASK_SIZE (0xbf000000UL)
#define TASK_SIZE_26 (0x04000000UL)
/*
* This decides where the kernel will search for a free chunk of vm
* space during mmap's.
*/
-#define TASK_UNMAPPED_BASE (TASK_SIZE / 3)
+#define TASK_UNMAPPED_BASE (0x40000000)
/*
* Page offset: 3GB
#define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
#define VMALLOC_VMADDR(x) ((unsigned long)(x))
#define VMALLOC_END (PAGE_OFFSET + 0x10000000)
+
+#define MODULE_START (PAGE_OFFSET - 16*1048576)
+#define MODULE_END (PAGE_OFFSET)
/*
* Task size: 3GB
*/
-#define TASK_SIZE (0xc0000000UL)
+#define TASK_SIZE (0xbf000000UL)
#define TASK_SIZE_26 (0x04000000UL)
/*
* This decides where the kernel will search for a free chunk of vm
* space during mmap's.
*/
-#define TASK_UNMAPPED_BASE (TASK_SIZE / 3)
+#define TASK_UNMAPPED_BASE (0x40000000)
/*
* Page offset: 3GB
#define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
#define VMALLOC_VMADDR(x) ((unsigned long)(x))
#define VMALLOC_END (PAGE_OFFSET + 0x1f000000)
+
+#define MODULE_START (PAGE_OFFSET - 16*1048576)
+#define MODULE_END (PAGE_OFFSET)
#if defined(CONFIG_ARCH_FOOTBRIDGE)
/* Task size and page offset at 3GB */
-#define TASK_SIZE (0xc0000000UL)
+#define TASK_SIZE (0xbf000000UL)
#define PAGE_OFFSET (0xc0000000UL)
#elif defined(CONFIG_ARCH_CO285)
/* Task size and page offset at 1.5GB */
-#define TASK_SIZE (0x60000000UL)
+#define TASK_SIZE (0x5f000000UL)
#define PAGE_OFFSET (0x60000000UL)
#else
* This decides where the kernel will search for a free chunk of vm
* space during mmap's.
*/
-#define TASK_UNMAPPED_BASE (TASK_SIZE / 3)
+#define TASK_UNMAPPED_BASE ((TASK_SIZE + 0x01000000) / 3)
/*
* The DRAM is always contiguous.
#else
#define VMALLOC_END (PAGE_OFFSET + 0x20000000)
#endif
+
+#define MODULE_START (PAGE_OFFSET - 16*1048576)
+#define MODULE_END (PAGE_OFFSET)
/*
* Task size: 3GB
*/
-#define TASK_SIZE (0xc0000000UL)
+#define TASK_SIZE (0xbf000000UL)
#define TASK_SIZE_26 (0x04000000UL)
/*
* This decides where the kernel will search for a free chunk of vm
* space during mmap's.
*/
-#define TASK_UNMAPPED_BASE (TASK_SIZE / 3)
+#define TASK_UNMAPPED_BASE (0x40000000)
/*
* Page offset: 3GB
#define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
#define VMALLOC_VMADDR(x) ((unsigned long)(x))
#define VMALLOC_END (PAGE_OFFSET + 0x10000000)
+
+#define MODULE_START (PAGE_OFFSET - 16*1048576)
+#define MODULE_END (PAGE_OFFSET)
/*
* Task size: 3GB
*/
-#define TASK_SIZE (0xc0000000UL)
+#define TASK_SIZE (0xbf000000UL)
#define TASK_SIZE_26 (0x04000000UL)
/*
* This decides where the kernel will search for a free chunk of vm
* space during mmap's.
*/
-#define TASK_UNMAPPED_BASE (TASK_SIZE / 3)
+#define TASK_UNMAPPED_BASE (0x40000000)
/*
* Page offset: 3GB
#define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
#define VMALLOC_VMADDR(x) ((unsigned long)(x))
#define VMALLOC_END (PAGE_OFFSET + 0x10000000)
+
+#define MODULE_START (PAGE_OFFSET - 16*1048576)
+#define MODULE_END (PAGE_OFFSET)
/*
* Task size: 3GB
*/
-#define TASK_SIZE (0xc0000000UL)
+#define TASK_SIZE (0xbf000000UL)
#define TASK_SIZE_26 (0x04000000UL)
/*
* This decides where the kernel will search for a free chunk of vm
* space during mmap's.
*/
-#define TASK_UNMAPPED_BASE (TASK_SIZE / 3)
+#define TASK_UNMAPPED_BASE (0x40000000)
/*
* Page offset: 3GB
#define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
#define VMALLOC_VMADDR(x) ((unsigned long)(x))
#define VMALLOC_END (0xe8000000)
+
+#define MODULE_START (PAGE_OFFSET - 16*1048576)
+#define MODULE_END (PAGE_OFFSET)
/*
* Task size: 3GB
*/
-#define TASK_SIZE (0xc0000000UL)
+#define TASK_SIZE (0xbf000000UL)
#define TASK_SIZE_26 (0x04000000UL)
/*
* This decides where the kernel will search for a free chunk of vm
* space during mmap's.
*/
-#define TASK_UNMAPPED_BASE (TASK_SIZE / 3)
+#define TASK_UNMAPPED_BASE (0x40000000)
/*
* Page offset: 3GB
#define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
#define VMALLOC_VMADDR(x) ((unsigned long)(x))
#define VMALLOC_END (PAGE_OFFSET + 0x10000000)
+
+#define MODULE_START (PAGE_OFFSET - 16*1048576)
+#define MODULE_END (PAGE_OFFSET)
/*
* Task size: 3GB
*/
-#define TASK_SIZE (0xc0000000UL)
+#define TASK_SIZE (0xbf000000UL)
#define TASK_SIZE_26 (0x04000000UL)
/*
* This decides where the kernel will search for a free chunk of vm
* space during mmap's.
*/
-#define TASK_UNMAPPED_BASE (TASK_SIZE / 3)
+#define TASK_UNMAPPED_BASE (0x40000000)
/*
* Page offset: 3GB
#define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
#define VMALLOC_VMADDR(x) ((unsigned long)(x))
#define VMALLOC_END (PAGE_OFFSET + 0x20000000)
+
+#define MODULE_START (PAGE_OFFSET - 16*1048576)
+#define MODULE_END (PAGE_OFFSET)
/*
* Task size: 3GB
*/
-#define TASK_SIZE (0xc0000000UL)
+#define TASK_SIZE (0xbf000000UL)
#define TASK_SIZE_26 (0x04000000UL)
/*
* This decides where the kernel will search for a free chunk of vm
* space during mmap's.
*/
-#define TASK_UNMAPPED_BASE (TASK_SIZE / 3)
+#define TASK_UNMAPPED_BASE (0x40000000)
/*
* Page offset: 3GB
#define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
#define VMALLOC_VMADDR(x) ((unsigned long)(x))
#define VMALLOC_END (0xe8000000)
+
+#define MODULE_START (PAGE_OFFSET - 16*1048576)
+#define MODULE_END (PAGE_OFFSET)
/*
* Task size: 3GB
*/
-#define TASK_SIZE (0xc0000000UL)
+#define TASK_SIZE (0xbf000000UL)
#define TASK_SIZE_26 (0x04000000UL)
/*
* This decides where the kernel will search for a free chunk of vm
* space during mmap's.
*/
-#define TASK_UNMAPPED_BASE (TASK_SIZE / 3)
+#define TASK_UNMAPPED_BASE (0x40000000)
/*
* Page offset: 3GB
#define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
#define VMALLOC_VMADDR(x) ((unsigned long)(x))
#define VMALLOC_END (PAGE_OFFSET + 0x1c000000)
+
+#define MODULE_START (PAGE_OFFSET - 16*1048576)
+#define MODULE_END (PAGE_OFFSET)
/*
* Task size: 3GB
*/
-#define TASK_SIZE (0xc0000000UL)
+#define TASK_SIZE (0xbf000000UL)
#define TASK_SIZE_26 (0x04000000UL)
/*
* This decides where the kernel will search for a free chunk of vm
* space during mmap's.
*/
-#define TASK_UNMAPPED_BASE (TASK_SIZE / 3)
+#define TASK_UNMAPPED_BASE (0x40000000)
/*
* Page offset: 3GB
#define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
#define VMALLOC_VMADDR(x) ((unsigned long)(x))
#define VMALLOC_END (0xe8000000)
+
+#define MODULE_START (PAGE_OFFSET - 16*1048576)
+#define MODULE_END (PAGE_OFFSET)
/*
* Task size: 3GB
*/
-#define TASK_SIZE (0xc0000000UL)
+#define TASK_SIZE (0xbf000000UL)
#define TASK_SIZE_26 (0x04000000UL)
/*
* This decides where the kernel will search for a free chunk of vm
* space during mmap's.
*/
-#define TASK_UNMAPPED_BASE (TASK_SIZE / 3)
+#define TASK_UNMAPPED_BASE (0x40000000)
/*
* Page offset: = 3GB
#define VMALLOC_VMADDR(x) ((unsigned long)(x))
#define VMALLOC_END (PAGE_OFFSET + 0x10000000)
+#define MODULE_START (PAGE_OFFSET - 16*1048576)
+#define MODULE_END (PAGE_OFFSET)
/*
* Task size: 3GB
*/
-#define TASK_SIZE (0xc0000000UL)
+#define TASK_SIZE (0xbf000000UL)
#define TASK_SIZE_26 (0x04000000UL)
/*
* This decides where the kernel will search for a free chunk of vm
* space during mmap's.
*/
-#define TASK_UNMAPPED_BASE (TASK_SIZE / 3)
+#define TASK_UNMAPPED_BASE (0x40000000)
/*
* Page offset: 3GB
#define VMALLOC_VMADDR(x) ((unsigned long)(x))
#define VMALLOC_END (PAGE_OFFSET + 0x10000000)
+#define MODULE_START (PAGE_OFFSET - 16*1048576)
+#define MODULE_END (PAGE_OFFSET)
#define ELF64_R_SYM(i) ((i) >> 32)
#define ELF64_R_TYPE(i) ((i) & 0xffffffff)
+#define R_ARM_NONE 0
+#define R_ARM_PC24 1
+#define R_ARM_ABS32 2
+
#define R_386_NONE 0
#define R_386_32 1
#define R_386_PC32 2