news 2026/10/21 8:41:57

Linux下atsha204a加密芯片驱动源码拆解与避坑指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Linux下atsha204a加密芯片驱动源码拆解与避坑指南

简介:这份资源是面向嵌入式与Linux内核开发者的ATSHA204A加密芯片驱动源码包,聚焦安全认证与数据加密场景,适合需要将SHA-256哈希与AES-128加密能力接入系统的中高级开发者参考。压缩包共12个文件,约32KB,以6个.h头文件与4个.c实现文件为主,分别承担接口定义、I2C通信、命令收发与API封装等职责,另含1个Makefile和1个Kconfig,用于编译规则与内核配置。源码结构清晰,涵盖模块初始化、读写操作、ioctl接口及返回码定义等核心逻辑,可帮助读者理解Linux字符设备驱动如何与硬件安全芯片交互,并作为Android HAL集成的参考起点。目前已有485人学习下载,适合希望深入驱动开发、硬件抽象层设计及加密芯片应用的读者研读与移植。

1. 从一颗加密芯片说起:atsha204a 在 Linux 下到底怎么跑起来

如果你手里有一块带 atsha204a 的板子,插上 Linux 系统后i2cdetect能看到地址,但/dev下什么都没有,那这篇笔记就是写给你的。atsha204a 是一颗常见的加密认证芯片,走 I2C 或单总线,主要用来做设备身份认证、密钥存储和随机数生成。Linux 内核里其实有它的驱动,但很多人拿到源码后卡在设备树配置和 hwmon 接口对接上。我这次拆的是一份 atsha204a 的 Linux 驱动源码,结构不复杂,但细节不少。适合谁看?做嵌入式安全、IoT 设备认证、或者单纯想给板子加一颗加密芯片的开发者。下面从目录结构开始,一路讲到怎么改、怎么验证。

2. 驱动源码结构拆解:从 Makefile 到 i2c_driver 注册

2.1 目录布局与编译入口

拿到源码包,第一件事不是看.c文件,而是看Makefile和Kconfig。这份 atsha204a 驱动通常放在drivers/crypto/或者drivers/hwmon/下,具体取决于它暴露的接口。我手上这份是放在drivers/crypto/atsha204a/里,目录结构大致如下:

atsha204a/ ├── Makefile ├── Kconfig ├── atsha204a-core.c ├── atsha204a-i2c.c ├── atsha204a.h └── atsha204a-common.c

Makefile里一般就一行obj-$(CONFIG_ATSHA204A) += atsha204a.o,然后atsha204a-objs := atsha204a-core.o atsha204a-i2c.o atsha204a-common.o。这里有个坑:如果你只编译atsha204a-i2c.c,会报一堆未定义符号,因为核心逻辑在core里。Kconfig里定义config ATSHA204A,依赖I2C和CRC8,有些版本还依赖HW_RANDOM。编译前先确认内核配置里CONFIG_CRC8是y,否则链接阶段会翻车。

2.2 i2c_driver 注册与设备树匹配

核心注册逻辑在atsha204a-i2c.c里,典型写法如下:

static const struct i2c_device_id atsha204a_id[] = { { "atsha204a", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, atsha204a_id); static const struct of_device_id atsha204a_of_match[] = { { .compatible = "atmel,atsha204a" }, { } }; MODULE_DEVICE_TABLE(of, atsha204a_of_match); static struct i2c_driver atsha204a_driver = { .driver = { .name = "atsha204a", .of_match_table = atsha204a_of_match, }, .probe = atsha204a_probe, .remove = atsha204a_remove, .id_table = atsha204a_id, }; module_i2c_driver(atsha204a_driver);

这段代码做了三件事:定义 I2C 设备 ID 表、定义设备树匹配表、注册i2c_driver。module_i2c_driver宏把init和exit都包了,省事。注意compatible字符串必须和你的设备树里写的一致,常见的是"atmel,atsha204a",但有些板子用"atmel,atsha204",差一个字母就匹配不上。probe函数里一般会做devm_kzalloc、i2c_set_clientdata、初始化crc8表、然后注册hwmon或者crypto设备。如果你发现probe根本没进,先查compatible和 I2C 地址。

2.3 设备树节点与 I2C 地址配置

设备树里要加一个节点,挂在对应的 I2C 控制器下:

&i2c1 { status = "okay"; clock-frequency = <100000>; atsha204a: atsha204a@64 { compatible = "atmel,atsha204a"; reg = <0x64>; wakeup-gpios = <&gpio1 12 GPIO_ACTIVE_HIGH>; }; };

reg是 I2C 从地址,atsha204a 默认是0x64,但有些封装是0xC8右移一位,写0x64就对了。wakeup-gpios是可选的,如果芯片需要唤醒引脚,驱动里会devm_gpiod_get拿这个 GPIO。clock-frequency建议先设100000,atsha204a 支持 400k,但长走线容易出玄学问题,降速能解决大部分通信失败。设备树改完记得make dtbs并更新到板子上,别只编译内核模块。

3. 核心通信流程:I2C 读写、CRC 校验与命令封装

3.1 底层 I2C 传输函数

atsha204a 的通信协议是固定长度的包,发命令和收响应都走 I2C。驱动里一般封装一个atsha204a_i2c_xfer:

static int atsha204a_i2c_xfer(struct atsha204a *atsha, u8 *tx, u8 *rx, size_t len) { struct i2c_client *client = atsha->client; struct i2c_msg msg[2]; int ret; msg[0].addr = client->addr; msg[0].flags = 0; msg[0].len = len; msg[0].buf = tx; msg[1].addr = client->addr; msg[1].flags = I2C_M_RD; msg[1].len = len; msg[1].buf = rx; ret = i2c_transfer(client->adapter, msg, 2); if (ret < 0) { dev_err(&client->dev, "i2c transfer failed: %d\n", ret); return ret; } return 0; }

这里用i2c_transfer而不是i2c_master_send,因为 atsha204a 需要先写命令再读响应,中间不能有 stop。msg[0]发命令,msg[1]读响应,len通常是 4 字节命令包或 32 字节响应包。注意client->addr是 7 位地址,内核会自动处理读写位。如果返回-EREMOTEIO,多半是芯片没应答,查供电和上拉电阻。

3.2 CRC8 校验与命令包组装

atsha204a 的响应包最后一位是 CRC8 校验,驱动里要算:

static u8 atsha204a_crc8(const u8 *data, size_t len) { u8 crc = 0; size_t i; int j; for (i = 0; i < len; i++) { crc ^= data[i]; for (j = 0; j < 8; j++) { if (crc & 0x01) crc = (crc >> 1) ^ 0x8C; else crc >>= 1; } } return crc; }

多项式是0x8C,初值0,不反转。算完和响应最后一位比对,不匹配就丢包重试。命令包组装一般长这样:

static int atsha204a_send_cmd(struct atsha204a *atsha, u8 opcode, u8 param1, u8 param2, u8 *data, size_t len) { u8 tx[4 + len]; u8 rx[32]; int ret; tx[0] = 0x03; /* 命令包长度 */ tx[1] = opcode; tx[2] = param1; tx[3] = param2; memcpy(&tx[4], data, len); ret = atsha204a_i2c_xfer(atsha, tx, rx, sizeof(tx)); if (ret) return ret; if (atsha204a_crc8(rx, 31) != rx[31]) { dev_err(&atsha->client->dev, "crc mismatch\n"); return -EIO; } memcpy(data, rx, len); return 0; }

opcode常见的有0x02(随机数)、0x10(读配置区)、0x12(读数据区)。param1和param2看具体命令。tx[0]是包长度,固定0x03表示后面 3 字节。响应固定 32 字节,最后一位 CRC。这里有个血泪经验:i2c_transfer的len别写错,写 4 发 4 读 4,芯片会直接不理你。

3.3 随机数与认证命令的调用链

随机数命令最简单,用来验证通信是否正常:

int atsha204a_get_random(struct atsha204a *atsha, u8 *rnd) { u8 data[32]; int ret; ret = atsha204a_send_cmd(atsha, 0x02, 0x00, 0x00, NULL, 0); if (ret) return ret; memcpy(rnd, data, 32); return 0; }

认证命令复杂一些,需要先读芯片序列号,再算 MAC。驱动里一般暴露一个sysfs节点或者hwmon属性,用户态通过echo触发。调用链是:用户态写sysfs→store函数 →atsha204a_send_cmd→i2c_transfer。如果你要集成到自己的认证流程,直接调atsha204a_get_random和atsha204a_send_cmd就行,不用走sysfs。

4. 避坑与排查:设备树、地址、CRC 和权限的常见翻车点

4.1 设备树匹配不上,probe 不执行

现象:dmesg里没有任何atsha204a相关日志,/sys/bus/i2c/devices/下也没有0-0064。原因:compatible字符串和驱动里的of_device_id不一致,或者 I2C 控制器status不是okay。解决:先cat /proc/device-tree/i2c1/atsha204a@64/compatible看实际值,再和驱动源码比对。如果设备树里没节点,手动echo atsha204a 0x64 > /sys/bus/i2c/devices/i2c-1/new_device也能临时绑定。

4.2 I2C 地址写错,通信返回 -EREMOTEIO

现象:probe进了,但i2c_transfer返回-EREMOTEIO。原因:reg写成了0xC8或者0x32。atsha204a 的 7 位地址是0x64,有些资料写 8 位地址0xC8,内核要的是 7 位。解决:i2cdetect -y 1确认芯片在0x64出现,设备树里改成0x64。如果i2cdetect也看不到,查供电和上拉,atsha204a 工作电压 2.0V 到 5.5V,别接错。

4.3 CRC 校验失败,随机数读出来全是 0xFF

现象:atsha204a_get_random返回成功,但rnd全是0xFF。原因:I2C 读时序不对,i2c_transfer的msg[1].len写成了4而不是32,或者msg[0]和msg[1]之间加了 stop。解决:确认len是 32,i2c_transfer返回 2 表示两个消息都成功。如果还是0xFF,用逻辑分析仪抓波形,看芯片有没有拉低 SDA 应答。

4.4 sysfs 节点权限不对,用户态写不进去

现象:echo 1 > /sys/class/hwmon/hwmon0/random报Permission denied。原因:sysfs属性默认0644,但有些驱动写成0444只读。解决:在probe里用sysfs_attr_init和device_create_file时指定S_IWUSR | S_IRUGO。或者直接用chmod临时改,但重启就没了。更稳的做法是写一个ioctl接口,别依赖sysfs。

4.5 内核版本不匹配,编译报 implicit declaration

现象:在 5.10 内核上编译 4.19 的驱动,报implicit declaration of function ‘devm_gpiod_get_optional’。原因:GPIO 描述符 API 在 4.19 之后有变动,devm_gpiod_get_optional的第三个参数类型变了。解决:看内核include/linux/gpio/consumer.h里的原型,把GPIOD_OUT_HIGH改成GPIOD_OUT_HIGH或者GPIOD_ASIS。如果差异太大,直接改驱动里的 GPIO 获取方式,用of_get_named_gpio加gpio_request也能跑。

5. 二次开发与验证:从 sysfs 接口到自定义认证流程

5.1 暴露一个干净的 sysfs 接口

驱动默认可能只暴露hwmon的random属性,但你要做认证,最好自己加一个sysfs节点。在probe里加:

static ssize_t auth_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct atsha204a *atsha = dev_get_drvdata(dev); u8 challenge[32]; u8 response[32]; int ret; if (count < 32) return -EINVAL; memcpy(challenge, buf, 32); ret = atsha204a_send_cmd(atsha, 0x14, 0x00, 0x00, challenge, 32); if (ret) return ret; memcpy(response, challenge, 32); dev_info(dev, "auth response: %*phN\n", 32, response); return count; } static DEVICE_ATTR_WO(auth);

然后在probe末尾device_create_file(dev, &dev_attr_auth)。用户态echo -n "32字节挑战" > /sys/.../auth就能触发认证。注意DEVICE_ATTR_WO只写,读会报错。0x14是MAC命令的 opcode,具体看数据手册。

5.2 用 hwmon 接口做快速验证

如果你不想改驱动,直接用hwmon也能验证。加载模块后:

modprobe atsha204a ls /sys/class/hwmon/ cat /sys/class/hwmon/hwmon0/name cat /sys/class/hwmon/hwmon0/random

random属性读出来是 32 字节的十六进制字符串。如果name是atsha204a,说明驱动绑定成功。random每次读都不同,说明随机数命令正常。这个接口适合产线快速测试,不用写额外代码。

5.3 自定义认证流程的改造点

要做设备认证,一般流程是:主机发挑战 → 芯片算 MAC → 主机验证。改造点有三个:第一,把atsha204a_send_cmd的opcode改成0x14,param1设0x00表示TempKey来源;第二,挑战数据要 32 字节,不足补零;第三,响应里的 MAC 要存下来和预期比对。我一般会在驱动里加一个miscdevice,用ioctl传挑战和响应,比sysfs灵活。ioctl命令号用_IOWR('A', 0x01, struct atsha204a_auth),结构体里放challenge[32]和response[32]。

5.4 验证方法与调试技巧

验证分三步:先i2cdetect确认地址,再dmesg | grep atsha204a看probe日志,最后读random看数据。如果random读出来不变,检查atsha204a_send_cmd里rx有没有被覆盖。调试时打开CONFIG_DYNAMIC_DEBUG,在i2c_transfer前后加dev_dbg,用echo 'file atsha204a-i2c.c +p' > /sys/kernel/debug/dynamic_debug/control动态开日志。别用printk,会把串口刷爆。

5.5 一个容易忽略的时序问题

atsha204a 在发命令后需要tWHI等待时间,典型值 4ms。如果i2c_transfer返回太快,芯片还没准备好,读出来就是0xFF。解决:在atsha204a_send_cmd里加usleep_range(4000, 5000),或者用wakeup-gpios拉低再拉高。我一开始没加,随机数读十次错三次,加了延时后一次不挂。从那以后我每次调 I2C 加密芯片都强制走一遍i2cdetect+random读 + 逻辑分析仪抓波形,三步缺一不可。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/21 8:41:23

PMSM脉冲注入初始位置检测:C代码实现与高精度调试解析

带一套伺服驱动器做整机调试时&#xff0c;最让人心里没底的往往不是电流环PI参数&#xff0c;而是上电那一瞬间。电机还停在那里&#xff0c;控制器却不知道转子朝哪个方向&#xff0c;如果直接切闭环&#xff0c;轻则电流环发出一阵抖动&#xff0c;重则电机朝着预估错误的方…

作者头像 李华
网站建设 2026/10/21 8:41:03

SAP学习笔记系统整理:模块地图、ABAP程序与事务代码速查

简介&#xff1a;一份面向 SAP 系统学习者与初中级业务顾问的原创实务笔记&#xff0c;聚焦归档数据查看、后台作业监控、物料账与会计账开启、物料主数据计量单位配置、公司代码与 PLANT 归属查询等高频操作问题。内容以问答形式还原真实工作场景&#xff0c;涵盖 SD_VBAK、RV…

作者头像 李华
网站建设 2026/10/21 8:40:42

从燃烧三要素到灭火器实操:消防安全手册的工程化拆解

简介&#xff1a;面向社会公众、企业员工及社区安全员的消防安全知识宣传手册&#xff0c;围绕火灾预防与应急处置展开。内容从火灾概念入手&#xff0c;条理分明地梳理了一般、重大、特大火灾的划分标准&#xff0c;以及按燃烧物质划分的A、B、C、D类和带电火灾类型&#xff0…

作者头像 李华
网站建设 2026/10/21 8:39:43

Eclipse SVN插件site-1.8.22兼容安装指南

简介&#xff1a;本资源为面向Java开发者的Eclipse/MyEclipse IDE专用SVN版本控制插件集成包&#xff08;Subclipse 1.8.22&#xff09;&#xff0c;专为需在本地IDE中无缝对接Subversion服务器的中初级开发者设计&#xff0c;解决脱离命令行、高效执行提交、更新、比对、冲突解…

作者头像 李华
网站建设 2026/10/21 8:39:18

灵感回路:AI时代独立开发者的想法验证与产品发布指南

AI时代最不缺的就是灵感。真正让独立开发者焦虑的是&#xff1a;每天醒来脑子里都有三五个“能做”的想法&#xff0c;收藏夹里躺着几十个链接&#xff0c;GitHub Star 了无数项目&#xff0c;但半年过去&#xff0c;一个能上线赚钱的产品都没有。如果你也有这种感觉&#xff0…

作者头像 李华