On Tue, Aug 9, 2011 at 6:57 PM, Eric Camachat <eric.camachat@xxxxxxxxx> wrote:
> Hi,
>
This is probably a better question for the xen-devel mailing list. See:
http://wiki.xensource.com/xenwiki/AskingXenDevelQuestions
> 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;
> }
> =================================================================================
>
> _______________________________________________
> Xen-users mailing list
> Xen-users@xxxxxxxxxxxxxxxxxxx
> http://lists.xensource.com/xen-users
>
--
Todd Deshane
http://www.linkedin.com/in/deshantm
http://www.xen.org/products/cloudxen.html
http://runningxen.com/
_______________________________________________
Xen-users mailing list
Xen-users@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-users
|