如何读取设备驱动程序中的寄存器?
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)
在 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)