首页/目录/全部文章

全部文章

八个专题的源码、算法与协议笔记都在这里。

笔记列表

Bus 驱动架构与源码总览

Bus 驱动架构与源码总览

1. 目录定位

drivers/bus收纳无法自然归入PCI、USB、I2C、SPI等标准目录的总线控制器。这里的“bus”至少有四种含义:

  1. Linux device model中的struct bus_type
  2. SoC内部互连及错误监控器;
  3. 外部并行/串行扩展总线控制器;
  4. 仅负责供电后再枚举子节点的容器设备。

因此不能假设目录中所有驱动共享同一Core或API。

2. 主要分类

类别 代表代码 作用
自定义设备总线 MHI、FSL-MC、RSB、MOXTET、MIPS CDMM 注册bus、device、driver并进行专用匹配
OF容器 simple-pm-bus.c runtime PM并populate子platform device
内部互连 ARM CCI、OMAP L3、Tegra ACONNECT coherency、子模块访问或互连错误
外部存储/扩展 WEIM、EBI2、GMI、MBUS、UniPhier chip-select、timing、地址窗口
错误/QoS GISB、BT1 AXI/APB、DA8xx MSTPRI timeout、错误解码、master优先级
SoC功能域 TI SYSC/PWMSS、Sun50i DE2、QCOM SSC clock/reset/PM后创建内部设备

3. 两种设备模型

多数单文件驱动是platform driver:

1
2
3
4
5
6
DT node
-> platform_device
-> of_match
-> probe
-> clocks/resets/regmap/MMIO
-> of_platform_populate(children)

MHI、FSL-MC等会进一步注册自定义总线:

1
2
3
4
controller/firmware discovery
-> device_register(custom device)
-> bus.match
-> custom driver probe

4. 与系统其它目录边界

  • drivers/base实现通用bus/device/driver Core;
  • drivers/interconnect实现带宽投票框架,不等于本目录互连驱动;
  • drivers/soc/rockchip承载RK3588 PM domain、QoS、system monitor等厂商逻辑;
  • drivers/pci/controller管理RK3588 PCIe Root Complex;
  • AMBA PrimeCell通用总线位于drivers/amba
  • clock/reset/genpd/syscon分别由各自框架管理。

5. 构建结构

顶层Kconfig定义二十余个平台选项,并source:

  • drivers/bus/fsl-mc/Kconfig
  • drivers/bus/mhi/Kconfig

Makefile无统一bus core目标。simple-pm-bus.oCONFIG_OF构建;mhi/目录总是进入递归Makefile,但其中对象仍由CONFIG_MHI_*决定。

6. 生命周期共性

总线控制器probe通常按以下顺序:

1
2
3
4
5
6
map resource
-> enable regulator/clock/power
-> deassert reset
-> program timing/window/error mask
-> register bus/controller
-> enumerate child devices

remove必须逆序,且先阻止新I/O、删除子设备,再关clock/power。错误路径若顺序不完整,容易产生访问断电寄存器、DMA仍运行或子设备悬挂。

7. RK3588结论

本目录没有rockchip-*源文件,RK3588 DTS也没有匹配这里平台专用compatible。该平台的NoC/QoS/PM/PCIe等由其它目录的Rockchip驱动负责。

潜在例外是:

  • simple-pm-bus为通用OF驱动,但只有节点以simple-pm-bus为最具体compatible时才执行PM和child populate;
  • MHI PCI generic理论上可驱动插在RK3588 PCIe上的受支持蜂窝模组,但当前Rockchip配置未启用MHI,且是否匹配取决于PCI ID而非RK3588 DTS。

8. 分析原则

阅读本目录应先回答:

  1. 驱动是否注册真正的bus_type
  2. 还是只作为platform容器;
  3. 是否拥有children的电源/clock;
  4. children来自DT还是固件/硬件枚举;
  5. 错误处理是报告、复位还是重建总线;
  6. 目标平台是否实际启用。

Linux 6.1 Bus 驱动文档索引

Linux 6.1 Bus 驱动文档索引

源码:rk3588/kernel-6.1/drivers/bus/

