- 论坛徽章:
- 20
|
本帖最后由 nswcfd 于 2016-12-02 15:51 编辑
- #define DRV_NAME "mmap"
- #define DRV_VERSION "0.1"
- #include <linux/module.h>
- #include <linux/kernel.h>
- #include <linux/mm.h>
- #include <linux/miscdevice.h>
- static int mmap_chr_close(struct inode *inode, struct file *file)
- {
- printk("chr close\n");
- return 0;
- }
- int nomap;
- module_param(nomap, int, 0);
- static struct page *page;
- static void mmap_open(struct vm_area_struct *vma)
- {
- printk("mmap_open: vma->start=%lx\n", vma->vm_start);
- }
- static void mmap_close(struct vm_area_struct *vma)
- {
- printk("mmap_close: vma->start=%lx\n", vma->vm_start);
- }
- static struct vm_operations_struct mmap_ops = {
- .open = mmap_open,
- .close = mmap_close,
- };
- static int mmap_chr_mmap(struct file *file, struct vm_area_struct *vma)
- {
- int err = -ENODEV;
- printk("vma->start=%lx, vma->end=%lx\n", vma->vm_start, vma->vm_end);
- if (nomap || !page)
- return -ENODEV;
- printk("page=%p, address=%p\n", page, page_address(page));
- *(int *)page_address(page) = current->pid;
- err = vm_insert_page(vma, vma->vm_start, page);
- if (err)
- return err;
- vma->vm_ops = &mmap_ops;
- return 0;
- }
- static struct file_operations mmap_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .release = mmap_chr_close,
- .mmap = mmap_chr_mmap,
- };
- #define TUN_MINOR 200
- #define MMAP_MINOR TUN_MINOR
- static struct miscdevice mmap_miscdev = {
- .minor = MMAP_MINOR,
- .name = "mmap",
- .fops = &mmap_fops,
- };
- static int __init mmap_init(void)
- {
- int ret = 0;
- page = alloc_page(GFP_KERNEL);
- printk("page=%p, addr=%p\n", page, page_address(page));
- ret = misc_register(&mmap_miscdev);
- if (ret)
- printk(KERN_ERR "mmap: Can't register misc device %d\n", MMAP_MINOR);
- return ret;
- }
- static void mmap_cleanup(void)
- {
- if (page)
- __free_page(page);
- misc_deregister(&mmap_miscdev);
- }
- module_init(mmap_init);
- module_exit(mmap_cleanup);
- MODULE_LICENSE("GPL");
- MODULE_ALIAS_MISCDEV(MMAP_MINOR);
复制代码
- #include <stdio.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <sys/mman.h>
- int main()
- {
- int fd = open("mmap_dev", O_RDWR);
- printf("fd=%d\n", fd);
- if (fd < 0)
- return 1;
- char *p = mmap(0, 10, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
- printf("mmap=%p\n", p);
- if (p != MAP_FAILED)
- printf("map[0]=%d, pid=%d\n", *(int *)p, getpid());
- }
复制代码
# ./mmap_test
fd=3
<4>vma->start=2ad8378f7000, vma->end=2ad8378f8000
<4>page=ffff810000b21b78, address=ffff810012d59000
mmap=0x2ad8378f7000
map[0]=4557, pid=4557
<4>mmap_close: vma->start=2ad8378f7000
<4>chr close
注意kernel执行fops->mmap的参数(vma->start)和用户态mmap返回的数值是一样的。
也就是说,在响应mmap syscall的时候,内核先分配vma(分配用户态线性地址),然后调用fops->mmap回调(关键步骤set_pte映射页表),最后给用户态返回vma->start。
|
|