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

问题描述 投票:0回答:1

在Linux设备驱动程序中,在设备的init函数中,我尝试读取一个地址(即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 将地址映射到虚拟地址并仅读取该地址?

linux-kernel linux-device-driver
1个回答
-1
投票

我给 SMMU IDR[2] 寄存器一个固定值 0x78789a9a。 (在偏移量 0x8 处,32 位寄存器。这是可能的,因为它是 qemu。) SMMU 从 0x09050000 开始,地址空间为 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));
..}

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

[  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加法器作为指针在此类平台上不起作用。后来我发现readl函数也解决了内存屏障问题)。 ADD :我将变量 addr1 的 volatile 固定为 __iomem。(感谢@0andriy)

© www.soinside.com 2019 - 2024. All rights reserved.