Skip to the content.

Linux I2C fault injection

1. Introduction

基于 GPIO 的 I2C 总线主驱动器可配置为提供故障注入功能。 然后,它将连接到另一条 I2C 总线,该总线由被测 I2C 总线主驱动器驱动。 GPIO 故障注入驱动程序可以在总线上创建特殊状态,其他 I2C 总线主驱动程序应妥善处理这些状态。

一旦启用了 Kconfig 选项 I2C_GPIO_FAULT_INJECTOR,内核 debugfs 文件系统中就会有一个“i2c-fault-injector”子目录,通常安装在 /sys/kernel/debug。 每个 GPIO 驱动的 I2C 总线都会有一个单独的子目录。 每个子目录将包含触发故障注入的文件。 现在将对其及其预期用例进行描述。

2. Wire states

“scl”

通过读取该文件,您可以获得 SCL 的当前状态。 通过写入,您可以更改其状态以将其强制拉低或再次释放它。 因此,通过使用“echo 0 > scl”,您可以强制 SCL 为低电平,因此无法进行通信,因为被测总线主机将无法计时。 它应该检测 SCL 无响应的情况并向上层报告错误。

“sda”

通过读取该文件,您可以获得SDA的当前状态。 通过写入,您可以更改其状态以将其强制拉低或再次释放它。 因此,通过使用“echo 0 > sda”可以强制 SDA 为低电平,从而无法传输数据。 被测总线主机应检测此情况并使用 Linux I2C 内核的帮助程序(请参阅“struct bus_recovery_info”)触发总线恢复(请参阅 I2C 规范版本 4,第 3.1.16 节)。 但是,总线恢复不会成功,因为 SDA 仍然处于低电平,直到您使用“echo 1 > sda”再次手动释放它。 可以使用“不完全传输”类故障注入器来完成自动释放测试。

3. Incomplete transfers

以下故障注入器会造成 SDA 被设备保持为低电平的情况。 总线恢复应该能够解决这些情况。 但请注意:有些 I2C 客户端设备会检测到其一侧卡住的 SDA,并在几毫秒后自行释放。 此外,可能有外部设备消除尖峰脉冲并监视 I2C 总线。 它还可以检测到卡住的 SDA,并自行启动总线恢复。 如果您想在总线主控驱动程序中实现总线恢复,请确保您之前检查过此类设备的硬件设置。 并且始终使用示波器或逻辑分析仪进行验证!

“incomplete_address_phase”

该文件是只写的,您需要将现有 I2C 客户端设备的地址写入其中。 然后,将开始对该设备进行读传输,但在传输客户端地址后,它将在 ACK 阶段停止。 由于设备将确认其存在,因此这会导致 SDA 在 SCL 为高电平时被设备拉低。 因此,与上面的“sda”文件类似,被测总线主机应该检测到这种情况并尝试总线恢复。 但这一次,它应该会成功,并且设备应该在切换 SCL 后释放 SDA。

“incomplete_write_byte”

与上面类似,该文件是只写的,您需要将现有 I2C 客户端设备的地址写入其中。

注入器将再次停止在一个 ACK 阶段,因此设备将保持 SDA 为低电平,因为它确认了数据。 但是,与“incomplete_address_phase”相比,有两个区别:

a. 发出的消息将是一条写消息

b. 在地址字节之后,将传输 0x00 字节。 然后,停在ACK处。

这是一个非常微妙的状态,当 SCL 上出现进一步的时钟脉冲时,设备被设置为将任何数据写入寄存器 0x00(如果它有寄存器)。 这就是为什么总线恢复(最多 9 个时钟脉冲)必须检查 SDA 或发送额外的 STOP 条件以确保总线已被释放。 否则随机数据将被写入设备!

4. Lost arbitration

在这里,我们要模拟多主设备设置中被测主设备失去对另一个主设备的总线仲裁的情况。

“lose_arbitration”

该文件是只写的,需要写入仲裁干扰的持续时间(以μs为单位,最大为100ms)。 然后调用进程将休眠并等待下一个总线时钟。 不过,该过程是可中断的。

仲裁丢失是通过等待被测主机的 SCL 下降,然后将 SDA 拉低一段时间来实现的。 因此,发出的 I2C 地址应该已损坏,并且应该可以正确检测到。 这意味着发出的地址应该有很多“1”位,以便能够检测损坏。 该地址不需要有设备,因为应该事先检测到仲裁丢失。 另请注意,SCL 下降是使用中断进行监控的,因此中断延迟可能会导致前几位未被损坏。 在空闲总线上使用此故障注入器的一个好的起点是:

# echo 200 > lose_arbitration &
# i2cget -y <bus_to_test> 0x3f

5. Panic during transfer

一旦被测主机开始传输,该故障注入器就会产生内核恐慌。 这通常意味着总线主驱动程序的状态机将被不正常地中断,并且总线可能最终处于异常状态。 使用它来检查您的关闭/重新启动/启动代码是否可以处理这种情况。

“inject_panic”

该文件是只写的,您需要写入检测到的传输开始和引发的内核恐慌之间的延迟(以微秒为单位,最大值为 100 毫秒)。 然后调用进程将休眠并等待下一个总线时钟。 不过,该过程是可中断的。

通过等待被测主机的 SCL 下降来检测传输的开始。 使用此故障注入器的一个好的起点是:

# echo 0 > inject_panic &
# i2cget -y <bus_to_test> <some_address>

请注意,不需要有设备侦听您正在使用的地址。 不过,结果可能会有所不同。