如何读取设备驱动程序中的寄存器?

how to read a register in device driver?

在 linux 设备驱动程序中,在设备的初始化函数中,我尝试读取地址(这是 arm64 的 SMMUv3 设备),如下所示。

uint8_t *addr1;

addr1 = ioremap(0x09050000, 0x20000); printk("SMMU_AIDR : 0x%X\n", *(addr1 + 0x1c));

但我收到 Internal error: synchronous external abort: 96000010 [#1] SMP 错误。
是否不允许使用 ioremap 将地址映射到虚拟地址并只读取该地址?

我给SMMU IDR[2]寄存器一个固定值0x78789a9a。 (在偏移量 0x8 处,32 位寄存器。这是可能的,因为它是 qemu。) SMMU 从 0x09050000 开始,地址为 space 0x20000.

__iomem uint32_t *addr1 = NULL;

static int __init my_driver_init(void)
{
...
addr1 = ioremap(0x09050000, 0x20000); // smmuv3
printk("SMMU_IDR[2]     : 0x%X\n", readl(addr1 +0x08/4));
..}

这是驱动初始化时的输出。(值读取正常)

[  453.207261] SMMU_IDR[2]     : 0x78789A9A

第一个问题是该地址的访问宽度错误。之前,它被定义为uint8_t *addr1;,我使用printk("SMMU_AIDR : 0x%X\n", *(addr1 + 0x1c))所以它在SMMU模型不允许的时候读取字节。

第二个问题(我认为这不会导致陷阱,因为 arm64 提供内存映射 io)是我对内存映射 IO 寄存器使用内存访问(指针取消引用)。正如人们评论的那样,我应该使用 readl 函数。 (主要是为了使代码可移植。readl 也适用于像 x86_64 这样的 iomap 平台。使用 mmio adderss 作为指针在此类平台上不起作用。后来我发现 readl 函数也解决了内存屏障问题) . 添加:我将变量 addr1 的 volatile 固定为 __iomem。(感谢 @0andriy)