文档 内容
Bus驱动架构与源码总览.md 目录定位、总线类型和整体分层
源码目录与模块索引.md 65个文件、Kconfig、Makefile及平台归属
01-Simple-PM-Bus与OF子设备枚举.md power-managed container和OF populate
02-Linux自定义Bus-Type与设备模型.md MHI、FSL-MC、RSB、MOXTET、CDMM
03-MHI-Host控制器通道与状态机.md Host MHI、ring、doorbell、PM及PCI glue
04-MHI-Endpoint设备侧实现.md Endpoint MHI、MMIO、ring和channel
05-FSL-MC-DPAA2对象总线.md Management Complex、DPRC、MSI和UAPI
06-外部并行总线与板级扩展.md WEIM、EBI2、GMI、MBUS、System Bus
07-SoC互连错误监控与QoS.md CCI、OMAP L3、GISB、Baikal和DA8xx
08-资源时钟复位PM与子节点生命周期.md probe/remove、runtime PM和populate
09-并发锁中断DMA与错误恢复.md 锁、IRQ、ring、DMA和恢复原则
10-RK3588适用性DTS与配置核对.md 本目录与RK3588实际关系
11-调试故障排查与安全边界.md sysfs/debugfs、总线错误和加固
12-RSB-MOXTET-CDMM专用总线.md 三类自定义bus type与传输模型
13-TI-SYSC模块电源与Idle管理.md TI target module、quirk、PM和恢复

drivers/bus不是统一“Linux总线核心”,而是多个SoC内部互连、外部扩展总线以及MHI/FSL-MC等专用bus type驱动的集合。RK3588没有本目录下的专用Rockchip驱动,绝大多数文件不会在该平台构建或匹配。

源码目录与模块索引

源码目录与模块索引

1. 规模

本目录共65个文件,包含顶层单文件驱动及两个主要子目录:

  • mhi/:Host和Endpoint MHI;
  • fsl-mc/:NXP DPAA2 Management Complex。

2. 顶层驱动

文件 平台/功能
arm-cci.c ARM CCI-400/500/550 cache-coherent interconnect
arm-integrator-lm.c ARM Integrator Logic Module bus
brcmstb_gisb.c Broadcom GISB timeout/abort/error decode
bt1-apb.cbt1-axi.c Baikal-T1总线错误处理
da8xx-mstpri.c TI DA8xx master priority
hisi_lpc.c HiSilicon LPC间接PIO
imx-weim.c i.MX external memory interface
intel-ixp4xx-eb.c IXP4xx expansion bus
mips_cdmm.c MIPS每CPU CDMM bus type
moxtet.c Turris MOX模块SPI配置总线
mvebu-mbus.c Marvell地址解码window
omap_l3_smx.comap_l3_noc.c OMAP L3互连错误
omap-ocp2scp.c OMAP协议桥及子PHY
qcom-ebi2.c Qualcomm外部总线
qcom-ssc-block-bus.c Snapdragon Sensor Core总线初始化
simple-pm-bus.c 通用power-managed OF bus
sun50i-de2.c Allwinner DE2访问域
sunxi-rsb.c Allwinner Reduced Serial Bus
tegra-aconnect.c Tegra APE内部总线
tegra-gmi.c Tegra通用memory interface
ti-pwmss.c TI PWM subsystem容器
ti-sysc.c TI interconnect target module
ts-nbus.c TS-4600 FPGA NBUS
uniphier-system-bus.c UniPhier外部system bus
vexpress-config.c Versatile Express config bus

3. MHI Host

文件 职责
host/init.c bus/controller/device/driver注册与配置解析
host/main.c channel/event/command ring、transfer API和IRQ
host/pm.c M0/M1/M2/M3、EE、SYS_ERR和电源转换
host/boot.c BHI/BHIE固件与RDDM下载
host/debugfs.c controller/channel/event调试
host/pci_generic.c Qualcomm/Quectel/Foxconn/Sierra/Telit等PCI modem glue
host/internal.hmhi/common.h ring、context、状态及寄存器内部定义

构建:

1
2
mhi.ko = init + main + pm + boot [+ debugfs]
mhi_pci_generic.ko = pci_generic

4. MHI Endpoint

文件 职责
ep/main.c endpoint bus、device/driver、channel及IRQ work
ep/mmio.c endpoint寄存器、host context访问
ep/ring.c host-owned ring读取与元素推进
ep/sm.c endpoint MHI状态机
ep/internal.h 私有对象

