mmap driver

mmap will establish a mapping between kernel and userspace, We can use it to read data from kernel more quickly.
mmap is a function pointer in driver, so we have to write a driver to realize it, a simple char device driver is enough.
If you don't know how to write a simple char device driver, my code also can help you know it.
I descript the process as below:
1. define a mmap function for struct file_operations, which will register as a driver.
2. When userspace call mmap(system call), file_operations->mmap() will be called.
3. file_operations->mmap should call remap_page_range() to map the memory between userspace and kernel space.
4. userspace call mmap actively, mmap return a void pointer. Now If userspace modify the pointer'
s content, kernel will be modified at the same time.

here is also some link which maybe can help you:
1. has a sample too: http://linux.insigma.com.cn/devbbs/printpage.asp?BoardID=14&ID=100

2. has a userspace sample too: http://www.opengroup.org/onlinepubs/009695399/functions/mmap.html

3. "man mmap" will help you more, such as the difference between MAP_SHARED and MAP_PRIVATE.
4. Linux Device Driver(ldd2) has some introduce about mmap. (Section 13)

Note:
1. We should malloc whole page memory in kernel for map.
2. A non-regular file can't be map to write.
3. The size that userspace request to map, will be changed to whole page then sent to kernel.

below is code:
kernel module: mmap.c
Code:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <asm/uaccess.h>
#include <linux/wrapper.h>
#include <asm/io.h>
MODULE_PARM(mmap_major, "i");
MODULE_PARM(mmap_nr_devs, "i");
#define DEVICE "mmap"
#define DATASIZE PAGE_SIZE<<3
int mmap_major = 0;
int mmap_nr_devs = 1;
typedef struct mmap_state
{
   char data[DATASIZE];
   unsigned int size;
   void *handle;
   unsigned int access_key;
   struct semaphore sem;
}mmap_state;

#define TYPE(dev) (MINOR(dev) >>4)
#define NUM(dev) (MINOR(dev) &0xf)

int mmap_open(struct inode *inode, struct file *filp);
ssize_t mmap_read(struct file *filp, char *buf, size_t count, loff_t *f_pos);
ssize_t mmap_write(struct file *filp,const char *buf,size_t count,loff_t *f_pos);
int mmap_release(struct inode *inode, struct file *filp);
static int mmap_mmap(struct file * file, struct vm_area_struct * vma);
int mmap_trim(mmap_state *dev);
int mmap_init_module(void);
void mmap_cleanup_module(void);

struct file_operations mmap_fops = {
   open: mmap_open,
   read: mmap_read,
   write: mmap_write,
   llseek: NULL,
   ioctl: NULL,
   release: mmap_release,
   mmap: mmap_mmap,
};

mmap_state *mmap_devices;

int mmap_open(struct inode *inode, struct file *filp)
{
   mmap_state *dev;
   int num = NUM(inode->i_rdev);
   int type = TYPE(inode->i_rdev);
   if (!filp->private_data && type)
   {
      printk(KERN_WARNING"data is not valid/n");
      return 0;
   }
   dev = (mmap_state *)filp->private_data;
   if (!dev)
   {
      if (num >= mmap_nr_devs)
         return -ENODEV;
      dev = &mmap_devices[num];
      filp->private_data = dev;
   }
   MOD_INC_USE_COUNT;
   if ( (filp->f_flags & O_ACCMODE) == O_WRONLY)
   {
      if (down_interruptible(&dev->sem))
      {
         MOD_DEC_USE_COUNT;
         return -ERESTARTSYS;
      }
      mmap_trim(dev);
      up(&dev->sem);
   }
   return 0;
}
static int mmap_mmap(struct file * file, struct vm_area_struct * vma)
{
   struct mmap_state *state = (struct mmap_state *)file->private_data;
   unsigned long size;
   int ret = -EINVAL;
   //printk("mmap_mmap()/n");
   if (vma->vm_pgoff != 0)
   {
      printk(" vm_pgoff != 0/n");
      goto error;
   }
   /* Don'
t try to swap out physical pages.. */
   vma->vm_flags |= VM_RESERVED;
   size = vma->vm_end - vma->vm_start;
   //printk(" data = [%p]/n", state->data);

   //printk(" content = [%s]/n", state->data);

   //printk(" start=[%lu] size=[%lu] end=[%lu]/n", vma->vm_start, size, vma->vm_end);

   if (size > state->size)
      goto error;
   if (remap_page_range( vma->vm_start, virt_to_phys(state->data), size,
                 vma->vm_page_prot))
      return -EAGAIN;
   //printk("mmap_mmap() success/n");

   return 0;
error:
   return ret;
}

int mmap_release(struct inode *inode, struct file *filp)
{
   MOD_DEC_USE_COUNT;
   return 0;
}

ssize_t mmap_read(struct file *filp, char *buf, size_t count,
               loff_t *f_pos)
{
   int ret = 0;
   mmap_state *dev = filp->private_data;
   if (down_interruptible(&dev->sem))
      return -ERESTARTSYS;
   if (*f_pos >= dev->size)
      goto out;
   if (*f_pos + count > dev->size)
      count = dev->size - *f_pos;
   if (copy_to_user(buf, &dev->data[*f_pos], count))
   {
      ret = -EFAULT;
      goto out;
   }
   *f_pos += count;
   ret = count;
out:
   up(&dev->sem);
   return ret;
}
ssize_t
mmap_write(struct file *filp, const char *buf, size_t count,loff_t *f_pos)
{
   int ret = 0;
   mmap_state *dev = filp->private_data;
   if (down_interruptible(&dev->sem))
      return -ERESTARTSYS;
   if (*f_pos + count > dev->size)
      count = dev->size - *f_pos;
   if (copy_from_user(&dev->data[*f_pos], buf, count))
   {
      ret = -EFAULT;
      goto out;
   }
   *f_pos += count;
   ret = count;

   if (dev->size < *f_pos)
      dev->size = *f_pos;
   
out:
   up(&dev->sem);
   return ret;
}

int mmap_trim(mmap_state *dev)
{
   memset(dev->data, 0, sizeof(dev->data));
   return 0;
}
int mmap_init_module(void)
{
   int result, i;
   struct page *page;
   SET_MODULE_OWNER(&mmap_fops);
   result = register_chrdev(mmap_major, DEVICE, &mmap_fops);
   if (result < 0)
   {
      
      printk(KERN_WARNING "mmap:cann't get major %d/n", mmap_major);
      return result;
   }
   if (mmap_major == 0)
      mmap_major = result;
   mmap_devices = kmalloc(mmap_nr_devs*sizeof(mmap_state),GFP_KERNEL);
   if (!mmap_devices)
   {
      result = -ENOMEM;
      goto fail;
   }
   memset(mmap_devices, 0, mmap_nr_devs * sizeof(mmap_state));
   for (i = 0; i < mmap_nr_devs; i++)
   {
      memset(mmap_devices[i].data, 0, sizeof(mmap_devices[i].data));
                                strcpy(mmap_devices[i].data, "aaa");
      mmap_devices[i].size = DATASIZE;
      /* Note here: if miss it, user space will get NULL */
      for (page = virt_to_page(mmap_devices[i].data); page <= virt_to_page(mmap_devices[i].data + (DATASIZE)); page++)
      {
         mem_map_reserve(page);
      }
      
      sema_init(&mmap_devices[i].sem, 1);
   }
   
   EXPORT_NO_SYMBOLS;
   return 0;
fail:
   mmap_cleanup_module();
   return result;
}

void mmap_cleanup_module(void)
{
   int i;
   unregister_chrdev(mmap_major, DEVICE);
   if (mmap_devices)
   {
      for (i = 0; i < mmap_nr_devs; i++)
         mmap_trim(mmap_devices + i);
      kfree(mmap_devices);
   }
}
module_init(mmap_init_module);
module_exit(mmap_cleanup_module);
MODULE_LICENSE("GPL");
EXPORT_NO_SYMBOLS;

Makefile here:
Code:
KERNELDIR = /usr/src/linux

include $(KERNELDIR)/.config

CFLAGS = -DEXPORT_SYMTAB -D__KERNEL__ -DMODULE -I$(KERNELDIR)/include -O -Wall

ifdef CONFIG_SMP
   CFLAGS += -D__SMP__ -DSMP
endif

ifdef CONFIG_MODVERSIONS
   CFLAGS += -DMODVERSIONS /
      -include $(KERNELDIR)/include/linux/modversions.h
endif
OBJ=mmap.o
all:$(OBJ)
clean:
   rm -f *.o



userspace: mmap_user.c
Code:
#include <sys/mman.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
int main()
{
   char *ptr = NULL;
   int fd = open("/dev/mmap0", O_RDWR);
   if (fd <= 0)
   {
      printf("open fail/n");
      return 1;
   }
   ptr = mmap(0, 90, PROT_WRITE|PROT_READ, MAP_SHARED, fd, 0);
   printf("ptr = [%s]/n", ptr);
   ptr[2] = 'c';
   printf("ptr = [%s]/n", ptr);
}



here is also a script to register a device:
Code:
#!/bin/sh
module="mmap"
device="mmap"
mode="664"

/sbin/insmod ./$module.o $* || exit 1
major=`cat /proc/devices | awk "//$2==/"$device/" {print //$1}"`
echo $major
rm -f /dev/${device}[0-3]
mknod /dev/${device}0 c $major 0
ln -sf ${device}0 /dev/${device}

一、综合实战—使用极轴追踪方式绘制信号灯 实战目标:利用对象捕捉追踪和极轴追踪功能创建信号灯图形 技术要点:结合两种追踪方式实现精确绘图,适用于工程制图中需要精确定位的场景 1. 切换至AutoCAD 操作步骤: 启动AutoCAD 2016软件 打开随书光盘中的素材文件 确认工作空间为"草图与注释"模式 2. 绘图设置 1)草图设置对话框 打开方式:通过"工具→绘图设置"菜单命令 功能定位:该对话框包含捕捉、追踪等核心绘图辅助功能设置 2)对象捕捉设置 关键配置: 启用对象捕捉(F3快捷键) 启用对象捕捉追踪(F11快捷键) 勾选端点、中心、圆心、象限点等常用捕捉模式 追踪原理:命令执行时悬停光标可显示追踪矢量,再次悬停可停止追踪 3)极轴追踪设置 参数设置: 启用极轴追踪功能 设置角度增量为45度 确认后退出对话框 3. 绘制信号灯 1)绘制圆形 执行命令:"绘图→圆→圆心、半径"命令 绘制过程: 使用对象捕捉追踪定位矩形中心作为圆心 输入半径值30并按Enter确认 通过象限点捕捉确保圆形位置准确 2)绘制直线 操作要点: 选择"绘图→直线"命令 捕捉矩形上边中点作为起点 捕捉圆的上象限点作为终点 按Enter结束当前直线命令 重复技巧: 按Enter可重复最近使用的直线命令 通过圆心捕捉和极轴追踪绘制放射状直线 最终形成完整的信号灯指示图案 3)完成绘制 验证要点: 检查所有直线是否准确连接圆心和象限点 确认极轴追踪的45度增量是否体现 保存绘图文件(快捷键Ctrl+S)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值