Commit fbbe4a70 authored by Russell King's avatar Russell King

[ARM] Fix ARM module support

This cset allows ARM modules to work again.  The solution was
suggested by Andi Kleen.

We shrink the available user space size by 16MB, thereby opening up
a window in virtual memory space between user space and the kernel
direct mapped RAM.  We place modules into this space, and, since the
kernel image is always at the bottom of kernel direct mapped RAM, we
can be assured that any 24-bit PC relocations (which have a range
of +/- 32MB) will always be able to reach the kernel.
parent 93eb95ed
......@@ -7,27 +7,59 @@
* 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)
......@@ -59,8 +91,6 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
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;
......@@ -81,18 +111,15 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
}
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;
......@@ -104,9 +131,12 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
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;
}
......@@ -117,11 +147,10 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
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;
}
......
......@@ -11,14 +11,14 @@
/*
* 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
......
......@@ -14,3 +14,6 @@
#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)
......@@ -14,9 +14,9 @@
#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
......
......@@ -23,4 +23,7 @@
#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
......@@ -17,14 +17,14 @@
/*
* 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
......
......@@ -14,3 +14,7 @@
#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)
......@@ -25,14 +25,14 @@
/*
* 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
......
......@@ -30,3 +30,6 @@
#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)
......@@ -19,14 +19,14 @@
/*
* 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
......
......@@ -20,3 +20,6 @@
#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)
......@@ -48,13 +48,13 @@ extern unsigned long __bus_to_virt(unsigned long);
#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
......@@ -70,7 +70,7 @@ extern unsigned long __bus_to_virt(unsigned long);
* 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.
......
......@@ -25,3 +25,6 @@
#else
#define VMALLOC_END (PAGE_OFFSET + 0x20000000)
#endif
#define MODULE_START (PAGE_OFFSET - 16*1048576)
#define MODULE_END (PAGE_OFFSET)
......@@ -23,14 +23,14 @@
/*
* 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
......
......@@ -30,3 +30,6 @@
#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)
......@@ -23,14 +23,14 @@
/*
* 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
......
......@@ -30,3 +30,6 @@
#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)
......@@ -10,14 +10,14 @@
/*
* 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
......
......@@ -14,3 +14,6 @@
#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)
......@@ -15,14 +15,14 @@
/*
* 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
......
......@@ -14,3 +14,6 @@
#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)
......@@ -11,14 +11,14 @@
/*
* 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
......
......@@ -14,3 +14,6 @@
#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)
......@@ -16,14 +16,14 @@
/*
* 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
......
......@@ -21,3 +21,6 @@
#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)
......@@ -21,14 +21,14 @@
/*
* 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
......
......@@ -20,3 +20,6 @@
#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)
......@@ -12,14 +12,14 @@
/*
* 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
......
......@@ -14,3 +14,6 @@
#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)
......@@ -13,14 +13,14 @@
/*
* 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
......
......@@ -15,3 +15,5 @@
#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)
......@@ -10,14 +10,14 @@
/*
* 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
......
......@@ -15,3 +15,5 @@
#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)
......@@ -200,6 +200,10 @@ typedef struct {
#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
......
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