我正在开发一个 Linux 内核模块,它为每个字符设备分配多个缓冲区,然后用户空间应用程序将这些缓冲区映射到用户空间。我的字符设备类有大约十个或更多缓冲区,并且在打开时间我分配这些缓冲区,每个缓冲区的大小为 0x8000。我遇到的问题是将这些缓冲区映射到用户空间指针时。我只能映射一个缓冲区,但是当我尝试分配第二个缓冲区时,它就会崩溃。我对dma_mmap_coherent不太熟悉,有人可以帮我解决这个问题。
下面是一些代码信息:
// 我的内存类型结构
typedef struct
{
unsigned int * uaddr;
unsigned int * kaddr;
unsigned long paddr;
unsigned int size;
unsigned int index;
dma_addr_t handle;
}memory_handle_t
// 内核中的缓冲区分配(IOCTL 调用)
static int allocate__memory_ioctl(struct file *pfile, void __user *uaddr)
{
struct myClass *my_class = (struct my_class *)pfile->private_data;
memory_handle_t minfo;
int idx = -1;
if ((idx = find_handle(my_class , NULL)) == -1) {
printk(KERN_INFO "cannot find a free slot.\n");
return -EACCES;
}
if (copy_from_user(&minfo, uaddr, sizeof(memory_handle_t))) {
printk(KERN_INFO "CANNOT COPY FROM USER POINTER. \n");
return -EACCES;
}
my_class->_memory[idx].size = minfo.size;
my_class->_memory[idx].kaddr = minfo.kaddr = dma_alloc_coherent(my_class->dma_device_p,
my_class->_memory[idx].size,
&my_class->_memory[idx].handle,
GFP_KERNEL);
if (my_class->_memory[idx].kaddr == NULL) {
printk(KERN_INFO "Dma memory allocation failed!\n");
my_class->_memory[idx].size = 0;
my_class->_memory[idx].kaddr = NULL;
return -1;
} else {
my_class->_memory[idx].paddr = minfo.paddr = virt_to_phys(my_class->_memory[idx].kaddr);
}
minfo.index = idx; /* Pass the index to user so he can use it to map */
if (copy_to_user(uaddr, &minfo, sizeof(memory_handle_t))) {
printk(KERN_INFO "CANNOT COPY TO THE USER POINTER. \n");
return -EFAULT;
}
return 0;
}
// MMAP
#define DMA_MAPPING (1 << 7)
static int c_mmap(struct file *pfile, struct vm_area_struct *vma)
{
struct myClass *my_class= (struct myClass *)pfile->private_data;
unsigned int idx = (vma->vm_pgoff & ~DMA_MAPPING) & 0xff; /* We are using the offset for index! */
if ((vma->vm_end - vma->vm_start) > my_class->_memory[idx].size) {
printk(KERN_ALERT "MMAP FAILED, SIZE MISMATCH. \n");
return -EINVAL;
}
vma->vm_flags |= VM_IO;
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
return dma_mmap_coherent(my_class->dma_device_p, vma, my_class->_memory[idx].kaddr,
my_class->_memory[idx].handle, my_class->_memory[idx].size);
}
// 用户空间应用程序
_fd = open(dev_name.c_str(), O_RDWR);
if (_fd < 1) {
printf("Unable to open device file");
exit(EXIT_FAILURE);
}
// start allocation and mmap
size_t _page_sz = sysconf(_SC_PAGESIZE);
unsigned int size = TEST_SIZE;
for(int idx=0;idx<11;idx++){
dma_memory_handle_t dh;
_mems[idx].size = dh.size = size;
int ret = ioctl(_fd, IOCTL_ALLOC_DMA_MEMORY, &dh);
if (ret < 0)
{
std::cerr << "memory allocation failed!";
perror("memory allocation failed! ");
throw(std::exception());
}
int index = dh.index;
// fails after the first iteration
**unsigned int *addr = (unsigned int *) mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, _fd, index*_page_sz);**
if (addr == MAP_FAILED)
{
std::cerr << "memory map failed!";
perror("memory map failed! ");
throw(std::exception());
}
_mems[idx].uaddr = addr;
_mems[idx].index = dh.index;
_mems[idx].paddr = dh.paddr;
_mems[idx].kaddr = dh.kaddr;
}