您的位置:首页 > 其它

用户空间与内核空间数据交换之mmap

2015-10-15 16:11 316 查看
在阅读以下测试程序之前先要搞清楚驱动程序中__get_free_pages的用法:

unsigned long __get_free_pages(unsigned int gfp_mask, unsigned int order)


This function works the same as alloc_pages(), except that it directly returns the logical address of the first requested page. Because the pages are contiguous, the other pages simply follow from the first.

还有几点值得注意:

__get_free_pages() 函数的第一个变量 gfp_mask 可以直接使用 kmalloc() 函数中使用的参数。但是,第二个变量不是指定大小,而表示 2^order 次方个页,如是 0 就分配一个页,是 3 就分配 8 个页。

使用该函数时,一定要注意 order 最大值,该最大值定义为 MAX_ORDER ,通常为 11 ,也可能是 10 ,这根据平台的不同而不同。如果 order 的值国大,则分配失败的几率就较高,通常使用小于 5 的值,即只分配 32 x PAGE_SIZE 大小的内存。

其实 kmalloc() 的底层实现也是基于 __get_free_pages() 。

如果想为分配一块内存空间,但嫌计算所需多少页比较麻烦,那可以使用 get_order() 函数来获取 order 值。

//内核模块测试程序
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/mm.h>

static unsigned long p = 0;

static int __init shao_init(void)
{
//分配共享内存(一个页面) 第二个参数即二的零次方个页面
//关于:在linux/gfp.h中定义的一个宏,是分配内核空间的内存时的一个标志位。这个标志位分配内存的一个选项,GFP_KERNEL是内核内存分配时
//最常用的,无内存可用时可引起休眠。
p = __get_free_pages(GFP_KERNEL, 0);
SetPageReserved(virt_to_page(p));

printk("<1> p = 0x%08x/n", p);

//在共享内存中写上一个字符串
strcpy(p, "Hello world!/n");

return 0;
}

static void __exit shao_exit(void)
{
ClearPageReserved(virt_to_page(p));
free_pages(p, 0);
}

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Kuanish");
MODULE_DESCRIPTION("mmap test");

module_init(shao_init);
module_exit(shao_exit);

//用户态测试程序
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>

#define PAGE_SIZE (4*1024)
#define PAGE_OFFSET 0xc0000000
#define KERNEL_VIRT_ADDR 0xc5e3c000 //此处地址即为内核模块打印的地址p,动态的不固定,需要自行修改

int main()
{
char *buf;
int fd;
unsigned long phy_addr;

fd=open("/dev/mem",O_RDWR);
if(fd == -1)
perror("open");
phy_addr=KERNEL_VIRT_ADDR - PAGE_OFFSET;

buf=mmap(0, PAGE_SIZE,
PROT_READ|PROT_WRITE, MAP_SHARED,
fd, phy_addr);
if(buf == MAP_FAILED)
perror("mmap");
puts(buf);//打印共享内存的内容
munmap(buf,PAGE_SIZE);

close(fd);
return 0;
}

还有一个问题值得思考,这块可被用户态和内核态同时访问的内存如何同步互斥呢?
如何考虑用信号量肯定是不行的,因为它无法介于内核态和用户态使用。
那么互斥锁行不行呢?似乎只能采用标志位来解决跨用户态与内核态的互斥同步问题了,但这样做程序的正确性又受到挑战。

参考: http://www.makelinux.net/books/lkd2/ch11lev1sec3 http://www.groad.net/bbs/thread-1113-1-1.html https://www.ibm.com/developerworks/cn/linux/l-netlink/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: