#ifdef __KERNEL__ #include #include #include #include #include #include #include #include #include "shm_dev.h" static int max_shm_size = SHM_MEM_SIZE; module_param(max_shm_size, int, 0644); MODULE_PARM_DESC(max_shm_size_int, "Set max bytes size of share memory.\n"); #define SHM_DEV_MAJOR (200) /** * @def SHM_DEV_NAME * @brief */ #define SHM_DEV_NAME ("shmdev") ///< 设备节点名称 /** * @var typedef {anonOBJECT_DRV} SHM_DRV * @brief */ /** * @var typedef {anonOBJECT_DRV} PSHM_DRV * @brief */ /** * @struct {anonOBJECT_DRV} * @brief */ typedef struct { struct class *dev_class; ///< 设备类,用于自动在 /dev 下创建文件节点 int dev_major; ///< 设备主版本号 atomic_t ref_count; ///< 驱动程序打开计数 unsigned int mem_size; ///< 共享内存大小 unsigned char *mem_buf; ///< 共享内存指针 } SHM_DRV, *PSHM_DRV; /** * @var g_shm_dev * @brief * @see PSHM_DRV */ static PSHM_DRV g_shm_dev = NULL; //DEFINE_RWLOCK(g_obj_lock); /** * @brief * * @return * @date 2019/08/07 */ static int shmdev_proc_init(void) { return shm_dev_proc_init(); } /** * @brief * * @return * @date 2019/08/07 */ static int shmdev_proc_uninit(void) { return shm_dev_proc_uninit(); } /** * @brief * * @return * @date 2019/08/07 */ const char *shmdev_version(void) { return SHMDEV_VERSION; } /** * @brief * * @param inode * @param filp * * @return * @date 2019/08/07 */ static int shmdev_open(struct inode *inode, struct file *filp) { // 增加引用计数 atomic_inc(&g_shm_dev->ref_count); return 0; } /** * @brief * * @param inode * @param filp * * @return * @date 2019/08/07 */ static int shmdev_release(struct inode *inode, struct file *filp) { // 减少引用计数 atomic_dec(&g_shm_dev->ref_count); return 0; } /** * @brief * * @param fd * @param vma * * @return * @date 2019/08/07 */ int shmdev_mmap(struct file *fd, struct vm_area_struct *vma) { // 重新映射内存页表 int ret = remap_pfn_range(vma, vma->vm_start, virt_to_phys(g_shm_dev->mem_buf) >> PAGE_SHIFT, g_shm_dev->mem_size, PAGE_SHARED); return ret; } /** * @var shmdev_fops * @brief */ static struct file_operations shmdev_fops = { .open = shmdev_open, .release = shmdev_release, .mmap = shmdev_mmap, }; /** * @brief * * @return * @date 2019/08/07 */ static int __init shmdev_module_init(void) { struct page *p = NULL; int ret = 0; printk(KERN_INFO "Hello ISG share memory manager version: %s\n", SHMDEV_VERSION); // 分配驱动程序结构内存 g_shm_dev = (PSHM_DRV)kmalloc(sizeof(SHM_DRV), GFP_KERNEL); if(g_shm_dev == NULL) { printk(KERN_ERR "Create isg objects error\n"); return -ENOMEM; } memset(g_shm_dev, 0, sizeof(SHM_DRV)); atomic_set(&g_shm_dev->ref_count, 0); // 注册字符设备 ret = register_chrdev(SHM_DEV_MAJOR, SHM_DEV_NAME, &shmdev_fops); if(ret < 0) { kfree(g_shm_dev); printk(KERN_ERR "register_chrdev error: %d\n", ret); return -ENOENT; } printk(KERN_ERR "ret = %d, major = %u, devno = %d\n", ret, SHM_DEV_MAJOR, MKDEV(SHM_DEV_MAJOR, 0)); // 创建字符设备类 g_shm_dev->dev_class = class_create(THIS_MODULE, "shm_class"); if(g_shm_dev->dev_class == NULL) { printk(KERN_ERR "class_create error\n"); kfree(g_shm_dev); return -ENOENT; } // 创建字符设备节点 if(device_create(g_shm_dev->dev_class, NULL, MKDEV(SHM_DEV_MAJOR, 0), NULL, "shm_dev/shm%d", 0) == NULL) { printk(KERN_ERR "device_create error\n"); class_destroy(g_shm_dev->dev_class); kfree(g_shm_dev); return -ENOENT; } // 初始化共享内存 g_shm_dev->mem_size = PAGE_ALIGN(max_shm_size); g_shm_dev->mem_buf = (unsigned char *)__get_free_pages(GFP_KERNEL, get_order(g_shm_dev->mem_size)); //printk("1g_shm_dev->mem_buf(%u): %p\n", g_shm_dev->mem_size, g_shm_dev->mem_buf); if(g_shm_dev->mem_buf == NULL) { printk(KERN_ERR "Malloc %d pages error\n", get_order(g_shm_dev->mem_size)); kfree(g_shm_dev); return -ENOMEM; } // 设置保留标志,避免被其它调用分配 for(p = virt_to_page(g_shm_dev->mem_buf); p < virt_to_page(g_shm_dev->mem_buf + g_shm_dev->mem_size); p++) { SetPageReserved(p); } memset(g_shm_dev->mem_buf, 0, g_shm_dev->mem_size); // 初始化 proc 接口 shmdev_proc_init(); return 0; } module_init(shmdev_module_init); /** * @brief * * @return * @date 2019/08/07 */ static void __exit shmdev_module_exit(void) { struct page *p = NULL; printk(KERN_INFO "Bye ISG share memory manager version: %s\n", SHMDEV_VERSION); shmdev_proc_uninit(); if(atomic_read(&g_shm_dev->ref_count) != 0) { printk(KERN_ERR "Device used, please close it first.\n"); return; } if(g_shm_dev->mem_buf) { for(p = virt_to_page(g_shm_dev->mem_buf); p < virt_to_page(g_shm_dev->mem_buf + g_shm_dev->mem_size); p++) { ClearPageReserved(p); } free_pages((unsigned long)g_shm_dev->mem_buf, get_order(g_shm_dev->mem_size)); } device_destroy(g_shm_dev->dev_class, MKDEV(SHM_DEV_MAJOR, 0)); class_destroy(g_shm_dev->dev_class); unregister_chrdev(SHM_DEV_MAJOR, SHM_DEV_NAME); kfree(g_shm_dev); } module_exit(shmdev_module_exit); MODULE_LICENSE("Dual BSD/GPL"); MODULE_VERSION("0.1"); #endif // __KERNEL__