先说结论:在应用层可以通过操作/dev/mem设备文件,以及mmap函数,将寄存器的地址映射到用户空间,然后直接在应用层对寄存器进行操作。
1、dev/mem 设备文件
该设备文件是物理内存的全映像,通过分析dev/mem设备驱动可以知道,通过这个设备文件可以映射整个处理器的地址空间,而不单单是内存。这里的地址空间指的是处理器总线上的全部可寻址空间。除了内存,还有外设IO空间。也就是说通过/dev/mem可以映射0-0xFFFFFFFF的全部物理地址(这个物理地址是真是有效的,处理器访问这个物理地址能够获取有效数据)。
2、mmap函数
/*
* addr:指定要映射到的虚拟地址,如果写NULL则表示由sys_mmap来分配该虚拟地址
* length:需要映射的长度
* port:映射页的权限
* flags: 标记位
* fd: 句柄,通常为open("/dev/mem/" ,O_RDWR | O_NDELAY);的返回值
* offset:需要映射的物理地址
* 返回值:由物理地址映射得到的虚拟地址
*/
void *mmap(void *addr,size_t length,int prot,int flags,int fd,off_t offset);
3、使用条件
当打开CONFIG_STRICT_DEVMEM时,mem驱动会对mmap要映射的物理地址进行范围和位置检查后才能进行映射。检查条件如下:
1:映射范围不能超过4G
2:该物理地址所在iomem不能exclusive
3:该物理地址不能处在lowmem中
4、代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#define MAP_SIZE 0x200
#define PHY_REG_BASE 0xFFB00000
static int fd;
int main (int argc,char *argv[])
{
fd = open("/dev/mem/",O_RDWR | O_NDELAY);
if(fd < 0)
{
printf("open /dev/mem failed.\n");
return 0;
}
unsigned char *var_reg_base = (unsigned char *)mmap(NULL,MAP_ZIZE,PROT_SREAD|PROT_WRITE,MAP_SHARED,fd,PHY_REG_BASE);
for(int i = 0;i<MAP_SIZE;i = i+4)
{
printf("0x%x = ",(PHY_REG_BASE +i));
printf("0x%x \n",*(volatile unsigned int *)(var_reg_base +i));
}
if(fd)
{
close(fd);
}
munmap(var_reg_base,phy_reg_base);
return 0;
}