Операция записи в отображенный в память ввод-вывод дает ошибку сегментации
Я получаю доступ к 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
Кто-нибудь может дать мне подсказку?
1 ответ
Возможно, вы захотите взглянуть на 'uio', который является платформой для помощи в реализации драйверов пользовательского режима в Linux. Помимо обычной задачи синхронизации с прерываниями, он также позволяет коду платформы гарантировать, что правильные биты доступа установлены в записях таблицы страниц для отображений.
Некоторые архитектуры, такие как x86, сохраняют ассоциативный массив диапазонов физических адресов для атрибутов, так что такие вещи, как "режим устройства", всегда должным образом реализуются шиной. ARMv7 не делает этого, ответственность за обеспечение правильного протокола шины лежит на программистах. Я сомневаюсь, что mmap из /dev/mem делает это. В результате ваша операция записи может быть опубликована как операция по шине, которую не поддерживает регистры устройства.
"Полезные" вещи, такие как PAT, являются частью причины, по которой X86 нельзя использовать в хороших вещах; однако стоимость ARM несут программисты.
Кроме того, *(volatile int *)x почти бессмысленен как стандарт, который сделал это так, но иногда может случиться так, что он сработает.