本文共 3871 字,大约阅读时间需要 12 分钟。
转自:
在内核申请一片物理内存,映射到用户空间使用的方法。环境:Linux ubuntu 4.10.0-42-generic。
方法经博主测试,测试环境:ubuntu 16.04,内核版本:linux-4.15
map.c:
#include#include #include #include #include #include #include #include //#include #include #include #include #include #include #include #include #include #include #include #include #include #define MMAPIOMEM_DEV_NAME "mmapiomem" #define MMAPIOMEM_DEV_MAJOR 280 #define MMAP_BUF_SIZE 0x500 char *mmap_buf_ptr; int mmapiomem_open(struct inode *inode,struct file *filp) { return 0; } int mmapiomem_release(struct inode *inode,struct file *filp) { return 0; } int mmapiomem_mmap(struct file *filp,struct vm_area_struct *vma) { int result; unsigned long page; vma->vm_flags |= (VM_IO | VM_LOCKED | (VM_DONTEXPAND | VM_DONTDUMP)); vma->vm_flags|=VM_IO; page = virt_to_phys(mmap_buf_ptr); result = remap_pfn_range(vma, vma->vm_start, ((unsigned int)page)>>PAGE_SHIFT, PAGE_SIZE*4, vma->vm_page_prot); if(result) { return -EAGAIN; } return 0; } struct file_operations mmapiomem_fops={ .owner=THIS_MODULE, .open=mmapiomem_open, .release=mmapiomem_release, .mmap=mmapiomem_mmap, }; struct cdev *mmap_cdev; struct class *mmap_class; int mmapiomem_init(void) { int result; int devno = MKDEV(MMAPIOMEM_DEV_MAJOR,0); mmap_buf_ptr = (char*)__get_free_pages(GFP_KERNEL,2); printk("%s,the mmap_buf_ptr is 0x%p\n",__func__,mmap_buf_ptr); memset(mmap_buf_ptr,0,PAGE_SIZE*4); *((unsigned int *)(mmap_buf_ptr)) = 0xc3a21b44; *((unsigned int *)(mmap_buf_ptr+0x4)) = 0xab8812df; mmap_cdev = cdev_alloc(); result = register_chrdev_region(devno,1,"mmap_char_mem"); cdev_init(mmap_cdev,&mmapiomem_fops); mmap_cdev->owner = THIS_MODULE; result = cdev_add(mmap_cdev, devno,1); mmap_class = class_create(THIS_MODULE,"mmap_char_class"); if (IS_ERR(mmap_class)) { result= PTR_ERR(mmap_class); return -1; } device_create(mmap_class, NULL, devno, NULL, MMAPIOMEM_DEV_NAME); return 0; } void mmapiomem_exit(void) { if (mmap_cdev != NULL) cdev_del(mmap_cdev); device_destroy(mmap_class,MKDEV(MMAPIOMEM_DEV_MAJOR,0)); class_destroy(mmap_class); unregister_chrdev_region(MKDEV(MMAPIOMEM_DEV_MAJOR,0),1); } module_init(mmapiomem_init); module_exit(mmapiomem_exit); MODULE_LICENSE("Dual BSD/GPL");
Makefile:
obj-m := map.oall: $(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(PWD) modulesclean: $(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
以上是内核部分,主要是创建一个字符设备,配置其mmap函数,分配连续内存。分配了4pages,并将首地址开始初始化了8bytes。
具体使用方法是:make insmod map.ko dmesg-c
最后打印出:
mmapiomem_init,the mmap_buf_ptr is 0xffff880129880000
user_test.c:
#include#include #include #include #include #include #include #include #include #include #define DEVICE_FILENAME "/dev/mmapiomem" #define MMAP_SIZE 0x8000 int main() { int ttydev; int dev,i; uint8_t *ptrdata; dev=open(DEVICE_FILENAME,O_RDWR|O_NDELAY); if(dev>=0) { printf("2)open the dev success\n"); ptrdata=(uint8_t*)mmap((void*)0x000000000f000000, MMAP_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, dev, 0); if(ptrdata!=NULL) { printf("the value of ptrdata0 is 0x%02x\n",*ptrdata); printf("the value of ptrdata1 is 0x%02x\n",*(ptrdata+0x1)); printf("the value of ptrdata2 is 0x%02x\n",*(ptrdata+0x2)); printf("the value of ptrdata3 is 0x%02x\n",*(ptrdata+0x3)); printf("the value of ptrdata4 is 0x%02x\n",*(ptrdata+0x4)); printf("the value of ptrdata5 is 0x%02x\n",*(ptrdata+0x5)); printf("the value of ptrdata6 is 0x%02x\n",*(ptrdata+0x6)); printf("the value of ptrdata7 is 0x%02x\n",*(ptrdata+0x7)); printf("the addr_map is: %p\n",ptrdata); } } close(dev); printf("6)here close the dev\n"); return 0; }
在虚拟机上测试结果如下:
可以看到在虚拟机下测试不成功,移步真机得到如下测试结果:
真机测试成功,可以看到,已经映射成功并且读取了我们之前初始化的值,返回了一个用户空间内存地址。因为程序结束后映射会取消掉,所以如果需要使用该地址的话,直接把这个addr_map传给自己的其他接口函数就行。
转载地址:http://othxi.baihongyu.com/