mmap.c 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. /* https://cirosantilli.com/linux-kernel-module-cheat#mmap */
  2. #include <asm-generic/io.h> /* virt_to_phys */
  3. #include <linux/fs.h>
  4. #include <linux/init.h>
  5. #include <linux/kernel.h> /* min */
  6. #include <linux/mm.h>
  7. #include <linux/module.h>
  8. #include <linux/proc_fs.h>
  9. #include <linux/uaccess.h> /* copy_from_user, copy_to_user */
  10. #include <linux/slab.h>
  11. static const char *filename = "lkmc_mmap";
  12. enum { BUFFER_SIZE = 4 };
  13. struct mmap_info {
  14. char *data;
  15. };
  16. /* After unmap. */
  17. static void vm_close(struct vm_area_struct *vma)
  18. {
  19. pr_info("vm_close\n");
  20. }
  21. /* First page access. */
  22. static vm_fault_t vm_fault(struct vm_fault *vmf)
  23. {
  24. struct page *page;
  25. struct mmap_info *info;
  26. pr_info("vm_fault\n");
  27. info = (struct mmap_info *)vmf->vma->vm_private_data;
  28. if (info->data) {
  29. page = virt_to_page(info->data);
  30. get_page(page);
  31. vmf->page = page;
  32. }
  33. return 0;
  34. }
  35. /* After mmap. TODO vs mmap, when can this happen at a different time than mmap? */
  36. static void vm_open(struct vm_area_struct *vma)
  37. {
  38. pr_info("vm_open\n");
  39. }
  40. static struct vm_operations_struct vm_ops =
  41. {
  42. .close = vm_close,
  43. .fault = vm_fault,
  44. .open = vm_open,
  45. };
  46. static int mmap(struct file *filp, struct vm_area_struct *vma)
  47. {
  48. pr_info("mmap\n");
  49. vma->vm_ops = &vm_ops;
  50. vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
  51. vma->vm_private_data = filp->private_data;
  52. vm_open(vma);
  53. return 0;
  54. }
  55. static int open(struct inode *inode, struct file *filp)
  56. {
  57. struct mmap_info *info;
  58. pr_info("open\n");
  59. info = kmalloc(sizeof(struct mmap_info), GFP_KERNEL);
  60. pr_info("virt_to_phys = 0x%llx\n", (unsigned long long)virt_to_phys((void *)info));
  61. info->data = (char *)get_zeroed_page(GFP_KERNEL);
  62. memcpy(info->data, "asdf", BUFFER_SIZE);
  63. filp->private_data = info;
  64. return 0;
  65. }
  66. static ssize_t read(struct file *filp, char __user *buf, size_t len, loff_t *off)
  67. {
  68. struct mmap_info *info;
  69. ssize_t ret;
  70. pr_info("read\n");
  71. if ((size_t)BUFFER_SIZE <= *off) {
  72. ret = 0;
  73. } else {
  74. info = filp->private_data;
  75. ret = min(len, (size_t)BUFFER_SIZE - (size_t)*off);
  76. if (copy_to_user(buf, info->data + *off, ret)) {
  77. ret = -EFAULT;
  78. } else {
  79. *off += ret;
  80. }
  81. }
  82. return ret;
  83. }
  84. static ssize_t write(struct file *filp, const char __user *buf, size_t len, loff_t *off)
  85. {
  86. struct mmap_info *info;
  87. pr_info("write\n");
  88. info = filp->private_data;
  89. if (copy_from_user(info->data, buf, min(len, (size_t)BUFFER_SIZE))) {
  90. return -EFAULT;
  91. } else {
  92. return len;
  93. }
  94. }
  95. static int release(struct inode *inode, struct file *filp)
  96. {
  97. struct mmap_info *info;
  98. pr_info("release\n");
  99. info = filp->private_data;
  100. free_page((unsigned long)info->data);
  101. kfree(info);
  102. filp->private_data = NULL;
  103. return 0;
  104. }
  105. static const struct proc_ops pops = {
  106. .proc_mmap = mmap,
  107. .proc_open = open,
  108. .proc_release = release,
  109. .proc_read = read,
  110. .proc_write = write,
  111. };
  112. static int myinit(void)
  113. {
  114. proc_create(filename, 0, NULL, &pops);
  115. return 0;
  116. }
  117. static void myexit(void)
  118. {
  119. remove_proc_entry(filename, NULL);
  120. }
  121. module_init(myinit)
  122. module_exit(myexit)
  123. MODULE_LICENSE("GPL");