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;
char size_py;
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);
用户态:
#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;
char addr_cnt_len;
char _buf;
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()实现的,并且分配的是地址是连续的物理地址,大小也肯定是页的整数倍,我的程序理论上应该是可行的,请大家多多讨论,帮助小弟解决下,谢了啊!! 补充下顺便顶下,网上大部分都是那种字符设备映射的例子,我不想那样做,这样做怎么会出错呢?大家给点意见啊 内核是不是不支持dev/mem映射到用户态了。貌似需要打开开关编译才行。 初学 者路 过.
你是 想要 在 上层 进行 映社 吗?
那 可 能 不行 .因 为 你 从 kernel 那到 的 那 个是 kernel space address, 上层 的function 是 没 法用 的 ,也 就是 那 个mmap会 出 错 .
说 错 勿 怪 ,偶 是 刚 从 win 投诚过来 的.:P 回复 1# 爱迟到
map_addr =(char *)mmap(0, size , PROT_READ | PROT_WRITE, MAP_SHARED, fd, _addr);
兄弟,你把这个函数的PROT_WRITE这个选项去掉,用户权限级别不能写内核映射出来的内存,你试试 谢谢,我试下啊 回复 6# 爱迟到
试完了之后告诉我一声 回复爱迟到
map_addr =(char *)mmap(0, size , PROT_READ | PROT_WRITE, MAP_SHARED, fd, _add ...
chenrvmldd 发表于 2011-04-21 20:05 http://bbs.chinaunix.net/images/common/back.gif
写权限能不能用,关键看driver里面的mmap是怎么实现的,支不支持。 要映射到用户空间,应该用remap_vmalloc_range这样的函数,我没看到你用。。。。
页:
[1]