253 lines
7.0 KiB
C
253 lines
7.0 KiB
C
/*********************************************************************/
|
|
/* Copyright 2009, 2010 The University of Texas at Austin. */
|
|
/* All rights reserved. */
|
|
/* */
|
|
/* Redistribution and use in source and binary forms, with or */
|
|
/* without modification, are permitted provided that the following */
|
|
/* conditions are met: */
|
|
/* */
|
|
/* 1. Redistributions of source code must retain the above */
|
|
/* copyright notice, this list of conditions and the following */
|
|
/* disclaimer. */
|
|
/* */
|
|
/* 2. Redistributions in binary form must reproduce the above */
|
|
/* copyright notice, this list of conditions and the following */
|
|
/* disclaimer in the documentation and/or other materials */
|
|
/* provided with the distribution. */
|
|
/* */
|
|
/* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY OF TEXAS AT */
|
|
/* AUSTIN ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, */
|
|
/* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF */
|
|
/* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */
|
|
/* DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OF TEXAS AT */
|
|
/* AUSTIN OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, */
|
|
/* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES */
|
|
/* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE */
|
|
/* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR */
|
|
/* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF */
|
|
/* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */
|
|
/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT */
|
|
/* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE */
|
|
/* POSSIBILITY OF SUCH DAMAGE. */
|
|
/* */
|
|
/* The views and conclusions contained in the software and */
|
|
/* documentation are those of the authors and should not be */
|
|
/* interpreted as representing official policies, either expressed */
|
|
/* or implied, of The University of Texas at Austin. */
|
|
/*********************************************************************/
|
|
|
|
#include <linux/version.h>
|
|
#include <linux/module.h>
|
|
#include <linux/sched.h>
|
|
#include <asm/pgtable.h>
|
|
#include <linux/init.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/cdev.h>
|
|
#include <linux/spinlock.h>
|
|
#include <linux/mm.h>
|
|
#ifdef CONFIG_BIGPHYS_AREA
|
|
#include <linux/bigphysarea.h>
|
|
#endif
|
|
#include <asm/current.h>
|
|
#ifdef MODVERSIONS
|
|
#include <linux/modversions.h>
|
|
#endif
|
|
#include <asm/io.h>
|
|
|
|
typedef struct {
|
|
pid_t pid;
|
|
#ifndef CONFIG_BIGPHYS_AREA
|
|
long size;
|
|
#endif
|
|
caddr_t address;
|
|
|
|
} buffer_t;
|
|
|
|
#define MAX_BUFF_SIZE 1024
|
|
#define MAX_LENGTH (4UL << 20)
|
|
|
|
static spinlock_t lock __attribute__((aligned(64)));
|
|
|
|
static buffer_t buffer[MAX_BUFF_SIZE];
|
|
|
|
static dev_t mapper_dev;
|
|
static struct cdev mapper_cdev;
|
|
|
|
static int mapper_open (struct inode *inode, struct file *fp){ return 0;}
|
|
|
|
static int mapper_release(struct inode *inode, struct file *fp){
|
|
|
|
int pos;
|
|
#ifndef CONFIG_BIGPHYS_AREA
|
|
caddr_t addr;
|
|
#endif
|
|
|
|
// printk("Releasing memory... %d\n", current -> tgid);
|
|
|
|
spin_lock(&lock);
|
|
|
|
for (pos = 0; pos < MAX_BUFF_SIZE; pos ++) {
|
|
if (buffer[pos].pid == (pid_t) current -> tgid) {
|
|
|
|
#ifdef CONFIG_BIGPHYS_AREA
|
|
bigphysarea_free_pages(buffer[pos].address);
|
|
#else
|
|
|
|
for (addr = buffer[pos].address; addr < buffer[pos].address + buffer[pos].size; addr += PAGE_SIZE) {
|
|
ClearPageReserved(virt_to_page(addr));
|
|
}
|
|
|
|
kfree(buffer[pos].address);
|
|
buffer[pos].size = 0;
|
|
#endif
|
|
buffer[pos].pid = 0;
|
|
buffer[pos].address = 0;
|
|
}
|
|
}
|
|
|
|
spin_unlock(&lock);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int mapper_mapper(struct file *fp, struct vm_area_struct *vma){
|
|
|
|
int ret, pos;
|
|
caddr_t alloc_addr;
|
|
#ifndef CONFIG_BIGPHYS_AREA
|
|
caddr_t addr;
|
|
#endif
|
|
long all_length, length, current_addr;
|
|
|
|
all_length = vma->vm_end - vma->vm_start;
|
|
current_addr = vma -> vm_start;
|
|
|
|
spin_lock(&lock);
|
|
|
|
while (all_length > 0) {
|
|
length = all_length;
|
|
if (length > MAX_LENGTH) length = MAX_LENGTH;
|
|
all_length -= MAX_LENGTH;
|
|
|
|
// printk("Allocating memory... %d\n", length);
|
|
|
|
pos = 0;
|
|
while ((pos < MAX_BUFF_SIZE) && (buffer[pos].address != 0)) pos ++;
|
|
|
|
if (pos >= MAX_BUFF_SIZE) {
|
|
|
|
printk("Memory Allocator : too much memory allocation requested.\n");
|
|
|
|
spin_unlock(&lock);
|
|
|
|
return -EIO;
|
|
}
|
|
|
|
#ifdef CONFIG_BIGPHYS_AREA
|
|
alloc_addr = (caddr_t)bigphysarea_alloc_pages(length >> PAGE_SHIFT, 1, GFP_KERNEL);
|
|
#else
|
|
alloc_addr = (caddr_t)kmalloc(length, GFP_KERNEL);
|
|
#endif
|
|
|
|
if (alloc_addr == (caddr_t)NULL) {
|
|
|
|
spin_unlock(&lock);
|
|
|
|
return -EIO;
|
|
}
|
|
|
|
#ifndef CONFIG_BIGPHYS_AREA
|
|
for (addr = alloc_addr; addr < alloc_addr + length; addr += PAGE_SIZE) {
|
|
clear_page(addr);
|
|
SetPageReserved(virt_to_page(addr));
|
|
}
|
|
#endif
|
|
|
|
if ((ret = remap_pfn_range(vma,
|
|
current_addr,
|
|
virt_to_phys((void *)alloc_addr) >> PAGE_SHIFT,
|
|
length,
|
|
PAGE_SHARED)) < 0) {
|
|
|
|
#ifdef CONFIG_BIGPHYS_AREA
|
|
bigphysarea_free_pages((caddr_t)alloc_addr);
|
|
#else
|
|
|
|
for (addr = alloc_addr; addr < alloc_addr + length; addr += PAGE_SIZE) ClearPageReserved(virt_to_page(addr));
|
|
|
|
kfree((caddr_t)alloc_addr);
|
|
#endif
|
|
|
|
spin_unlock(&lock);
|
|
|
|
return ret;
|
|
}
|
|
|
|
buffer[pos].pid = current -> tgid;
|
|
buffer[pos].address = alloc_addr;
|
|
#ifndef CONFIG_BIGPHYS_AREA
|
|
buffer[pos].size = length;
|
|
#endif
|
|
|
|
current_addr += length;
|
|
}
|
|
|
|
spin_unlock(&lock);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static struct file_operations mapper_fops = {
|
|
.open = mapper_open,
|
|
.release = mapper_release,
|
|
.mmap = mapper_mapper,
|
|
.owner = THIS_MODULE,
|
|
};
|
|
|
|
static int __init mapper_init(void){
|
|
|
|
int ret, i;
|
|
|
|
ret = alloc_chrdev_region(&mapper_dev, 0, 1, "mapper");
|
|
|
|
cdev_init(&mapper_cdev, &mapper_fops);
|
|
|
|
ret = cdev_add(&mapper_cdev, mapper_dev, 1);
|
|
|
|
spin_lock_init(&lock);
|
|
|
|
for (i = 0; i < MAX_BUFF_SIZE; i++) {
|
|
buffer[i].pid = 0;
|
|
#ifndef CONFIG_BIGPHYS_AREA
|
|
buffer[i].size = 0;
|
|
#endif
|
|
buffer[i].address = 0;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void __exit mapper_exit(void){
|
|
|
|
int pos;
|
|
|
|
for (pos = 0; pos < MAX_BUFF_SIZE; pos ++) {
|
|
if (buffer[pos].address != 0) {
|
|
#ifdef CONFIG_BIGPHYS_AREA
|
|
bigphysarea_free_pages(buffer[pos].address);
|
|
#else
|
|
kfree(buffer[pos].address);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
cdev_del(&mapper_cdev);
|
|
|
|
unregister_chrdev_region(mapper_dev, 1);
|
|
}
|
|
|
|
module_init(mapper_init);
|
|
module_exit(mapper_exit);
|
|
MODULE_DESCRIPTION("BigPhysArea User Mapping Driver");
|
|
MODULE_LICENSE("Unknown");
|