例說linux核心與應用資料通訊(四):對映裝置核心空間到使用者態
阿新 • • 發佈:2019-01-25
在應用程式中呼叫mmap來實現記憶體對映,應用程式程式碼如下:#include <linux/module.h> #include <linux/types.h> #include <linux/fs.h> #include <linux/errno.h> #include <linux/mm.h> #include <linux/sched.h> #include <linux/init.h> #include <linux/cdev.h> #include <asm/io.h> #include <asm/system.h> #include <asm/uaccess.h> #include <linux/kernel.h> #include "chr_memdev.h" int chrmem_major; struct chrmem_dev *chrmem_devp; int chrmem_open(struct inode *inode, struct file *filp) { filp->private_data = chrmem_devp; return 0; } ...... void sln_vma_open(struct vm_area_struct *vma) { printk("===vma_open: %s===\n", chrmem_devp->data); } void sln_vma_close(struct vm_area_struct *vma) { printk("===vma_close: %s===\n", chrmem_devp->data); } static struct vm_operations_struct sln_remap_vm_ops = { .open = sln_vma_open, .close = sln_vma_close }; int chrmem_release(struct inode *inode, struct file *filp) { return 0; } static int chrmem_dev_mmap(struct file*filp, struct vm_area_struct *vma) { struct chrmem_dev *dev = filp->private_data; if (remap_pfn_range(vma,vma->vm_start,virt_to_phys(dev->data)>>PAGE_SHIFT, vma->vm_end - vma->vm_start, vma->vm_page_prot)) return -EAGAIN; vma->vm_ops = &sln_remap_vm_ops; sln_vma_open(vma); return 0; } static const struct file_operations chrmem_fops = { .owner = THIS_MODULE, .open = chrmem_open, .release = chrmem_release, .read = chrmem_read, .write = chrmem_write, .llseek = chrmem_llseek, .ioctl = chrmem_ioctl, .mmap = chrmem_dev_mmap }; static int chrmem_dev_init(void) { int result; dev_t devno; /* 分配裝置號 */ result = alloc_chrdev_region(&devno, 0, 1, "chrmem_dev"); if (result < 0) { return result; } // 為自定義裝置結構體分配記憶體空間 mem_devp = kmalloc(MEMDEV_NR_DEVS * sizeof(struct mem_dev), GFP_KERNEL); if (!mem_devp) { result = - ENOMEM; goto err; } memset(mem_devp, 0, sizeof(struct mem_dev)); /*初始化字元裝置*/ cdev_init(&mem_devp->cdev, &mem_fops); mem_devp->cdev.owner = THIS_MODULE; /*添加註冊字元裝置 */ mem_major = MAJOR(devno); cdev_add(&mem_devp->cdev, MKDEV(mem_major, 0), MEMDEV_NR_DEVS); /*初始化自定義裝置資料內容*/ mem_devp->data = kmalloc(MEMDEV_SIZE, GFP_KERNEL); memset(mem_devp->data, '*', MEMDEV_SIZE / 100 ); return 0; err: unregister_chrdev_region(devno, 1); return result; } static int chrmem_dev_init(void) { int result; dev_t devno; /* 分配裝置號 */ result = alloc_chrdev_region(&devno, 0, 1, "chrmem_dev"); if (result < 0) { return result; } // 為自定義裝置結構體分配記憶體空 chrmem_devp = kmalloc(CHR_MEMDEV_NUM * sizeof(struct chrmem_dev), GFP_KERNEL); if (!chrmem_devp) { result = - ENOMEM; goto err; } memset(chrmem_devp, 0, sizeof(struct chrmem_dev)); /*初始化字元裝置*/ cdev_init(&chrmem_devp->cdev, &chrmem_fops); chrmem_devp->cdev.owner = THIS_MODULE; /*添加註冊字元裝置 */ chrmem_major = MAJOR(devno); cdev_add(&chrmem_devp->cdev, MKDEV(chrmem_major, 0), CHR_MEMDEV_NUM); /*初始化自定義裝置資料內容*/ chrmem_devp->data = kmalloc(CHR_MEMDEV_DATA_SIZE, GFP_KERNEL); memset(chrmem_devp->data, '*', CHR_MEMDEV_DATA_SIZE / 100 ); return 0; err: unregister_chrdev_region(devno, 1); return result; } static void chrmem_dev_exit(void) { cdev_del(&chrmem_devp->cdev); //delete device kfree(chrmem_devp); // release device memory unregister_chrdev_region(MKDEV(chrmem_major, 0), 1); // unregister char device No. } module_init(chrmem_dev_init); module_exit(chrmem_dev_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("shallnet"); MODULE_DESCRIPTION("blog.csdn.net/shallnet");
應用程式在實現對映之後,首先讀取輸出共享記憶體內容,然後寫入,然後清空該共享記憶體內容以及重設共享記憶體。在編譯驅動和應用程式之後首先插入驅動,在建立裝置節點,最後執行應用程式看是否成功,如下:#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <sys/mman.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <sys/ioctl.h> #define SHR_MEMSIZE 4096 #define MEM_CLEAR 0x0 #define MEM_RESET 0x1 #define MEM_DEV_FILENAME "/dev/sln_memdev" int main() { int fd; char *shm = NULL; fd = open(MEM_DEV_FILENAME, O_RDWR); if (fd < 0) { printf("open(): %s\n", strerror(errno)); return -1; } shm = mmap(NULL, SHR_MEMSIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); if (MAP_FAILED == shm) { printf("mmap: %s\n", strerror(errno)); } printf("Before Write, shm = %s\n", shm); strcpy(shm,"User write to share memory!"); printf("After write, shm = %s\n", shm); if (0 > ioctl(fd, MEM_CLEAR, NULL)) { printf("ioctl: %s\n", strerror(errno)); return -1; } printf("After clear, shm = %s\n", shm); if (0 > ioctl(fd, MEM_RESET, NULL)) { printf("ioctl: %s\n", strerror(errno)); return -1; } printf("After reset, shm = %s\n", shm); munmap(shm, SHR_MEMSIZE); close(fd); return 0; }