kmalloc申请的内存映射到用户态的问题
我最近写一个内存映射的模块,上网查了些资料,自己也写了测试程序,可是映射出现问题:
- #include <linux/module.h>
- #include <linux/slab.h>
- #include <linux/init.h>
- #include <linux/kthread.h>
- #include <asm/uaccess.h>
- #include <linux/proc_fs.h>
- #include <linux/err.h>
- #include <linux/mm.h>
- #include <asm/page.h>
- MODULE_AUTHOR("cwj@126.com");
- MODULE_DESCRIPTION("KENEL_MAP.DEMO");
- MODULE_LICENSE("GPL");
- #define MEM_SHARE_DIR "mem_share_dir"
- #define MEM_SHARE_ADDR "mem_share_addr"
- #define MEM_SHARE_SIZE "mem_share_size"
- #define MEM_SIZE 100
- #define PARM_SIZE 32
- unsigned long addr;
- char addr_py[PARM_SIZE];
- char size_py[PARM_SIZE];
- unsigned long addr_cnt_len;
- int i;
- static struct task_struct *thread_map;
- static struct proc_dir_entry *mem_share_dir;
- static struct proc_dir_entry *mem_share_addr;
- static struct proc_dir_entry *mem_share_size;
- static unsigned char *p1, *p2, *p3;
- long atol(const char *str)
- {
- unsigned int index;
- unsigned int num;
- int ret;
- ret = 0;
- index = 1;
- num = 0;
- //计算字符串的长度(strlen的实现,字符串中只包含数字字符)
- while(*str)
- {
- if(*str < '0' || *str > '9') //判断字符是否是数字
- {
- return -1;
- }
- str++;
- num++;
- }
- //转换字符到相应的数字,这里最好的数据结构描述应该是栈
- while(str--, num--)
- {
- ret += index * (*str - '0');
- index *= 10;
- }
- return ret;
- }
- static int proc_read_addr(char *page, char **start, off_t off, int count, int *eof, void *data)
- {
- int ret;
- ret = 0;
- if(off > 0)
- {
- printk("copy has finished !\n");
- return ret;
- }
- if(addr == 0)
- {
- return ret;
- }
- sprintf(page, "%lu", addr);
- printk("page =%s, addr = %lu\n", page, addr);
- ret = PARM_SIZE;
- return ret;
- }
- static int proc_write_addr(struct file *fp, const char *buf, unsigned long count, void *data)
- {
- int ret;
- memset(addr_py, 0, PARM_SIZE);
- ret = count;
- if(count > PARM_SIZE && count == 0)
- {
- printk("buf fault!\n");
- return 0;
- }
- if(copy_from_user(addr_py, buf, count))
- {
- printk("copy_from_user fault!\n");
- return -1;
- }
- return ret;
- }
- static int proc_read_size(char *page, char **start, off_t off, int count, int *eof, void *data)
- {
- int ret;
- ret = 0;
- if(off > 0)
- {
- printk("copy has finished !\n");
- return ret;
- }
- if(addr_cnt_len == 0)
- {
- return 0;
- }
- sprintf(page, "%lu", addr_cnt_len);
- ret = PARM_SIZE;
- return ret;
- }
- static int proc_write_size(struct file *fp, const char *buf, unsigned long count, void *data)
- {
- int ret;
- memset(size_py, 0, PARM_SIZE);
- ret = count;
- if(count > PARM_SIZE && count == 0)
- {
- printk("buf fault!\n");
- return 0;
- }
- if(copy_from_user(size_py, buf, count))
- {
- printk("copy_from_user fault!\n");
- return -1;
- }
- addr_cnt_len = atol(size_py);
- return ret;
- }
- static int thread_map_func(void *data)
- {
- if(kthread_should_stop())
- return 0;
- while(p1 || p2 || p3)
- {
- set_current_state(TASK_UNINTERRUPTIBLE);
- if(kthread_should_stop())
- break;
- if(i == 3 && addr_cnt_len == 0)
- {
- break;
- }
- if(addr_cnt_len != 0)
- goto __next;
- if(p1 && i == 0)
- {
- SetPageReserved(virt_to_page(p1));
- addr = __pa(p1);
- addr_cnt_len = 27;
- i++;
- }
- else if(p2 && i == 1)
- {
- SetPageReserved(virt_to_page(p2));
- addr = __pa(p2);
- addr_cnt_len = 27;
- i++;
- }
- else if(p3 && i == 2)
- {
- SetPageReserved(virt_to_page(p3));
- addr = __pa(p3);
- addr_cnt_len = 27;
- i++;
- }
- printk("py = %lu\n", addr);
- __next:
- schedule_timeout(50 * HZ);
- }
- return 0;
- }
- static int __init init_kernel_map(void)
- {
- thread_map = NULL;
- mem_share_dir = NULL;
- mem_share_addr = NULL;
- mem_share_size = NULL;
- mem_share_dir = proc_mkdir(MEM_SHARE_DIR, NULL);
- if(mem_share_dir == NULL)
- {
- printk("proc create fault!\n");
- return 0;
- }
- mem_share_addr = create_proc_entry(MEM_SHARE_ADDR, 0644, mem_share_dir);
- if(mem_share_addr == NULL)
- {
- remove_proc_entry(MEM_SHARE_DIR, NULL);
- printk("mem_share_addr fault!\n");
- return 0;
- }
- mem_share_addr->read_proc = proc_read_addr;
- mem_share_addr->write_proc = proc_write_addr;
- mem_share_addr->uid = 0;
- mem_share_addr->gid = 0;
- mem_share_size = create_proc_entry(MEM_SHARE_SIZE, 0644, mem_share_dir);
- if(mem_share_size == NULL)
- {
- remove_proc_entry(MEM_SHARE_ADDR, mem_share_dir);
- remove_proc_entry(MEM_SHARE_DIR, NULL);
- printk("mem_share_size fault!\n");
- return 0;
- }
- mem_share_size->read_proc = proc_read_size;
- mem_share_size->write_proc = proc_write_size;
- mem_share_size->uid = 0;
- mem_share_size->gid = 0;
- thread_map = kthread_create(thread_map_func, NULL, "kernel_mem_share");
- if(IS_ERR(thread_map))
- {
- printk("thread create fault!\n");
- return 0;
- }
- p1 = kmalloc(MEM_SIZE, GFP_KERNEL);
- p2 = kmalloc(MEM_SIZE, GFP_KERNEL);
- p3 = kmalloc(MEM_SIZE, GFP_KERNEL);
- memset(p1, 0, MEM_SIZE);
- memset(p2, 0, MEM_SIZE);
- memset(p3, 0, MEM_SIZE);
- memcpy(p1, "111111111111111111111111111", 27);
- memcpy(p2, "222222222222222222222222222", 27);
- memcpy(p3, "333333333333333333333333333", 27);
- wake_up_process(thread_map);
- return 0;
- }
- static void __exit exit_kernel_map(void)
- {
- if(p1)
- {
- ClearPageReserved(virt_to_page(p1));
- kfree(p1);
- p1 = NULL;
- }
- if(p2)
- {
- ClearPageReserved(virt_to_page(p2));
- kfree(p2);
- p2 = NULL;
- }
- if(p3)
- {
- ClearPageReserved(virt_to_page(p3));
- kfree(p3);
- p3 = NULL;
- }
- remove_proc_entry(MEM_SHARE_ADDR, mem_share_dir);
- remove_proc_entry(MEM_SHARE_SIZE, mem_share_dir);
- remove_proc_entry(MEM_SHARE_DIR, NULL);
- if(thread_map)
- {
- kthread_stop(thread_map);
- thread_map = NULL;
- }
- }
- module_init(init_kernel_map);
- module_exit(exit_kernel_map);
复制代码
- 用户态:
- [code]#include <stdio.h>
- #include <unistd.h>
- #include <sys/stat.h>
- #include <sys/mman.h>
- #include <fcntl.h>
- #include <sys/types.h>
- #include <stdlib.h>
- #include <string.h>
- #define MEM_SIZE 100
- #define MEM_ADDR_SIZE 32
- #define PAGE_SIZE 4096
- unsigned long addr;
- unsigned long addr_cnt_size;
- char _addr[MEM_ADDR_SIZE];
- char addr_cnt_len[MEM_ADDR_SIZE];
- char _buf[MEM_SIZE];
- char *map_addr;
- int get_mem(int fd, unsigned long _addr, char *buf, unsigned long size)
- {
- unsigned long size_cpy;
- size_cpy = size;
- if(size % PAGE_SIZE)
- size = (size / PAGE_SIZE + 1) << 12;
- else
- size = (size / PAGE_SIZE) << 12;
- map_addr =(char *)mmap(0, size , PROT_READ | PROT_WRITE, MAP_SHARED, fd, _addr);
- perror("mmap");
- if(!map_addr)
- {
- return 0;
- }
- memcpy(buf, map_addr, size_cpy);
- munmap(map_addr, size);
- return 1;
- }
- int main(int argc, char *argv[])
- {
- int fd;
- int fd_addr;
- int fd_size;
- int i;
- i = 0;
- fd = open("/dev/mem", O_RDWR);
- fd_addr = open("/proc/mem_share_dir/mem_share_addr", O_RDWR);
- fd_size = open("/proc/mem_share_dir/mem_share_size", O_RDWR);
- while(1)
- {
- if(i == 0 || !addr_cnt_size){
- memset(_addr, 0, MEM_ADDR_SIZE);
- map_addr = NULL;
- read(fd_addr, _addr, MEM_ADDR_SIZE);
- printf("%s\n", _addr);
- addr = atol(_addr);
- if(addr == 0)
- continue;
- printf("addr = %u[%8lx]\n", addr);
- memset(addr_cnt_len, 0, MEM_ADDR_SIZE);
- read(fd_size, addr_cnt_len, MEM_ADDR_SIZE);
- addr_cnt_size = atol(addr_cnt_len);
- printf("size = %u[%8lx]\n", addr_cnt_size);
- if(get_mem(fd, addr, _buf, addr_cnt_size))
- {
- i++;
- printf("mem_cnt = %s\n", _buf);
- }
- }
- sleep(100);
- if(i == 3)
- {
- break;
- }
- }
- close(fd_addr);
- close(fd_size);
- close(fd);
- }
复制代码上面是小弟写的用户态与内核态的例子,在运行该例子的时候,内核地址取的都对但是用户态映射不成功。
用户态程序运行后会出现如下的错误:
- 189023744
- addr = 189023744[ b444600]
- size = 27[ 1b]
- mmap: Invalid argument
- Segmentation fault (core dumped)
复制代码kmalloc既然在实现上是调用的_get_free_pages()实现的,并且分配的是地址是连续的物理地址,大小也肯定是页的整数倍,我的程序理论上应该是可行的,请大家多多讨论,帮助小弟解决下,谢了啊!!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
写权限能不能用,关键看driver里面的mmap是怎么实现的,支不支持。
要映射到用户空间,应该用remap_vmalloc_range这样的函数,我没看到你用。。。。
回复 6# 爱迟到
试完了之后告诉我一声
谢谢,我试下啊
回复 1# 爱迟到
map_addr =(char *)mmap(0, size , PROT_READ | PROT_WRITE, MAP_SHARED, fd, _addr);
兄弟,你把这个函数的PROT_WRITE这个选项去掉,用户权限级别不能写内核映射出来的内存,你试试
初学 者路 过.
你是 想要 在 上层 进行 映社 吗?
那 可 能 不行 .因 为 你 从 kernel 那到 的 那 个是 kernel space address, 上层 的function 是 没 法用 的 ,也 就是 那 个mmap会 出 错 .
说 错 勿 怪 ,偶 是 刚 从 win 投诚过来 的.
内核是不是不支持dev/mem映射到用户态了。貌似需要打开开关编译才行。
补充下顺便顶下,网上大部分都是那种字符设备映射的例子,我不想那样做,这样做怎么会出错呢?大家给点意见啊