原来的程序:
/* 文件操作 */
static struct file_operations xxx_fops = {
......
.mmap = _xxxx_mmap,
......
};
static int _xxxx_mmap(struct file * file, struct vm_area_struct * vma)
{
int offset;
offset = ((int)(__pa(pdata)) >> PAGE_SHIFT); // pdata是 __get_free_page得到的
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
vma->vm_flags |= VM_RESERVED;
printk("vma start: 0x%lx, buffer pfn: 0x%lx/n", vma->vm_start, offset);
if (remap_pfn_range(vma, vma->vm_start,
offset,
vma->vm_end - vma->vm_start,
vma->vm_page_prot))
return -EAGAIN;
return 0;
}
ldd3中讲到,对于常规内存,不能用remap_pfn_range,这个限制用来保证系统稳定性。
remap_pfn_range时候做外部io/mem空间映射。
所以上面的例子当然运行错误,改为nopage方式,如下(运行正常):
/* 文件操作 */
static struct file_operations xxx_fops = {
......
.mmap = _xxxx_mmap,
......
};
static int _xxxx_mmap(struct file * file, struct vm_area_struct * vma)
{
vma->vm_ops = &scullv_vm_ops;
vma->vm_flags |= VM_RESERVED;
return 0;
}
struct page *scullv_vma_nopage(struct vm_area_struct *vma,
unsigned long address, int *type)
{
struct page *page = NOPAGE_SIGBUS;
if(pdata) {
page = virt_to_page(pdata); // get_free_page得到的内存不要用vmalloc_to_page
get_page(page);
if(type)
*type = VM_FAULT_MINOR;
}
return page;
}
测试程序:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/fcntl.h>
#include <sys/types.h>
#include <sys/mman.h>
int main(int argc, char *argv[])
{
int fd;
int *mp;
int i = 0;
if(-1 == (fd = open("/dev/testdev", O_RDWR)))
return -1;
mp = (int *)mmap(0, 4096, (PROT_WRITE | PROT_READ), MAP_SHARED, fd, 0);
if(MAP_FAILED == mp) {
printf("mmap failed/n");
close(fd);
return -2;
}
// success, r/w here
while(1) {
mp[0] = 4;
mp[1] = 0x111 + i++;
mp[2] = 0x222 + i++;
mp[3] = 0x333 + i++;
mp[4] = 0x444 + i++;
sleep(1);
}
close(fd);
return 0;
/* 文件操作 */
static struct file_operations xxx_fops = {
......
.mmap = _xxxx_mmap,
......
};
static int _xxxx_mmap(struct file * file, struct vm_area_struct * vma)
{
int offset;
offset = ((int)(__pa(pdata)) >> PAGE_SHIFT); // pdata是 __get_free_page得到的
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
vma->vm_flags |= VM_RESERVED;
printk("vma start: 0x%lx, buffer pfn: 0x%lx/n", vma->vm_start, offset);
if (remap_pfn_range(vma, vma->vm_start,
offset,
vma->vm_end - vma->vm_start,
vma->vm_page_prot))
return -EAGAIN;
return 0;
}
ldd3中讲到,对于常规内存,不能用remap_pfn_range,这个限制用来保证系统稳定性。
remap_pfn_range时候做外部io/mem空间映射。
所以上面的例子当然运行错误,改为nopage方式,如下(运行正常):
/* 文件操作 */
static struct file_operations xxx_fops = {
......
.mmap = _xxxx_mmap,
......
};
static int _xxxx_mmap(struct file * file, struct vm_area_struct * vma)
{
vma->vm_ops = &scullv_vm_ops;
vma->vm_flags |= VM_RESERVED;
return 0;
}
struct page *scullv_vma_nopage(struct vm_area_struct *vma,
unsigned long address, int *type)
{
struct page *page = NOPAGE_SIGBUS;
if(pdata) {
page = virt_to_page(pdata); // get_free_page得到的内存不要用vmalloc_to_page
get_page(page);
if(type)
*type = VM_FAULT_MINOR;
}
return page;
}
测试程序:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/fcntl.h>
#include <sys/types.h>
#include <sys/mman.h>
int main(int argc, char *argv[])
{
int fd;
int *mp;
int i = 0;
if(-1 == (fd = open("/dev/testdev", O_RDWR)))
return -1;
mp = (int *)mmap(0, 4096, (PROT_WRITE | PROT_READ), MAP_SHARED, fd, 0);
if(MAP_FAILED == mp) {
printf("mmap failed/n");
close(fd);
return -2;
}
// success, r/w here
while(1) {
mp[0] = 4;
mp[1] = 0x111 + i++;
mp[2] = 0x222 + i++;
mp[3] = 0x333 + i++;
mp[4] = 0x444 + i++;
sleep(1);
}
close(fd);
}