[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] 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
Description: Text Data

Attachment: memtest-user.c
Description: Text Data

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.