#include #include #include #include #include #include #include #include #define MEMTEST_MAJOR 886 #define MEMTEST_NAME "memtest" #define MEMTEST_MAGIC 'M' #define MEMTEST_DMA_SIZE _IO(MEMTEST_MAGIC, 0) #define MEMTEST_DMA_PADDR _IO(MEMTEST_MAGIC, 1) #define MEMTEST_DMA_VADDR _IO(MEMTEST_MAGIC, 2) #define SIZE_ORDER 2 static uint32_t _size = (PAGE_SIZE << SIZE_ORDER); static unsigned long _vbase = 0; static phys_addr_t _pbase = 0; static int memtest_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { int ret = -ENOIOCTLCMD; phys_addr_t *paddr; unsigned long *vaddr; uint32_t *size; switch(cmd) { case MEMTEST_DMA_SIZE: size = (uint32_t*)arg; *size = _size; ret = 0; break; case MEMTEST_DMA_PADDR: paddr = (phys_addr_t*)arg; *paddr = _pbase; ret = 0; break; case MEMTEST_DMA_VADDR: vaddr = (unsigned long*)arg; *vaddr = _vbase; ret = 0; break; } return ret; } static void memtest_vma_open(struct vm_area_struct *vma) { printk("%s: virt %#lx, phys %#lx\n", __func__, vma->vm_start, vma->vm_pgoff << PAGE_SHIFT); } static void memtest_vma_close(struct vm_area_struct *vma) { printk("%s\n", __func__); } static struct vm_operations_struct memtest_vm_ops = { .open = memtest_vma_open, .close = memtest_vma_close, }; static int memtest_mmap(struct file * file, struct vm_area_struct * vma) { /* Remap-pfn-range will mark the range VM_IO and VM_RESERVED */ if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, vma->vm_end - vma->vm_start, vma->vm_page_prot)) { return -EAGAIN; } vma->vm_ops = &memtest_vm_ops; memtest_vma_open(vma); return 0; } static struct file_operations memtest_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .ioctl = memtest_ioctl, .mmap = memtest_mmap, }; static int __init memtest_init(void) { int retval; printk(MEMTEST_NAME ": registering /dev/" MEMTEST_NAME " (%d)\n",MEMTEST_MAJOR ); retval = register_chrdev(MEMTEST_MAJOR, MEMTEST_NAME, &memtest_fops); if (retval < 0) { printk(MEMTEST_NAME ": failed to register /dev/" MEMTEST_NAME "\n"); } printk(MEMTEST_NAME ": size of phys_addr_t is %lu bytes\n", sizeof(phys_addr_t)); //_vbase = get_zeroed_page(GFP_KERNEL); _vbase = __get_free_pages(GFP_KERNEL, SIZE_ORDER); if (_vbase == 0) { printk(MEMTEST_NAME ": kmalloc(%d, GFP_KERNEL) failed\n", _size); } else { memset((void*)_vbase, 'L', _size); ((uint32_t*)_vbase)[0] = 0x1234; ((uint32_t*)_vbase)[1] = 0xabcd; ((uint32_t*)_vbase)[2] = 0xeeee; ((uint32_t*)_vbase)[3] = 0xffff; _pbase = virt_to_bus((void*)_vbase); } printk(MEMTEST_NAME ": _vbase = %#lx\n", _vbase); printk(MEMTEST_NAME ": _pbase = %#lx\n", (unsigned long)_pbase); return retval; } static void __exit memtest_exit(void) { if (_vbase != 0) free_page(_vbase); unregister_chrdev(MEMTEST_MAJOR, MEMTEST_NAME); } MODULE_LICENSE("GPL"); module_init(memtest_init); module_exit(memtest_exit);