正如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
初始化为#define
d 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。
答案 0 :(得分:2)
您可以分步使用标准的phram驱动程序从用户空间访问内存。不需要编码。内核重新编译最多。
你真的有超过64Gb的内存吗?你的硬件真的支持吗?
答案 1 :(得分:1)
当我从使用空间应用程序执行mmap时,我看到系统挂起。
在使用remap_pfn_range()API之前,请参阅mm / memory.c(内核源代码)中内联的文档,它表明您必须先保持mm信号量。
/**
* remap_pfn_range - remap kernel memory to userspace
* @vma: user vma to map to
* @addr: target user address to start at
* @pfn: physical address of kernel memory
* @size: size of map area
* @prot: page protection flags for this mapping
*
* Note: this is only safe if the mm semaphore is held when called.
*/
如何获取信号量是通过up_read()和down_read()API - 只是&#34; grep&#34;对于mm目录中的up_read,有很多例子:
mempolicy.c: up_read(&mm->mmap_sem);
migrate.c: up_read(&mm->mmap_sem);
mincore.c: up_read(¤t->mm->mmap_sem);
mmap.c: up_read(&mm->mmap_sem);
msync.c: up_read(&mm->mmap_sem);
nommu.c: up_read(&mm->mmap_sem);