【问题标题】:Write operation on memory mapped IO gives segmentation fault内存映射 IO 上的写操作会导致分段错误
【发布时间】:2018-08-14 05:39:12
【问题描述】:

我通过将其物理基地址映射到用户空间来访问 UART。读操作成功,但写操作给出分段错误。下面是我的代码

#define     READ_REG32(reg)     ( *((volatile int *) (reg)) )
#define     WRITE_REG32(reg,value)     ( *((volatile int *) (reg)) = value )

static int Write_on_uart()  
{  
    void * map_base;  
    FILE *f;  
    int type,fd;  

    fd = open("/dev/mem", O_RDWR | O_SYNC);  
    if (fd) {  
        printf("Success to open /dev/mem fd=%08x\n", fd);  
    }  
    else {  
        printf("Fail to open /dev/mem fd=%08x\n", fd);    
    }  
    map_base = mmap(0, ALLOC_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0x21E8000);

    type = READ_REG32(map_base + UCR1);
    printf("READ_REG32 successful\n");


    printf("Going to WRITE_REG32 register\n");

    WRITE_REG32(map_base + UTXD,'R'); ///Got segementation fault
    printf("WRITE_REG32 successful\n");

    close(fd);  
    munmap(map_base, ALLOC_SIZE);  

    printf("reg32[%08x] = value[%08x] \n", map_base, type);  

    type = (type & ( 1 << 27 )) >> 27 ;  

    printf("reg32[%08x] = value[%08x] \n", map_base, type);  

    return type;  
}  

分段错误如下:

, *pte=00000000, *ppte=00000000
[   50.354260] CPU: 0 PID: 401 Comm: raw_uart_access Not tainted 4.9.84-+gb2a7f2f #4
[   50.381000] Hardware name: Freescale i.MX6 UltraLite (Device Tree)
[   50.397017] task: 9229d140 task.stack: 9271a000
[   50.411233] PC is at 0x1057c
[   50.423459] LR is at 0x10574
[   50.435355] pc : [<0001057c>]    lr : [<00010574>]    psr: 200d0010
[   50.435355] sp : 7e8b4c80  ip : 00000000  fp : 7e8b4c9c
[   50.464647] r10: 76f61fac  r9 : 00000000  r8 : 00000000
[   50.478608] r7 : 00000000  r6 : 00010408  r5 : 00000000  r4 : 00010634
[   50.493738] r3 : ffffffff  r2 : 00000010  r1 : 76f60210  r0 : ffffffff
[   50.508645] Flags: nzCv  IRQs on  FIQs on  Mode USER_32  ISA ARM  Segment user
[   50.532259] Control: 10c5387d  Table: 9297806a  DAC: 00000055
[   50.546485] CPU: 0 PID: 401 Comm: raw_uart_access Not tainted 4.9.84-+gb2a7f2f #4
[   50.570395] Hardware name: Freescale i.MX6 UltraLite (Device Tree)
[   50.585015] Backtrace: 
[   50.595863] [<8010bd3c>] (dump_backtrace) from [<8010c014>] (show_stack+0x18/0x1c)
[   50.620055]  r7:00000017 r6:600d0113 r5:00000000 r4:80c1c9f0
[   50.634156] [<8010bffc>] (show_stack) from [<8042ed84>] (dump_stack+0x90/0xa4)
[   50.657979] [<8042ecf4>] (dump_stack) from [<80108a98>] (show_regs+0x14/0x18)
[   50.673778]  r7:00000017 r6:0000007f r5:0000000b r4:9229d140
[   50.688016] [<80108a84>] (show_regs) from [<801147e0>] (__do_user_fault+0xc4/0xc8)
[   50.712379] [<8011471c>] (__do_user_fault) from [<801149f0>] (do_page_fault+0x20c/0x3a4)
[   50.737755]  r8:0000007f r7:00000017 r6:9267dc40 r5:9229d140 r4:9271bfb0
[   50.753746] [<801147e4>] (do_page_fault) from [<8010134c>] (do_DataAbort+0x44/0xc0)
[   50.779830]  r10:76f61fac r9:00000000 r8:9271bfb0 r7:0000007f r6:801147e4 r5:00000017
[   50.806897]  r4:80c09db4
[   50.819029] [<80101308>] (do_DataAbort) from [<8010cee0>] (__dabt_usr+0x40/0x60)
[   50.845699] Exception stack(0x9271bfb0 to 0x9271bff8)
[   50.860521] bfa0:                                     ffffffff 76f60210 00000010 ffffffff
[   50.887867] bfc0: 00010634 00000000 00010408 00000000 00000000 00000000 76f61fac 7e8b4c9c
[   50.915238] bfe0: 00000000 7e8b4c80 00010574 0001057c 200d0010 ffffffff
[   50.931721]  r8:10c5387d r7:10c5387d r6:ffffffff r5:200d0010 r4:0001057c

谁能给我提示?

【问题讨论】:

  • 尝试检查 MAP_FAILED 上的 mmap,也许它不是内存的 mmap 部分?
  • @NickS:我可以使用相同的 mmap 地址阅读
  • @RahulRDhobi 您正在从一个偏移量 (UCR1) 读取,但写入另一个偏移量 (UTXD),因此地址不完全相同
  • 首先,如果您打印从 UCR1 读取的值,它将对您有所帮助。看看这个值是否有意义。如果您打印ALLOC_SIZEUCR1UTXD 的值也会有所帮助,因为它们不会在任何地方显示。你确定它们在映射的内存块内吗?要检查的另一件事可能是带有void * 指针的算术运算。这是未定义的行为,并且取决于编译器。它应该在 GCC 中工作,但通常我会避免这样做,只是为了安全起见。
  • 当我们在做的时候,你为什么要测试 fd,然后不管结果如何都继续执行程序?如果打开失败,您将面临另一个 SEGFAULT。

标签: c linux linux-kernel mmap memory-mapping


【解决方案1】:

您可能想看看“uio”,这是一个帮助在 linux 中实现用户模式驱动程序的框架。除了与中断同步的常见问题外,它还允许平台代码确保在映射的页表条目中设置正确的访问位。

某些体系结构,如 x86,将物理地址范围的关联数组与属性保持一致,以便总线始终正确实现诸如“设备模式”之类的内容。 ARMv7 不这样做,程序员有责任确保使用正确的总线协议。我怀疑 /dev/mem 的 mmap 会这样做。结果是您的写操作可能会被发布为设备寄存器不支持的总线操作。

像 PAT 这样的“有用”的东西是 X86 不能用于好东西的部分原因;但是 ARM 的成本由程序员承担。

此外,*(volatile int *)x 作为标准几乎毫无意义,但有时可能会起作用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-07-23
    • 1970-01-01
    • 2020-11-04
    • 1970-01-01
    • 2020-03-14
    • 2011-04-22
    • 1970-01-01
    相关资源
    最近更新 更多