Linux应用层编程,如何申请物理地址连续的内存空间?
如题,面试时被问到,我们知道,在内核层可以通过 kmalloc 等函数申请到物理地址连续的内存地址,但是在应用层呢?面试官说有办法,期待高手。。。
Answers
在用户空间申请连续的物理内存需要调用mmap()函数,函数原型如下:
/**
* mmap - 将物理地址映射至用户空间
* @addr: 指定文件应被映射到进程空间的起始地址,一般被指定为NULL,此时选择起始地址的任务留给内核来完成
* @len: 映射到用户空间的字节数
* @prot: 指定被映射空间的访问权限,可取如下几个值的或:
* PROT_READ(可读),PROT_WRITE (可写),PROT_EXEC (可执行)
PROT_NONE(不可访问)
* @flags: 由以下几个常值指定:MAP_SHARED,MAP_PRIVATE,MAP_FIXED,MAP_ANON
* @fd: 映射到用户空间的文件的描述符,一般由open()返回
* fd可以指定为-1,此时须指定flags参数中的MAP_ANON,表明进行的是匿名映射
* @offset: 被映射内存区在文件中的偏移值
*/
void* mmap(void * addr, size_t len, int prot, int flags, int fd, off_t offset);
该函数映射文件描述符 fd 指定文件的 [offset, offset + len] 物理内存区至调用进程的 [addr, addr + len] 的用户空间虚拟内存区,通常用于内存的共享或者用户空间程序控制硬件设备,函数的返回值为最后文件映射到用户空间的地址,进程可直接操作该地址。这个函数的使用和驱动程序有一定关系,常见的用法如下:
#define HwGPIO_BASE (0xF0102000)
#define MAP_SIZE 4096UL
#define MAP_MASK (MAP_SIZE - 1)
static unsigned int pTestRegBase;
static int dev_fd;
dev_fd = open("/dev/mem", O_RDWR | O_NDELAY);
if( dev_fd < 0) {
LOGE("open(/dev/mem) failed.");
return;
}
pTestRegBase = (void *)mmap(NULL, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, dev_fd, HwGPIO_BASE & ~MAP_MASK);
这里将HwGPIO_BASE开始大小为1个page的物理地址映射到了用户空间,然后可以用pTestRegBase作为起始地址操作。