[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-users] mmap in PV xen-4.0.1
Hi, I have a problem to map kernel memory to userspace via /dev/mem. The mmap() succeeded, but when I try to access it, the program will hang forever (until press ctrl-c to terminate it). # memtest-user memtest_vma_open: virt 0x7fbc90085000, phys 0x3eee8000 paddr = 0x3eee8000 mem = 0x7fbc90089000 map = 0x7fbc90085000 map[0]= 4c4c4c4c map[1]= 4c4c4c4c *** Hang here, it cannot (finish) access the memory mapped via /dev/mem *** My test source below, and it runs properly on HVM, VirtualBox, QEM and physical machines. What mistake I did? My kernel module look like this: ================================================================================= #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/types.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/mm.h> #include <asm/io.h> #include <asm/page.h> #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); ================================================================================= Here is my user program: ================================================================================= #include <stdio.h> #include <stdlib.h> #include <sys/mman.h> #include <unistd.h> #include <sys/ioctl.h> #include <fcntl.h> #include <errno.h> #include <stdint.h> #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 DEVDIAG "/dev/memtest" #define DEVMEM "/dev/mem" uint32_t get_size(void); unsigned long get_paddr(void); unsigned int * mmap_memtest(unsigned long paddr, uint32_t size); unsigned int * mmap_mem(unsigned long paddr, uint32_t size); uint32_t get_size(void) { int diagfd, rv; uint32_t size; diagfd = open( DEVDIAG, O_RDWR | O_SYNC | O_DSYNC | O_RSYNC ); if (diagfd < 0) { perror("Error : fail to open" DEVDIAG); return 0; } rv = ioctl( diagfd, MEMTEST_DMA_SIZE, &size); if (rv < 0) { perror("Fail to perform ioctl"); return 0; } close(diagfd); return size; } unsigned long get_paddr(void) { int diagfd, rv; unsigned long paddr; diagfd = open( DEVDIAG, O_RDWR | O_SYNC | O_DSYNC | O_RSYNC ); if (diagfd < 0) { perror("Error : fail to open" DEVDIAG); return 0; } rv = ioctl( diagfd, MEMTEST_DMA_PADDR, &paddr); if ( rv < 0 ) { perror("Fail to perform ioctl"); return 0; } close(diagfd); return paddr; } unsigned int * mmap_memtest(unsigned long paddr, uint32_t size) { int diagfd; unsigned int page_size = getpagesize(); unsigned int page_mask = ~(page_size - 1); unsigned int *vaddr = NULL; /** test mmap */ if ( paddr & ~page_mask ) { printf("Error : not algined %#lxx & %08x\n", paddr, ~page_mask ); return NULL; } diagfd = open( DEVDIAG, O_RDWR | O_SYNC | O_DSYNC | O_RSYNC ); if (diagfd < 0) { printf("Error : fail to open "DEVDIAG); return NULL; } vaddr = (unsigned int*) mmap(NULL, size, PROT_READ, MAP_SHARED, diagfd, paddr); close(diagfd); return vaddr; } unsigned int * mmap_mem(unsigned long paddr, uint32_t size) { int memfd; unsigned int page_size = getpagesize(); unsigned int page_mask = ~(page_size - 1); unsigned int *vaddr = NULL; /** test mmap */ if ( paddr & ~page_mask ) { printf("Error : not algined %#lxx & %08x\n", paddr, ~page_mask ); return NULL; } memfd = open(DEVMEM, O_RDWR | O_SYNC | O_DSYNC | O_RSYNC); if (memfd < 0) { perror("Error : fail to open "DEVMEM); return NULL; } vaddr = (unsigned int*) mmap(NULL, size, PROT_READ, MAP_SHARED, memfd, paddr); close(memfd); return vaddr; } int main(int argc, char **argv) { uint32_t size = get_size(); unsigned long paddr = get_paddr(); unsigned int *mem = mmap_mem(paddr, size); unsigned int *map = mmap_memtest(paddr, size); printf("paddr = %#lx\n", paddr); printf(" mem = %p\n", mem); printf(" map = %p\n", map); if (map) { printf("map[0]= %x\n", map[0]); printf("map[1]= %x\n", map[1]); } if (mem) { printf("mem[0]= %x\n", mem[0]); printf("mem[1]= %x\n", mem[1]); } return 0; } ================================================================================= Attachment:
memtest-module.c Attachment:
memtest-user.c _______________________________________________ Xen-users mailing list Xen-users@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-users
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |