сбой доступа к несогласованному адресу на драйверах Linux wifi на платформе arc
Я получаю сбой на insmod драйверов WIFI Marvell pcie.
я использую беспроводной драйверы на Arch=дугу ОС=Linux и обратным порядком байтов.
аварии проследить, говорит невыровненному адресу, ведущих к краху.
Я провел небольшое расследование и нашел место аварии, ниже приведен фрагмент кода.
case NullPktPeriod_i:
/** keep alive null data pkt interval in full power mode */
psnmp_mib->oid = wlan_cpu_to_le16((t_u16)NullPktPeriod_i);
if (cmd_action == HostCmd_ACT_GEN_SET) {
psnmp_mib->query_type =
wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
psnmp_mib->buf_size = wlan_cpu_to_le16(sizeof(t_u32));
ul_temp = *((t_u32 *)pdata_buf);
*((t_u32 *)(psnmp_mib->value)) =
wlan_cpu_to_le32((t_u32)ul_temp);
cmd->size += sizeof(t_u32);
}
break;
Crash находится в строке *((t_u32 *)(psnmp_mib->value)) = wlan_cpu_to_le32((t_u32)ul_temp);, потому что psnmp_mib->value является беззнаковым символом и типизирован в unsigned long int. Но значение, которое мы присваиваем из pdata_buf, составляет только 1 байт ul_temp = *((t_u32 *)pdata_buf);.
Странное поведение, если я инициализируйте ul_temp (unsigned long int variable) до нуля (любое значение), и если я запущу, аварии не будет видно. но таймаут команды PCI происходит для получения команды get_hardware_spec, и ядро зависает.
Я понятия не имею, как решить эту проблему. Пожалуйста, предоставьте некоторые материалы для дальнейшего продвижения.
Удар - это мои журналы аварий,
[ 29.920000] Path: (null)
[ 29.930000] CPU: 0 PID: 1047 Comm: kworker/u3:1 Tainted: P O 3.12.0 #103
[ 29.930000] Workqueue: MOAL_WORK_QUEUE woal_main_work_queue [pcie8xxx]
[ 29.940000] task: 9f0e02c0 ti: 9d192000 task.ti: 9d192000
[ 29.940000]
[ECR ]: 0x00230400 => Misaligned r/w from 0x9d451072
[ 29.950000] [EFA ]: 0x9d451072
[ 29.950000] [BLINK ]: wlan_prepare_cmd+0x1be/0x478 [mlan]
[ 29.950000] [ERET ]: wlan_ops_sta_prepare_cmd+0x1fe0/0x37dc [mlan]
[ 29.950000] [STAT32]: 0x00000a06 : E2 E1
[ 29.970000] BTA: 0x78571ccc SP: 0x9d193c34 FP: 0x00000000
[ 29.980000] LPS: 0x982de26c LPE: 0x982de270 LPC: 0x00000000
[ 29.980000] r00: 0x00000000 r01: 0x00000016 r02: 0x00000012
r03: 0x0000001e r04: 0x00000000 r05: 0x9d193cb4
r06: 0x9d451064 r07: 0x7857129c r08: 0xfffffffe
r09: 0x00000000 r10: 0x000004cf r11: 0x00000002
r12: 0x00000000
[ 29.990000]
[ 29.990000] Stack Trace:
Пожалуйста, помогите.
1 ответ:
Просто. Просто делайте правильные вещи . В общем случае, можно было бы использовать
memcpy:t_u32 value = wlan_cpu_to_le32((t_u32)ul_temp); memcpy(psnmp_mib->value, &value, sizeof (t_u32));Как указывает 0andriy , здесь можно использовать
put_unaligned:put_unaligned(wlan_cpu_to_le32((t_u32)ul_temp), (t_u32*)psnmp_mib->value);Однако это очень тревожно, потому что стандарт C действительно утверждает, что поведение неопределенно, когда :
Преобразование между двумя типами указателей приводит к неверно выровненному результату(6.3.2.3).
Таким образом, даже простое присутствие актерского состава
(t_u32*)может ли привести к тому, что компилятор "поймет", что указательpsnmp_mib->valueв любом случае выровнен по требованию выравниванияt_u32.
Не выровненный доступ-или даже приведение указателей к не выровненным структурам - имеет неопределенное поведение даже на платформах, которые "предположительно" допускают не выровненный доступ "везде".
Comments