【发布时间】:2017-01-17 19:57:30
【问题描述】:
我试图从 linux 内核写入系统控制寄存器。但结果是分段错误:
无法处理虚拟地址 20050004 处的内核分页请求
内核模块代码:
#define REGBASE 0x20050000
void writeRegister(void){
__raw_writel( 0x00000002, REGBASE + 0x0004 );
}
如何访问系统控制寄存器所在的片上内存?
【问题讨论】:
我试图从 linux 内核写入系统控制寄存器。但结果是分段错误:
无法处理虚拟地址 20050004 处的内核分页请求
内核模块代码:
#define REGBASE 0x20050000
void writeRegister(void){
__raw_writel( 0x00000002, REGBASE + 0x0004 );
}
如何访问系统控制寄存器所在的片上内存?
【问题讨论】:
我猜 REGBASE 是物理地址而不是虚拟地址。您需要先请求内核将其映射到地址空间,然后才能使用它。大多数时候你会使用ioremap 来映射它。
例如:
void __iomem *io = ioremap(REGBASE, SZ_4K);
writel(0x00000002, io + 0x0004);
【讨论】:
我知道这并不完全是您正在寻找的答案,但如果您想避免为您的应用程序编写内核模块,那么有一种方法可以在用户空间中做到这一点。
这是 Raspberry Pi3 中 GPIO 访问的示例:
#define RASPBERRY_PI_PERI_BASE 0x3F000000
#define GPIO_BASE (RASPBERRY_PI_PERI_BASE + 0x200000) // GPIO controller
#define BLOCK_SIZE (4*1024)
static volatile uint32_t *gpio = NULL;
int GPIO_init(void) {
int fd;
if ((fd = open ("/dev/mem", O_RDWR | O_SYNC | O_CLOEXEC) ) < 0) return -1; // printf("Failed to open /dev/mem, try checking permissions.\n");
gpio = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, GPIO_BASE);
if ((int32_t)gpio == -1) return -1; // printf("Failed mmap (GPIO): %s\n", strerror (errno));
return 0;
}
现在你有一个简单的指针变量 *gpio 链接到硬件的内存地址。您将“mem”设备映射到内存上,这是“免费”为您存在的 :-)
问候。
【讨论】: