【发布时间】:2012-09-29 05:09:16
【问题描述】:
正如this 问题中所讨论的,我正在使用内核引导参数memmap=8G$64G 在引导时保留一个内存块
我编写了一个character driver 内核模块,在初始化期间会对该保留的内存块进行 ioremap。
正如here 解释的那样,在我的驱动程序mmap 中,我需要做的就是remap_pfn_range 用于ioremap 返回的这个内存块指针。
我在 3.0 linux 内核上运行它。我的用户空间应用程序将此内存块作为驱动程序安装的设备打开。当我从使用空间应用程序中执行 mmap 时,我看到 系统挂起。 我的 dmesg 没有提供太多信息。
任何输入?
static int __init myDev_module_init(void)
{
int retval;
myDev_major = register_chrdev(0, DEVICE_NAME, &myDevfops);
if (myDev_major < 0)
{
err("failed to register device: error %d\n", myDev_major);
retval = myDev_major;
goto FAILED_CHRDEVREG;
}
myDev_class = class_create(THIS_MODULE, CLASS_NAME);
if (IS_ERR(myDev_class))
{
err("failed to register device class '%s'\n", CLASS_NAME);
retval = PTR_ERR(myDev_class);
goto FAILED_CLASSREG;
}
myDev_device = device_create(myDev_class, NULL, MKDEV(myDev_major, 0), NULL, CLASS_NAME "_" DEVICE_NAME);
if (IS_ERR(myDev_device))
{
err("failed to create device '%s_%s'\n", CLASS_NAME, DEVICE_NAME);
retval = PTR_ERR(myDev_device);
goto FAILED_DEVREG;
}
这里myDev.startOffset被初始化为#defined 64GB,myDev.memSize被初始化为8GB。
//myDev.startAddr = ioremap(myDev.startOffset,myDev.memSize);
//memset_io(myDev.startAddr, 0, myDev.memSize);
return 0;
FAILED_DEVREG:
class_unregister(myDev_class);
class_destroy(myDev_class);
FAILED_CLASSREG:
unregister_chrdev(myDev_major, DEVICE_NAME);
FAILED_CHRDEVREG:
return -1;
}
static int myDev_device_open(struct inode* inode, struct file* filp)
{
dbg("");
if ( ((filp->f_flags & O_ACCMODE) == O_WRONLY) || ((filp->f_flags & O_ACCMODE) == O_RDWR) )
{
warn(" Opening the device with write access\n");
//return -EACCES;
}
info(" device Open is called\n");
filp->private_data = &myDev;
return 0;
}
mmap 非常简单。
static int myDev_device_mmap(struct file * f, struct vm_area_struct * vma)
{
int retval = 0;
struct myDevDev * pDev = (struct myDevDev *)(f->private_data);
dbg("");
if(vma)
{
if(f)
{
if(f->private_data)
warn("mmap: f->private_data : %p\n", f->private_data);
else
warn(" mmap :f->private_data : NULL \n");
}
else
{
warn("mmap: f :NULL\n");
}
warn(": mmap: vm start : %lu\n", vma->vm_start);
warn(" mmap: vm end : %lu\n", vma->vm_end);
warn(" mmap: vm pg offset : %lu\n", vma->vm_pgoff);
//retval = remap_pfn_range(vma, vma->vm_start, pDev->startOffset >> PAGE_SHIFT, pDev->memSize, PAGE_SHARED) ;
// retval = remap_pfn_range(vma, vma->vm_start, pDev->startAddr >> PAGE_SHIFT, pDev->memSize, PAGE_SHARED) ;
//retval = remap_pfn_range(vma,pDev->startAddr ,pDev->startOffset >> PAGE_SHIFT, pDev->memSize, PAGE_SHARED);
retval = remap_pfn_range(vma,vma->vm_start ,pDev->startOffset >> PAGE_SHIFT, pDev->memSize, PAGE_SHARED);
if(retval <0)
{
warn(" ERROR : in mapping kernel virtual space to user space return value : %d \n",retval);
return -EINVAL;
}
//if(0)
{
vma->vm_flags |=VM_LOCKED;
vma->vm_ops = &myRemapVMOps;
vma->vm_flags |= VM_RESERVED;
vma->vm_private_data = f->private_data;
myDevice_VMA_Open(vma);
}
}
else
{
warn ("vma is NULL");
}
dbg(" Done ");
warn("mmpaing done : \n");
return 0;
}
从我的用户空间应用程序中,我正在执行以下操作:
int err, i=0;
void * mptr = NULL;
printf(" Access the reserved memory chunk \n ");
int fd = open("/dev/myDevice", O_RDWR | O_SYNC);
if(fd <=0)
{
printf("ERROR: my device driver is not loaded \n");
return 1;
}
printf("\n mmaping mem chunk size :%llu pagesize :%lu input mptr :%p\n", sz,getpagesize (), mptr);
mptr = mmap(0, sz , PROT_READ | PROT_WRITE, MAP_SHARED | MAP_LOCKED, fd, 0);
if(mptr == MAP_FAILED)
{
close(fd);
perror("Error mmapping the file");
printf("\nmmapped mem address %p\n",mptr);
exit(1);
}
printf("\nmmapped mem address %p\n",mptr);
//char * ptr = (char *)mptr;
//*ptr = 'a';
//int * pInt = (int *) (((char *) mptr)+1);
//for(;i<10000; ++i)
{
// pInt[i] = 2*i;
}
/* free the mmapped memory
*/
if (munmap(mptr, sz) == -1)
{
perror("Error un-mmapping the file");
}
close(fd);
观察:
我没有看到 (vma->vm_end - vma->vm_start) 中反映的大小,出于某种原因,它始终为 4K。
【问题讨论】:
-
通常在调用 ioremap() 之前调用 request_mem_region() 来声明/保留物理地址空间块。
/proc/iomem显示什么?如果“系统挂起”(而不仅仅是用户应用程序),那么问题就出在内核中! -
/proc/iomem显示要保留的块1000000000-1280000000 : reserved -
numactl --hardware已经告诉我内存块没有反映在 numa 节点中,因此它对内核空间不可见。 -
不确定我们是否还需要做
request_mem_region()? -
/proc/vmallocinfo显示了ioremapped内存块,尽管!我在设备驱动程序init中打印了ioremap返回的地址,它与vmallocinfo条目匹配!
标签: linux-kernel kernel linux-device-driver embedded-linux kernel-module