我试图通过将硬件映射到用户空间来访问硬件registers of an A20 SOM。在这种情况下,target是PIO,列在物理地址0x01C20800
。
正在使用官方的Olimex Debian7(wheezy)图像。内核Linux a20-olimex 3.4.90+
我能够通过在所述内存空间上使用devmem2 tool和Allwinner的文档来验证位置(使用devmem切换pinmode和level)。
另一方面,调用mmap
*map = mmap(
NULL,
BLOCK_SIZE, // = (4 * 1024)
PROT_READ | PROT_WRITE,
MAP_SHARED,
*mem_fd,
*addr_p
);
以mmap error: Invalid argument
以下是代码的更完整版本:http://pastebin.com/mfEuVdbJ
不要担心指针,因为在0x01C28000
访问UART0时,相同的代码可以正常工作。
虽然只有UART0(和UART4),它用作串行控制台。
我已经反编译了script.bin(尽管DTB仍在使用)但没有成功,因为那里启用了UART 0,7和8。
我也以root用户身份登录
我仍然会猜到与权限相关的内容,但我现在很丢失,因为devmem完全没有问题
> root@a20-olimex:~# devmem2 0x01c20800 w /dev/mem opened. Memory mapped
> at address 0xb6f85000.
答案 0 :(得分:0)
如果你阅读了友好的手册
EINVAL Invalid argument (POSIX.1)
是错误代码。 (不是EPERM!)。所以我们查找具体的功能
EINVAL We don't like addr, length, or offset (e.g., they are too large,
or not aligned on a page boundary).
BLOCK_SIZE, // 1024
- ?
您需要sysconf(_SC_PAGE_SIZE)
的倍数。在实践中它将是4096.我不会打扰完全通用的数学来计算它 - 如果你需要它你会找到例子。
答案 1 :(得分:0)
虽然sourcejedi并没有解决我的问题,但他给了我正确的方法。 我看了前面提到的devmem tool's source,发现mmap呼叫的地址被掩盖了
address & ~MAP_MASK
获取整个页面,这与我的评论中的操作基本相同。
但是,要在映射完成后返回正确的位置,您必须重新添加掩码
<强> final_address = mapped_address + (target_address & MAP_MASK);
强>
这导致以下代码(基于OP's pastebin)
其中
MAP_MASK = (sysconf(_SC_PAGE_SIZE) - 1)
在这种情况下 4095
int map_peripheral(unsigned long *addr_p, int *mem_fd, void **map, volatile unsigned int **addr)
{
if (!(*addr_p)) {
printf("Called map_peripheral with uninitilized struct.\n");
return -1;
}
// Open /dev/mem
if ((*mem_fd = open("/dev/mem", O_RDWR | O_SYNC)) < 0) {
printf("Failed to open /dev/mem, try checking permissions.\n");
return -1;
}
*map = mmap(
NULL,
MAP_SIZE,
PROT_READ | PROT_WRITE,
MAP_SHARED,
*mem_fd, // file descriptor to physical memory virtual file '/dev/mem'
*addr_p & ~MAP_MASK // address in physical map to be exposed
/************* magic is here **************************************/
);
if (*map == MAP_FAILED) {
perror("mmap error");
return -1;
}
*addr = (volatile unsigned int *)(*map + (*addr_p & MAP_MASK));
/************* and here ******************************************/
return 0;
}