构建为mhi_ep.ko

5. FSL-MC

文件组 职责
fsl-mc-bus.c bus type、root MC、设备枚举
dprc*.c container命令与DPRC driver
mc-io.cmc-sys.c portal command I/O
obj-api.cdpbp.cdpcon.cdpmcp.c MC对象协议
fsl-mc-allocator.c resource pool
fsl-mc-msi.c MSI domain
fsl-mc-uapi.c userspace portal

6. Kconfig平台限制

绝大多数选项依赖具体ARCH_*,不能仅因ARM64而启用。典型例:

  • TI_SYSC依赖ARCH_OMAP2PLUS
  • TEGRA_*依赖ARCH_TEGRA
  • SUNXI_RSB依赖ARCH_SUNXI
  • QCOM_*依赖ARCH_QCOM
  • FSL_MC_BUS依赖Layerscape;
  • MHI_BUS本身无SoC依赖,但具体controller需PCI或其它transport。

7. 注册方式

  • 普通platform driver:module_platform_driver()
  • 必须早于children的驱动:postcore_initcall_sync()builtin_platform_driver()
  • 自定义总线:bus_register()后再注册controller;
  • MHI/FSL-MC使用postcore_initcall()建立bus type;
  • simple-pm-bus随OF构建但仍按compatible匹配。

8. 不是RK3588驱动索引

文件名中的ARM、AXI、APB、NoC描述的是协议或其它SoC,并不表示RK3588适用。判断依据必须是Kconfig、compatible、PCI ID和最终.config

字符设备注册、CDev 与 Misc 框架

字符设备注册、CDev 与 Misc 框架

1. Dev_t

字符设备由dev_t标识:

1
2
major -> 驱动/分发表
minor -> 实例或子功能

静态major用于兼容ABI;新驱动通常alloc_chrdev_region()动态分配。

2. CDev

标准注册:

1
2
3
4
5
alloc_chrdev_region
-> cdev_init(&cdev, &fops)
-> cdev_add(devt, count)
-> class_create
-> device_create

cdev_add()建立dev_t到cdev的kobject映射。device_create()只建立device model/sysfs和devtmpfs事件,二者不是同一动作。

注销逆序:

1
2
3
4
device_destroy
-> class_destroy
-> cdev_del
-> unregister_chrdev_region

必须先阻止新open,并保证已有fd的私有对象仍存活。

3. Open分发

fs/char_dev.c中的chrdev_open()

  1. 从inode dev_t查找cdev;
  2. 缓存inode->i_cdev
  3. 增加cdev/module引用;
  4. 替换file->f_op
  5. 调用具体driver .open

后续read/write/ioctl直接进入具体fops。

4. register_chrdev

Legacy接口可一次注册整个major。Driver open再按minor分发。mem.c、virtio_console等仍使用该接口。

新多实例driver更适合明确的region+cdev,便于生命周期和sysfs对应。

5. Misc框架

misc.c固定注册major 10并维护misc list。Driver:

1
2
3
4
5
6
struct miscdevice {
int minor;
const char *name;
const struct file_operations *fops;
...
};

调用misc_register()

  • MISC_DYNAMIC_MINOR从bitmap分配;
  • 加入全局list;
  • device_create_with_groups()
  • 默认node名来自namenodename

6. Misc Open

所有misc node先进入misc_open()

  1. 取inode minor;
  2. 在misc list查找;
  3. 请求模块;
  4. file->f_op替换为目标fops;
  5. file->private_data设为miscdevice;
  6. 调目标.open

Driver若覆盖private_data,需理解这个初始值。

7. 并发和引用

注册表由mutex保护,但registry锁不保护driver内部状态。Driver需自己处理:

  • 多open;
  • remove与fd并发;
  • ioctl和read并发;
  • blocking wait;
  • mmap在close后仍存在;
  • module卸载。

.owner = THIS_MODULE只保护模块代码,不自动保护platform私有内存。

8. File Private Data

常见模式:

1
2
3
4
5
6
7
8
9
open:
container_of(inode->i_cdev)
allocate file context
file->private_data = ctx

release:
cancel waits
put device reference
free ctx

每fd状态不要误放到全局device结构中,否则多个进程会互相覆盖offset、mode或pending command。

9. Poll

1
2
3
poll_wait(file, &waitq, table)
-> check readable/writable/error state
-> return EPOLLIN/OUT/ERR/HUP

状态更新后必须先改变受锁保护的条件,再wake_up_interruptible_poll(),避免丢唤醒。

10. Compat IOCTL

64位RK3588运行32位应用时会进入.compat_ioctl。含pointer、long、alignment或可变数组的结构不能直接复用native布局。

Ioctl命令必须验证:

  • magic和number;
  • direction/size;
  • integer range;
  • user pointer;
  • reserved bits;
  • capability和device state。

Mem、Null、Zero、Full 与 Kmsg 设备

Mem、Null、Zero、Full 与 Kmsg 设备

1. Major 1分发表

mem.c注册MEM_MAJOR=1。统一memory_open()按minor从devlist[]选择fops:

Minor Node 行为
1 /dev/mem 物理地址空间
3 /dev/null read EOF,write丢弃
4 /dev/port I/O port,条件构建
5 /dev/zero read零,mmap匿名零页
7 /dev/full read零,write -ENOSPC
8 /dev/random CRNG接口
9 /dev/urandom CRNG接口
11 /dev/kmsg 内核日志

设备由mem_class创建;mode通过devnode callback设置。

2. /dev/null

  • read立即返回0;
  • write返回输入长度;
  • splice/write_iter同样消费数据;
  • poll通常始终可读/写。

它不分配或保存payload。

3. /dev/zero

Read将用户buffer清零;mmap提供零填充匿名内存语义。大read循环中需处理signal和调度,避免长期占用CPU。

Write只丢弃数据,与/dev/null类似。

4. /dev/full

Read行为类似zero;任何write返回-ENOSPC。用于测试应用磁盘满错误路径。

5. /dev/mem

Offset代表物理地址。Read/write先通过架构hook验证区域,再使用xlate_dev_mem_ptr()等映射。

关键限制:

  • CONFIG_DEVMEM决定node是否存在;
  • CONFIG_STRICT_DEVMEM/devmem_is_allowed()限制RAM和敏感区域;
  • architecture可拒绝访问;
  • cache属性必须匹配物理区域;
  • mmap由phys_mem_access_prot()等决定page protection。

CAP_SYS_RAWIO和node权限仍不能使错误映射安全。

6. RK3588 /dev/mem风险

直接写GRF/CRU/PMU/IOC可能:

  • 绕过regmap锁和write-mask;
  • 关闭clock/power;
    -破坏pinmux和电压域;
  • 与driver并发修改;
    -暴露secure/保留内存;
  • 绕过设备所有权。

产品应禁用或严格限制DEVMEM;调试也应优先使用driver/debugfs。

7. /dev/port

只适用于ISA/PCI I/O port架构。ARM64 RK3588通常没有x86式port I/O,DEVPORT依赖ISA或PCI但实际架构支持仍需核对。

它与MMIO /dev/mem不是同一地址空间。

8. /dev/kmsg

kmsg_fops提供:

  • read内核log record;
  • write注入用户消息到printk ring;
  • poll等待新record;
  • llseek支持定位/清晰语义。

读取和写入权限会泄露内核地址、设备信息或允许日志欺骗。dmesg_restrict、LSM和node mode应配合。

9. Init

chr_dev_init()

1
2
3
4
register_chrdev(MEM_MAJOR)
-> class_create("mem")
-> iterate devlist
-> device_create

若某个device_create失败会继续创建其它node,启动日志需检查部分失败。

10. 容器边界

Device namespace不会天然虚拟化/dev/mem/dev/kmsg。将宿主node映射进容器等于扩大宿主攻击面。

内核 Random、CRNG 与用户接口

内核 Random、CRNG 与用户接口

1. 目标

random.c聚合不可信或不同质量的输入,维护cryptographic RNG状态,并向内核和用户空间提供随机字节。它不把某个HWRNG输出原样转交应用。

2. 输入来源

典型输入:

  • interrupt timing;
  • device/input timing;
  • bootloader seed;
  • CPU RNG;
  • hardware generator;
  • architecture/firmware randomness;
  • 用户向random/urandom写入的数据。

数据可以混入pool但不一定获得entropy credit。Credit决定CRNG何时被认为初始化。

3. 初始化阶段

系统早期CRNG可能未ready。代码维护初始化状态和waitqueue:

1
2
3
4
5
6
collect entropy
-> fast pool/input pool mixing
-> threshold reached
-> initialize CRNG key/state
-> wake random waiters
-> notify callbacks

密码、长期密钥和TLS随机数必须等待CRNG ready。

4. /dev/random

Linux 6.1中,CRNG初始化后/dev/random与urandom都基于同一安全生成器;主要差别是random在初始化前阻塞。

Read支持:

  • blocking;
  • O_NONBLOCK
  • signal中断;
  • iter I/O;
  • poll ready。

不要用“每读取一次就消耗固定entropy位”的旧模型解释现代实现。

5. /dev/urandom

初始化前历史上可返回早期输出,因此敏感程序更推荐getrandom(),它能显式等待ready且不依赖device node。

初始化后适合大多数随机需求。

6. getrandom

Flags包括:

  • GRND_NONBLOCK
  • GRND_RANDOM
  • GRND_INSECURE

默认调用在CRNG ready前等待。GRND_INSECURE允许早期输出,只适合明确不要求密码学安全的场景。

7. 内核API

  • get_random_bytes()
  • get_random_u32/u64()
  • get_random_long()
  • get_random_bytes_wait()
  • add_device_randomness()
  • add_hwgenerator_randomness()
  • wait_for_random_bytes()

Driver应使用API,不应自行read /dev/urandom

8. 写入语义

向random/urandom写数据会mix进状态,但普通write不会自动声明这些数据含有可信entropy。只有受控内核路径可credit entropy。

这防止任意用户通过可预测数据欺骗CRNG ready。

9. Reseed

CRNG按时间/生成量及新entropy reseed。Per-CPU batched random减少全局锁竞争,适合非密钥的频繁u32/u64使用。

10. Trust配置

RANDOM_TRUST_CPURANDOM_TRUST_BOOTLOADER控制CPU/boot seed是否被credit,而不是是否mix。

RK3588产品应评估:

  • Bootloader是否每次提供唯一高质量seed;
  • SMCCC/SoC TRNG是否可信;
  • 克隆镜像是否保存并更新random seed;
  • 安全启动链是否保护seed注入。

11. 并发

Random fast path使用per-CPU状态、锁、RCU和waitqueue降低竞争。Entropy输入可来自IRQ,不能在该路径睡眠。

用户read大buffer会分块生成并检查signal/reschedule。

12. 与HWRNG区别

/dev/random/urandom /dev/hwrng
内核CSPRNG输出 当前硬件源原始输出
混合多源、reseed 单一selected hwrng
适合密钥 需自行健康评估
初始化状态明确 可因硬件故障返回错误

应用通常不应直接用/dev/hwrng替代getrandom()

HWRNG Core 注册、选择与熵注入

HWRNG Core 注册、选择与熵注入

1. Core对象

硬件driver填充struct hwrng

  • name
  • init/cleanup
  • read,或data_present/data_read
  • quality
  • list、kref和completion。

通过hwrng_register()devm_hwrng_register()加入Core。

2. /dev/hwrng

Core注册miscdevice:

1
2
3
major 10 / HWRNG_MINOR
node /dev/hwrng
fops rng_chrdev_ops

只允许read open;write返回无效。Read从当前selected RNG取原始数据,并支持O_NONBLOCK

3. 多RNG选择

Core维护rng_listcurrent_rng

  • 默认选择quality最高者;
  • 用户可写rng_current固定选择;
  • 当前RNG注销时自动切到最佳剩余源;
  • 同名RNG禁止重复注册。

Sysfs属性:

1
2
3
4
rng_available
rng_current
rng_selected
rng_quality

具体路径位于hwrng misc device对应sysfs节点。

4. Quality

quality范围0–1024,表示每1024位输入估计可credit的entropy bit数。它不是吞吐率,也不是统计测试分数。

设置过高会让内核过度信任硬件,设置为0则后台输入仍可mix但不credit。

Rockchip driver在本树声明quality=999,这是一项强信任假设,应结合硬件认证和健康检测评估。

5. 后台填充线程

选择current RNG后启动hwrng kthread:

1
2
3
4
rng_get_data(wait=1)
-> bytes * quality计算credit
-> add_hwgenerator_randomness
-> mix到内核pool并按quality credit

读取失败或无数据时使用hwrng_msleep()等待,也能被设备注销的dying completion唤醒。

6. Early Randomness

新RNG注册时,Core可能非阻塞读取32字节并调用add_device_randomness()。这只mix,不按quality直接credit。

7. 并发

  • rng_mutex:list和current选择;
  • reading_mutex:硬件read、共享buffer和data_avail;
  • kref:当前RNG跨read生命周期;
  • cleanup_done:等待最后引用cleanup;
  • dying:中断driver sleep。

Driver unregister会从list移除、切换current、停止fill线程并等待cleanup完成。

8. Driver回调

.read(rng, buf, max, wait)

  • 返回生成字节数;
  • 0表示暂时无数据;
  • 负值表示错误;
  • 不得写超过max;
  • wait=false不应长时间阻塞。

Core串行调用当前RNG read,但driver的probe/PM/error IRQ仍需自行同步。

9. PM

HWRNG Core不管理厂商clock。Driver应在read/init/cleanup或runtime PM中:

  • enable clock/power;
  • 等待ready;
  • 读取并清状态;
  • 停止generator;
  • autosuspend。

10. 故障

硬件timeout不能回退为伪随机0数据。应返回errno,使Core可停止使用或切换其它RNG。

产品还应关注:

  • 连续值检测;
  • stuck-at故障;
  • reset后重复序列;
  • 低温/低压;
  • virtualization伪造;
  • 多源是否真正独立。

RK3588 Rockchip TRNG 驱动

RK3588 Rockchip TRNG 驱动

1. 匹配

hw_random/rockchip-rng.c支持四类硬件:

Compatible 实现
rockchip,cryptov1-rng Crypto V1内嵌TRNG
rockchip,cryptov2-rng Crypto V2 RNG window
rockchip,trngv1 独立TRNG V1
rockchip,rkrng 新RKRNG/DRNG接口

RK3588节点使用rockchip,trngv1

2. DTS

SoC定义:

1
2
3
4
5
6
7
8
rng: rng@fe378000 {
compatible = "rockchip,trngv1";
reg = <0x0 0xfe378000 0x0 0x200>;
interrupts = <GIC_SPI 400 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&scmi_clk SCMI_HCLK_SECURE_NS>;
resets = <&scmi_reset SRST_H_TRNG_NS>;
status = "disabled";
};

rk3588-linux.dtsi和Android include将其设为okay。最终板级是否启用取决于实际include和运行DTB。

驱动当前使用MMIO、clock和polling;DTS IRQ/reset属性没有被此文件显式获取。

3. Probe

1
2
3
4
5
6
7
8
9
rk_rng_probe
-> match SoC data
-> devm_of_iomap
-> adjust legacy Crypto V2 offset if needed
-> devm_clk_bulk_get_all
-> setup hwrng(name="rockchip", quality=999)
-> enable runtime PM/autosuspend 100ms
-> devm_hwrng_register
-> optional hardware init under PM reference

每次read通过runtime PM启用clock,结束后mark last busy并autosuspend。

4. TRNG V1初始化

trng_v1_init()

  • 校验VERSION为0x46bc
  • 检查seeded/generating/reseeding;
  • 必要时poll到仅SEEDED;
  • 清ISTAT;
  • 设置auto reseed count 1000。

源码对某次poll返回值没有用于终止后续初始化,调试seed异常时应关注状态是否实际稳定。

5. 读取

trng_v1_read()

  1. 清旧ISTAT;
  2. 选择256-bit mode;
  3. 发RAND命令;
  4. udelay 10us;
  5. 若未ready,poll最多50ms;
  6. 最多读取32字节RAND0–RAND7;
  7. 清status并写NOP停止。

Core请求超过32字节时,外层rk_rng_read()循环多次生成。

6. 寄存器字节序

rk_rng_read_regs()对每个32-bit结果执行be32_to_cpu()。这表示driver按硬件输出字节序重新排列,再写入用户buffer;跨平台统计时不要直接拿寄存器dump与/dev/hwrng字节串逐字节比较。

7. Runtime PM

  • resume:bulk enable clocks;
  • suspend:bulk disable/unprepare;
  • system sleep:pm_runtime_force_suspend/resume

Read用pm_runtime_get_sync(),失败时put_noidle();正常完成put_sync_autosuspend()

8. 超时

Poll周期100us、总超时50ms。Timeout返回负errno并关闭生成器。若/dev/hwrng卡顿:

  • 查secure clock;
  • 查SCMI reset/firmware;
  • 查TRNG version/status;
  • 查runtime PM;
  • 查安全世界是否占用;
  • 查低频/电源域。

9. 安全评估

quality=999使后台线程几乎按满熵credit。产品应确认:

  • 硬件有在线健康测试;
  • secure firmware正确初始化;
  • reset后不会重复输出;
  • 多核并发由Core reading mutex串行;
  • 故障不会返回全0;
  • bootloader seed和TRNG不会共享可预测状态。

10. 运行验证

1
2
3
4
5
cat /sys/class/misc/hw_random/rng_available
cat /sys/class/misc/hw_random/rng_current
dd if=/dev/hwrng bs=32 count=4 2>/dev/null | hexdump -C
cat /proc/sys/kernel/random/entropy_avail
dmesg | grep -i rng

统计测试只能发现部分明显故障,不能证明密码学安全。

TPM Core、命令设备与 Resource Manager

TPM Core、命令设备与 Resource Manager

1. 分层

1
2
3
4
5
6
Userspace TSS
-> /dev/tpmN or /dev/tpmrmN
-> TPM Core
-> TPM 1.2/2.0 command helpers
-> transport ops
-> physical TPM / fTPM / vTPM

TPM Core不等于可信启动策略;它只提供命令、资源、事件日志和chip生命周期。

2. tpm_chip

struct tpm_chip包含:

  • struct device
  • tpm_class_ops transport;
  • TPM版本/flags;
  • command buffer和超时;
  • ops semaphore;
  • dev_num;
  • cdev与resource-manager cdev;
  • PCR bank和event log;
  • shutdown/work状态。

Transport通过tpmm_chip_alloc()创建并 tpm_chip_register()发布。

3. Device Nodes

  • /dev/tpmN:直通式命令设备;
  • /dev/tpmrmN:TPM 2.0 resource manager;
  • sysfs/securityfs:PCR、caps、event log等。

普通tpmN更接近独占硬件上下文;tpmrmN为每fd维护virtualized handle/session空间。

4. 命令路径

1
2
3
4
5
6
7
8
9
write TPM command
-> validate header/length/tag
-> lock chip ops
-> transmit
-> transport send/recv/status/cancel
-> validate response
-> cache response in file context
read
-> copy response

一个write对应一个command,read取得结果。非法size或命令状态返回errno。

5. File Context

tpm_file_priv保存:

  • response buffer;
  • response length;
  • timeout work;
  • TPM space;
  • chip引用。

每fd上下文避免不同进程命令/响应串线。Release取消work并清理space。

6. Resource Manager

tpmrm-dev.ctpm2-space.c在context switch时:

  • load该fd的transient objects/sessions;
  • 重写virtual handle到physical handle;
    -执行命令;
  • 保存/flush对象;
  • 将response handle映射回virtual值。

它不虚拟化PCR或所有global TPM state,应用仍可能互相影响。

7. TPM 1.2与2.0

  • tpm1-cmd.c:startup、PCR、capability、self-test、random;
  • tpm2-cmd.c:PCR banks、properties、startup、self-test、random;
  • TPM 2.0支持resource manager;
  • timeouts根据命令duration和设备属性计算。

8. Event Log

eventlog/支持OF、EFI和ACPI来源,并解析TPM1/TPM2 measurement records。

Event log是boot measurement记录,不是TPM实时读出的PCR镜像。验证需重新扩展日志并与PCR比较。

9. HWRNG

HW_RANDOM_TPM可将TPM GetRandom注册为hwrng。TPM随机接口通常吞吐低,且会与TPM命令竞争,不应作为高带宽随机源。

10. 并发

TPM物理命令串行化;ops lock防止并发传输。Long command、cancel和timeout work会与remove/suspend竞争。

Shutdown必须:

  • 阻止新command;
  • cancel timeout work;
  • 等当前transmit;
    -注销cdev;
  • 释放transport。

11. 权限

