/*********************************************************************/ /* 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 #include #include #include #include #include #include #include #include #ifdef CONFIG_BIGPHYS_AREA #include #endif #include #ifdef MODVERSIONS #include #endif #include 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");