1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
|
/* $Id: modutil.c,v 1.9 2001/08/14 22:10:56 davem Exp $
* arch/sparc64/mm/modutil.c
*
* Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
* Based upon code written by Linus Torvalds and others.
*/
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#define MODULES_VADDR 0x0000000001000000ULL /* Where to map modules */
#define MODULES_LEN 0x000000007f000000ULL
#define MODULES_END 0x0000000080000000ULL
static struct vm_struct * modvmlist = NULL;
void module_unmap (void * addr)
{
struct vm_struct **p, *tmp;
if (!addr)
return;
if ((PAGE_SIZE-1) & (unsigned long) addr) {
printk("Trying to unmap module with bad address (%p)\n", addr);
return;
}
for (p = &modvmlist ; (tmp = *p) ; p = &tmp->next) {
if (tmp->addr == addr) {
*p = tmp->next;
vmfree_area_pages(VMALLOC_VMADDR(tmp->addr), tmp->size);
kfree(tmp);
return;
}
}
printk("Trying to unmap nonexistent module vm area (%p)\n", addr);
}
void * module_map (unsigned long size)
{
void * addr;
struct vm_struct **p, *tmp, *area;
size = PAGE_ALIGN(size);
if (!size || size > MODULES_LEN) return NULL;
addr = (void *) MODULES_VADDR;
for (p = &modvmlist; (tmp = *p) ; p = &tmp->next) {
if (size + (unsigned long) addr < (unsigned long) tmp->addr)
break;
addr = (void *) (tmp->size + (unsigned long) tmp->addr);
}
if ((unsigned long) addr + size >= MODULES_END) return NULL;
area = (struct vm_struct *) kmalloc(sizeof(*area), GFP_KERNEL);
if (!area) return NULL;
area->size = size + PAGE_SIZE;
area->addr = addr;
area->next = *p;
*p = area;
if (vmalloc_area_pages(VMALLOC_VMADDR(addr), size, GFP_KERNEL, PAGE_KERNEL)) {
module_unmap(addr);
return NULL;
}
return addr;
}
|