diff --git a/amifldrv.c b/amifldrv.c index c4ac199..b9dd274 100644 --- a/amifldrv.c +++ b/amifldrv.c @@ -1,60 +1,78 @@ -#include +/* + * American Megatrends ROM Driver + * There wasn't a copyright here, so idk + */ + #include +#include +#include #include #include +#include +#include +#include + #include "amifldrv.h" -#include "amiwrap.h" -int amifldrv_ioctl(void); -int amifldrv_mmap(void); -static int *kmalloc_area = NULL; -static int *kmalloc_ptr = NULL; +#include "linux_iface.h" + +static int *kmalloc_area = NULL; +static int *kmalloc_ptr = NULL; static unsigned long kmalloc_len = 0L; +static int kcount = 0; static int major; static AMIFLDRV_ALLOC kmalloc_drv[128]; -static int kcount = 0; -static int amifldrv_init_module(void) + +/* + * Section: Character Device Implementation + * ============================================================================ + */ + +#if LINUX_POST_2_6 +static int chardev_open_count = 0; +#endif + +/** + * Character Device open action + */ +int +AMI_chrdrv_open(struct inode* inode, struct file* file) { - ulArg0 = 0; - pvArg0 = &amifldrv_fops; - if ((major=wrap_register_chrdev()) < 0) { - return (-EIO); +#if LINUX_PRE_2_6 + MOD_INC_USE_COUNT; +#else + if (chardev_open_count > 0) + { + return -EBUSY; } - memset(kmalloc_drv, 0, sizeof(AMIFLDRV_ALLOC) * 128); + + ++chardev_open_count; + try_module_get(THIS_MODULE); +#endif + return(0); } -static void amifldrv_cleanup_module(void) + +int +AMI_chrdrv_release(struct inode* inode, struct file* file) { - unsigned long virt_addr; - int iloop = 0; - if (kcount > 0) { - for (iloop=0; iloop= 128) return -EINVAL; - kmalloc_ptr = NULL; - if (!arg || kmalloc_ptr) { + + if (kcount >= 128) + { return -EINVAL; } - pvArg0 = (void*)&arg_kernel_space; - pvArg1 = (void*)arg; - ulArg0 = sizeof(AMIFLDRV_ALLOC); - wrap_copy_from_user(); - if (arg_kernel_space.size > 128*1024) return -EINVAL; + + kmalloc_ptr = NULL; + + if (!arg || kmalloc_ptr) + { + return -EINVAL; + } + + copy_from_user((void*) &arg_kernel_space, (void*) arg, sizeof(AMIFLDRV_ALLOC)); + + if (arg_kernel_space.size > 128*1024) + { + return -EINVAL; + } + kmalloc_len = ((arg_kernel_space.size + PAGE_SIZE -1) & PAGE_MASK); - ulArg0 = kmalloc_len+2*PAGE_SIZE; - ulArg1 = GFP_DMA|GFP_KERNEL; - kmalloc_ptr = wrap_kmalloc(); + kmalloc_ptr = kmalloc((kmalloc_len + 2 * PAGE_SIZE), GFP_DMA | GFP_KERNEL); kmalloc_area=(int *)(((unsigned long)kmalloc_ptr + PAGE_SIZE -1) & PAGE_MASK); + for (virt_addr=(unsigned long)kmalloc_area; virt_addr<(unsigned long)kmalloc_area+kmalloc_len; virt_addr+=PAGE_SIZE) { - ulArg0 = virt_addr; - pvArg0 = wrap_virt_to_page(); - wrap_mem_map_reserve(); + mem_map_reserve(virt_to_page(virt_addr)); } for (i=0; i<(kmalloc_len/sizeof(int)); i++) { kmalloc_area[i]=(0xafd0<<16) +i; @@ -94,10 +119,9 @@ int amifldrv_ioctl(void) kcount++; arg_kernel_space.kvirtadd = kmalloc_area; arg_kernel_space.kphysadd = (void *)((unsigned long)virt_to_phys(kmalloc_area)); - pvArg0 = (void*)arg; - pvArg1 = (void*)&arg_kernel_space; - ulArg0 = sizeof(AMIFLDRV_ALLOC); - wrap_copy_to_user(); + + copy_to_user((void*) arg, (void*) &arg_kernel_space, sizeof(AMIFLDRV_ALLOC)); + return 0; } case CMD_FREE: @@ -105,10 +129,9 @@ int amifldrv_ioctl(void) unsigned long virt_addr; AMIFLDRV_ALLOC arg_kernel_space; int isearch = 0; - pvArg0 = (void*)&arg_kernel_space; - pvArg1 = (void*)arg; - ulArg0 = sizeof(AMIFLDRV_ALLOC); - wrap_copy_from_user(); + + copy_from_user((void*) &arg_kernel_space, (void*) arg, sizeof(AMIFLDRV_ALLOC)); + if (kcount > 0) { for (isearch=0; isearchvm_pgoff<vm_end - vma->vm_start; + unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; + unsigned long size = vma->vm_end - vma->vm_start; + if (offset & ~PAGE_MASK) { return -ENXIO; } if (!kmalloc_ptr) { return(-ENXIO); } - if (size>kmalloc_len) { + if (size > kmalloc_len) { return(-ENXIO); } - if ((offset+size)>kmalloc_len) { + if ((offset+size) > kmalloc_len) { return -ENXIO; } if ((vma->vm_flags & VM_WRITE) && !(vma->vm_flags & VM_SHARED)) { return(-EINVAL); } + vma->vm_flags |= VM_LOCKED; - pvArg0 = vma; - ulArg0 = vma->vm_start; - ulArg1 = virt_to_phys((void*)((unsigned long)kmalloc_area)); - ulArg2 = size; - pgArg0 = PAGE_SHARED; - if (wrap_remap_page_range()) { - return -ENXIO; + + { + unsigned long pfn = virt_to_phys((void*)((unsigned long) kmalloc_area)); + +#if LINUX_POST_2_6 + int remap_result = + remap_pfn_range(vma, + vma->vm_start, + pfn >> PAGE_SHIFT, + size, + PAGE_SHARED); +#else + int remap_result = + remap_page_range(vma, + vma->vm_start, + pfn, + size, + PAGE_SHARED); +#endif + + if (remap_result) + { + return -ENXIO; + } } + return(0); } + +#if defined(HAVE_UNLOCKED_IOCTL) +# define $IOCTL_FIELD unlocked_ioctl +#else +# define $IOCTL_FIELD ioctl +#endif + +struct file_operations AMI_chrdrv_fops = { + owner: THIS_MODULE, + open: AMI_chrdrv_open, + release: AMI_chrdrv_release, + mmap: AMI_chrdrv_mmap, + $IOCTL_FIELD: AMI_chrdrv_ioctl, +}; + +/* + * Section: Linux Kernel Module Setup + * ============================================================================ + */ + +#if LINUX_POST_2_6 + +MODULE_AUTHOR ("American Megatrends Inc."); +MODULE_DESCRIPTION ("AMI Flash Update utility driver"); +MODULE_LICENSE ("Proprietary"); + +#endif + +static int /* module_init */ +amifldrv_init_module(void) +{ + major = register_chrdev(0, "amifldrv", &AMI_chrdrv_fops); + + if (major < 0) + { + return -EIO; + } + + memset(kmalloc_drv, 0, sizeof(AMIFLDRV_ALLOC) * 128); + + return(0); +} + +static void /* module_exit */ +amifldrv_cleanup_module(void) +{ + unsigned long virt_addr; + int iloop = 0; + if (kcount > 0) + { + for (iloop=0; iloop < kcount; iloop++) + { + kmalloc_ptr = kmalloc_drv[iloop].kmallocptr; + kmalloc_area = kmalloc_drv[iloop].kvirtadd; + kmalloc_len = kmalloc_drv[iloop].kvirtlen; + if (kmalloc_ptr) + { + for(virt_addr = (unsigned long)kmalloc_area; + virt_addr < (unsigned long)kmalloc_area + kmalloc_len; + virt_addr += PAGE_SIZE) + { + mem_map_unreserve(virt_to_page(virt_addr)); + } + + if (kmalloc_ptr) + { + kfree(kmalloc_ptr); + } + } + } + kcount = 0; + } + + unregister_chrdev(major, "amifldrv"); + + return; +} + +module_init(amifldrv_init_module); +module_exit(amifldrv_cleanup_module); + diff --git a/linux_iface.h b/linux_iface.h new file mode 100644 index 0000000..39c4db5 --- /dev/null +++ b/linux_iface.h @@ -0,0 +1,11 @@ +#include + +#define LINUX_PRE_2_6 (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) +#define LINUX_POST_2_6 (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) + +#if LINUX_PRE_2_6 +# include +#else +# define mem_map_reserve(p) set_bit(PG_reserved, &((p)->flags)) +# define mem_map_unreserve(p) clear_bit(PG_reserved, &((p)->flags)) +#endif