TPM并非“只有root才能安全使用”。Node权限、TSS daemon和resource manager共同决定多用户隔离。

高风险命令包括:

  • hierarchy/owner授权修改;
  • NV define/write;
  • PCR extend;
  • dictionary attack参数;
  • clear/change EPS;
  • firmware vendor command。

应使用policy session和最小设备权限。

12. 可信启动

完整链路还需要:

  • boot ROM/bootloader measurement;
  • event log传递;
  • kernel IMA/EVM;
  • PCR policy;
  • remote attestation;
  • key sealing;
  • 安全更新和anti-rollback。

只看到/dev/tpm0不代表系统已实现可信启动。

TPM 传输驱动与 RK3588 配置

TPM 传输驱动与 RK3588 配置

1. TIS Core

tpm_tis_core.c实现FIFO接口通用逻辑:

  • locality request/release;
  • status与burst count;
  • FIFO send/recv;
  • command ready/go;
  • interrupt或polling;
  • cancel;
  • timeout和quirk。

MMIO、SPI、I2C transport提供寄存器read/write。

2. MMIO TIS

tpm_tis.c支持OF/PNP等TIS FIFO MMIO设备。RK3588若外接I2C/SPI TPM,不使用此路径。

3. SPI

tpm_tis_spi_main.c实现标准SPI PTP framing和wait-state。tpm_tis_spi_cr50.c处理Google Cr50特化。

板级需正确配置:

  • SPI mode/frequency;
  • CS;
  • IRQ;
  • reset/power GPIO;
  • wake和suspend。

4. I2C

本树包括:

  • generic PTP I2C;
  • Cr50 I2C;
  • Atmel;
  • Infineon;
  • Nuvoton;
  • ST33。

这些协议并非完全可互换。Generic TIS I2C不能替代vendor-specific framing。

5. CRB

tpm_crb.c支持ACPI TPM 2.0 Command Response Buffer,主要用于PC/服务器固件平台。依赖ACPI,通常不是RK3588 DT板路径。

6. Virtual/Firmware TPM

  • tpm_vtpm_proxy.c/dev/vtpmx创建userspace后端;
  • Xen/IBM vTPM frontend;
  • tpm_ftpm_tee.c:通过OP-TEE访问secure-world fTPM。

fTPM安全取决于TEE、secure storage、anti-rollback和TA实现,不因运行在secure world自动等同离散TPM。

7. RK3588 Defconfig

三份主要Rockchip defconfig显式启用:

1
2
CONFIG_TCG_TPM=y
CONFIG_TCG_TIS_I2C_INFINEON=y

未显式启用generic TIS I2C、SPI、CRB或fTPM TEE。最终.config仍需检查依赖合并结果。

8. DTS核对

SoC级rk3588s.dtsi没有板载TPM节点。是否存在Infineon I2C TPM取决于具体板级DTS/overlay和硬件BOM。

所以:

  • TPM Core编进内核不代表/dev/tpm0存在;
  • 选中Infineon driver不代表I2C总线上有chip;
  • 必须核对运行DTB和I2C探测日志。

9. Board节点示意

1
2
3
4
5
6
7
8
9
&i2cX {
status = "okay";

tpm@2e {
compatible = "infineon,slb9645tt";
reg = <0x2e>;
/* interrupts/reset/power按芯片binding */
};
};

示意compatible必须以实际芯片和本树driver match表为准。

10. Probe失败

重点检查:

  • I2C address和pull-up;
  • 电源/reset timing;
  • adapter支持的transaction;
  • chip ID;
  • locality;
  • IRQ polarity;
  • polling fallback;
  • clock stretching;
  • secure firmware是否独占I2C。

11. Suspend/Resume

TPM可能参与suspend measurement、sealed key和hibernation。System suspend前Core执行shutdown相关命令;transport恢复后必须保证chip状态和locality有效。

切断TPM电源可能丢失volatile objects和sessions。

12. 运行验证

1
2
3
4
5
zcat /proc/config.gz | grep TCG
ls -l /dev/tpm*
dmesg | grep -i tpm
cat /sys/class/tpm/tpm0/tpm_version_major
ls /sys/kernel/security/tpm0 2>/dev/null

进一步使用tpm2_getcaptpm2_pcrread和event log验证,而不是向device node手工写任意字节。