全志的SOC,只要不是太老旧的芯片,里面都集成了2048bit的EFUSE,但此熔丝位的很多细节,并没有相关描述文档,这导致大家很难在实际项目中应用此功能,而且也缺乏灵活的烧写工具,基于此问题,我花了点时间扩展了下XFEL工具。
扩展的命令如下:
usage:
xfel extra efuse dump - Dump all of the efuse information
xfel extra efuse read32 <offset> - Read 32-bits value from efuse
xfel extra efuse write32 <offset> <value> - Write 32-bits value to efuse
xfel extra efuse write <offset> <file> - Write file to efuse
执行dump指令,显示如下信息:
xfel extra efuse dump
chipid:(0x0000 128-bits)
93406000 0c004814 01426250 48671b4b
brom-conf-try:(0x0010 32-bits)
00000000
thermal-sensor:(0x0014 64-bits)
88fbc11a 01e9080f
ft-zone:(0x001c 128-bits)
898f1919 0f760f6c 3108126c 811a0a0e
tvout:(0x002c 32-bits)
0000028f
tvout-gamma:(0x0030 64-bits)
00000000 00000000
oem-program:(0x0038 64-bits)
00000000 00000000
write-protect:(0x0040 32-bits)
00000000
read-protect:(0x0044 32-bits)
00000000
reserved1:(0x0048 64-bits)
00000000 00000000
huk:(0x0050 192-bits)
00000000 00000000 00000000 00000000 00000000 00000000
reserved2:(0x0068 64-bits)
00000000 00000000
rotpk:(0x0070 256-bits)
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
ssk:(0x0090 256-bits)
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
rssk:(0x00b0 128-bits)
00000000 00000000 00000000 00000000
hdcp-hash:(0x00c0 128-bits)
00000000 00000000 00000000 00000000
nv1:(0x00d0 32-bits)
00000000
nv2:(0x00d4 32-bits)
00000000
reserved3:(0x00d8 96-bits)
00000000 00000000 00000000
oem-program-secure:(0x00e4 224-bits)
00000000 00000000 00000000 00000000 00000000 00000000 00000000
可以通过write32 或者write指令来烧写熔丝。
全志加密引导功能可以通过烧写熔丝来启用,当然你也可以烧写自己的序列号,或者mac地址之类的,当然这个efuse还可以用来做防盗版,来实现一机一固件,简要说明下,就是在efuse里烧录本机固件的签名文件,而这个签名文件又是跟cpu序列号关联,可以采用ECDSA256签名算法,签名大小为512bit,64字节,比RSA的签名要小很多,而且强度够。
离线
efuse分配信息如下:
static const struct sid_section_t {
char * name;
uint32_t offset;
uint32_t size_bits;
} sids[] = {
{ "chipid", 0x0000, 128 },
{ "brom-conf-try", 0x0010, 32 },
{ "thermal-sensor", 0x0014, 64 },
{ "ft-zone", 0x001c, 128 },
{ "tvout", 0x002c, 32 },
{ "tvout-gamma", 0x0030, 64 },
{ "oem-program", 0x0038, 64 },
{ "write-protect", 0x0040, 32 },
{ "read-protect", 0x0044, 32 },
{ "reserved1", 0x0048, 64 },
{ "huk", 0x0050, 192 },
{ "reserved2", 0x0068, 64 },
{ "rotpk", 0x0070, 256 },
{ "ssk", 0x0090, 256 },
{ "rssk", 0x00b0, 128 },
{ "hdcp-hash", 0x00c0, 128 },
{ "nv1", 0x00d0, 32 },
{ "nv2", 0x00d4, 32 },
{ "reserved3", 0x00d8, 96 },
{ "oem-program-secure", 0x00e4, 224 },
};
这是根据全志SDK总结而来。
离线
EFUSE写操作仅能由0 到 1,所以只要是保持0状态的bit,都是可以写入的,当你都搞成1了,就无力回天了,没办法变成0。熔丝熔断了,是个不可逆的物理过程。
离线
现在XFEL支持了D1 / D1s / F133芯片的EFUSE读写操作
1,dump efuse
$ xfel extra efuse dump
chipid:(0x0000 128-bits)
93005c00 ac004814 01425a4c 1c5318cb
brom-conf-try:(0x0010 32-bits)
00000000
thermal-sensor:(0x0014 64-bits)
7906c10a 019db011
ft-zone:(0x001c 128-bits)
83883119 0ef00f02 2b06111c 87180a0b
tvout:(0x002c 32-bits)
00000285
tvout-gamma:(0x0030 64-bits)
00000000 00000000
oem-program:(0x0038 64-bits)
00000000 00000000
write-protect:(0x0040 32-bits)
00000000
read-protect:(0x0044 32-bits)
00000000
reserved1:(0x0048 64-bits)
00000000 00000000
huk:(0x0050 192-bits)
00000000 00000000 00000000 00000000 00000000 00000000
reserved2:(0x0068 64-bits)
00000000 00000000
rotpk:(0x0070 256-bits)
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
ssk:(0x0090 256-bits)
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
rssk:(0x00b0 128-bits)
00000000 00000000 00000000 00000000
hdcp-hash:(0x00c0 128-bits)
00000000 00000000 00000000 00000000
nv1:(0x00d0 32-bits)
00000000
nv2:(0x00d4 32-bits)
00000000
reserved3:(0x00d8 96-bits)
00000000 00000000 00000000
oem-program-secure:(0x00e4 224-bits)
00000000 00000000 00000000 00000000 00000000 00000000 00000000
2, write oem-program 1
$ xfel extra efuse write32 0x0038 0x11223344
$ xfel extra efuse dump
chipid:(0x0000 128-bits)
93005c00 ac004814 01425a4c 1c5318cb
brom-conf-try:(0x0010 32-bits)
00000000
thermal-sensor:(0x0014 64-bits)
7906c10a 019db011
ft-zone:(0x001c 128-bits)
83883119 0ef00f02 2b06111c 87180a0b
tvout:(0x002c 32-bits)
00000285
tvout-gamma:(0x0030 64-bits)
00000000 00000000
oem-program:(0x0038 64-bits)
11223344 00000000
write-protect:(0x0040 32-bits)
00000000
read-protect:(0x0044 32-bits)
00000000
reserved1:(0x0048 64-bits)
00000000 00000000
huk:(0x0050 192-bits)
00000000 00000000 00000000 00000000 00000000 00000000
reserved2:(0x0068 64-bits)
00000000 00000000
rotpk:(0x0070 256-bits)
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
ssk:(0x0090 256-bits)
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
rssk:(0x00b0 128-bits)
00000000 00000000 00000000 00000000
hdcp-hash:(0x00c0 128-bits)
00000000 00000000 00000000 00000000
nv1:(0x00d0 32-bits)
00000000
nv2:(0x00d4 32-bits)
00000000
reserved3:(0x00d8 96-bits)
00000000 00000000 00000000
oem-program-secure:(0x00e4 224-bits)
00000000 00000000 00000000 00000000 00000000 00000000 00000000
3, write oem-program 2
$ xfel extra efuse write32 0x003c 0x55667788
$ xfel extra efuse dump
chipid:(0x0000 128-bits)
93005c00 ac004814 01425a4c 1c5318cb
brom-conf-try:(0x0010 32-bits)
00000000
thermal-sensor:(0x0014 64-bits)
7906c10a 019db011
ft-zone:(0x001c 128-bits)
83883119 0ef00f02 2b06111c 87180a0b
tvout:(0x002c 32-bits)
00000285
tvout-gamma:(0x0030 64-bits)
00000000 00000000
oem-program:(0x0038 64-bits)
11223344 55667788
write-protect:(0x0040 32-bits)
00000000
read-protect:(0x0044 32-bits)
00000000
reserved1:(0x0048 64-bits)
00000000 00000000
huk:(0x0050 192-bits)
00000000 00000000 00000000 00000000 00000000 00000000
reserved2:(0x0068 64-bits)
00000000 00000000
rotpk:(0x0070 256-bits)
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
ssk:(0x0090 256-bits)
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
rssk:(0x00b0 128-bits)
00000000 00000000 00000000 00000000
hdcp-hash:(0x00c0 128-bits)
00000000 00000000 00000000 00000000
nv1:(0x00d0 32-bits)
00000000
nv2:(0x00d4 32-bits)
00000000
reserved3:(0x00d8 96-bits)
00000000 00000000 00000000
oem-program-secure:(0x00e4 224-bits)
00000000 00000000 00000000 00000000 00000000 00000000 00000000
4, reboot and dump efuse again
$ xfel extra efuse dump
chipid:(0x0000 128-bits)
93005c00 ac004814 01425a4c 1c5318cb
brom-conf-try:(0x0010 32-bits)
00000000
thermal-sensor:(0x0014 64-bits)
7906c10a 019db011
ft-zone:(0x001c 128-bits)
83883119 0ef00f02 2b06111c 87180a0b
tvout:(0x002c 32-bits)
00000285
tvout-gamma:(0x0030 64-bits)
00000000 00000000
oem-program:(0x0038 64-bits)
11223344 55667788
write-protect:(0x0040 32-bits)
00000000
read-protect:(0x0044 32-bits)
00000000
reserved1:(0x0048 64-bits)
00000000 00000000
huk:(0x0050 192-bits)
00000000 00000000 00000000 00000000 00000000 00000000
reserved2:(0x0068 64-bits)
00000000 00000000
rotpk:(0x0070 256-bits)
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
ssk:(0x0090 256-bits)
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
rssk:(0x00b0 128-bits)
00000000 00000000 00000000 00000000
hdcp-hash:(0x00c0 128-bits)
00000000 00000000 00000000 00000000
nv1:(0x00d0 32-bits)
00000000
nv2:(0x00d4 32-bits)
00000000
reserved3:(0x00d8 96-bits)
00000000 00000000 00000000
oem-program-secure:(0x00e4 224-bits)
00000000 00000000 00000000 00000000 00000000 00000000 00000000
离线
写完会熔断吗?会不会因为写efuse不当导致芯片成砖
这个是可能的,比如你烧写了加密引导位,并且随便填了个rotpk的sha256值,那么你的芯片就永远无法启动了,没有合法的加密引导签名,谁都没辙,就变砖了。
但只要不碰到关键熔丝,还是没啥风险的,在操作之前,仔细确认EFUSE分配信息,就无伤大雅了。
efuse分配信息,其实也不是一成不变的,除了核心分配信息,基本都是随着SDK的而重新分配的,这些细节就只能去翻代码了。
有些efuse存储了全志出厂时的芯片校正信息,比如温度传感器校正参数,TVOUT校正,各种AD,DA,内部RC补偿等等,这些没有文档,只能自己去寻找蛛丝马迹了。
离线
扩展XFEL,支持V851/V853芯片的EFUSE读写操作
$ xfel extra efuse dump
chipid:(0x0000 128-bits)
62c07800 cc004820 0145c519 204e1a8c
brom-conf-try:(0x0010 32-bits)
00000000
thermal-sensor:(0x0014 64-bits)
2291c0f9 007c9279
ft-zone:(0x001c 128-bits)
100f1109 13210de2 00278600 00691510
reserved1:(0x002c 96-bits)
00000000 00000000 00000000
write-protect:(0x0038 32-bits)
00000000
read-protect:(0x003c 32-bits)
00000000
lcjs:(0x0040 32-bits)
00000000
reserved2:(0x0044 800-bits)
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000
rotpk:(0x00a8 256-bits)
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
reserved3:(0x00c8 448-bits)
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000
离线
在F133芯片上,烧写ECDSA256 64字节签名文件到EFUSE,偏移为0x00c0区域,也就是2048bit的最后面的512bit,efuse前面的bit有各种隐藏用途,需小心使用,但后面的bit就随便整了。无需担心变砖。
经验证,是可以通过efuse来存储签名文件,并能够验签通过。
1,通过write指令烧写64字节签名文件,烧写到0xc0这个偏移位置
xfel extra efuse write 0x00c0 sign.bin
2,查看烧写好的efuse,发现0xc0偏移,已经储存了签名文件,与sign.bin的内容保持一致
xfel extra efuse dump
chipid:(0x0000 128-bits)
93005c00 ac004814 01425a4c 1c5318cb
brom-conf-try:(0x0010 32-bits)
00000000
thermal-sensor:(0x0014 64-bits)
7906c10a 019db011
ft-zone:(0x001c 128-bits)
83883119 0ef00f02 2b06111c 87180a0b
tvout:(0x002c 32-bits)
00000285
tvout-gamma:(0x0030 64-bits)
00000000 00000000
oem-program:(0x0038 64-bits)
11223344 55667788
write-protect:(0x0040 32-bits)
00000000
read-protect:(0x0044 32-bits)
00000000
reserved1:(0x0048 64-bits)
00000000 00000000
huk:(0x0050 192-bits)
00000000 00000000 00000000 00000000 00000000 00000000
reserved2:(0x0068 64-bits)
00000000 00000000
rotpk:(0x0070 256-bits)
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
ssk:(0x0090 256-bits)
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
rssk:(0x00b0 128-bits)
00000000 00000000 00000000 00000000
hdcp-hash:(0x00c0 128-bits)
e133aa93 7aaf3227 14b10f12 06b71c6c
nv1:(0x00d0 32-bits)
ef80e46e
nv2:(0x00d4 32-bits)
e0ba33d4
reserved3:(0x00d8 96-bits)
a6fe6c3c f65c2d60 915ae6c7
oem-program-secure:(0x00e4 224-bits)
90ce9b07 94906489 3e39dce8 d06473aa 1dda2501 1f940484 36a770d8
3, 验签,将efuse里的签名读出来,用ECDSA256公钥进行验签,这里是对CPU唯一序列号的SHA256摘要进行验签。经过这样的操作,只要你没有ECDSA256私钥,你是无法生成正确的签名文件的,那么验签就无法通过。当别人想抄板或更换CPU,因序列号变了,且没有正确的签名,就无法启动运行,实现放盗版保护。
离线
上面的验签过程,有两种应用场景,需求不同,思路也会不同。
第一种,自己的产品防盗版,没有升级需求,或者loader没有升级需求,也就是某部分固件,完全不变化,且需防盗版抄袭。
这种需求,你需要将CPU ID + 固件或者loader,两者所有信息进行sha256摘要运算,并用ECDSA256对SHA256的摘要进行签名,存储在EFUSE里。当别人复制产品时,复制了SPI NOR FLASH,复制了EFUSE 签名,因CPU ID不同,也无法正常验签。
第二种,自己是方案商仅出主控芯片,客户自行烧录生产,有固件及各种烧写工具。这种情况要求客户必须从你这里走芯片,而不能从市面上随便购买。
对于这种需求,仅需要对CPU ID 进行SHA256摘要运算,并用ECDSA256对SHA256的摘要进行签名,存储在EFUSE里,烧录好,出给客户就可以了。客户可以随便刷机,升级,但不能随便购买芯片。
当然,固件完整性,固件防逆向,这些需求,可结合坑网之前的讨论的帖子,来实现。
最后一句话,攻防手段千千万,但几千年来,唯一不变的,还是人心,人性。
离线
有厂家提前烧好的区域,比如chipid,thermal-sensor,但这些都还是可见的,全志在启用加密引导功能后,有部分EFUSE就不可见了,读取会直接返回0。
全志SOC,写EFUSE,必须通过SID控制器,通过寄存器操作来写入,但读取EFUSE,有两种方案,一种是比较简单的SRAM映射,直接用MMIO来访问就可以了,这里有个细节需要注意,仅支持word字访问,不支持byte字节访问,还有一种方案,就是用SID控制器来读取。
SRAM映射方案,只有在SOC重启时更新一次,所以,如果新写入了efuse,想不重启来查看的话,就需要用SID控制器来读取。
启用加密模式后,SID控制器访问也会受限,需要用SMC相关指令来访问,具体还没有研究加密后的SID控制器。
离线
当烧写了加密引导,如果所有固件都引导失败了,会自动进入非加密模式的FEL。
离线
要启用加密引导模式,需要将LCJS段里面的某个bit写1,就启用加密引导了,如果这个时候rotpk段还没有写入,那么全志的会引导任何一个加密引导固件,不进行任何校验,但只要写入了rotpk(非全0),就需要校验了。
rotpk,其实就是RSA2048公钥的SHA256摘要,总共256bit,这个在烧写时,必须保留好RSA2048私钥,否则就像锁门并焊死锁孔。
离线
chipid 0状态的bit 可以重写吗?
我觉得应该是可写的,只是还没有这样去操作过,此过程,跟全志芯片出厂时流程一致。之前实验过OEM段,多次写入,0值bit可以再次编程到1。
离线
受影响,我们常用的非加密模式引导头是egon,如果修改成加密引导,那么加密头就需要toc0,这个部分有些差异,toc头信息比egon信息要多一些,能否兼容,这个还没有深入研究,现在只知道,两个头信息不一样的,这些操作都是SBROM里面来实现的,而且全志的BROM有两套,一个是普通的BROM,另一个是SBROM,根据EFUSE配置,自动选择对应的BROM,SBROM也是可以dump出来的。前提是烧写LCJS后,用程序dump出来,FEL模式是无法dump SBROM,fel仅存在与非加密模式
离线
在DUMP EFUSE后,有一个ft-zone字段,一直不能明白ft是啥意思,现在终于搞明白了,原来是final test (FT) stage的缩写,芯片终测后,写入的EFUSE值,总共128bit,具体是干啥的,就不得而知了。
ft-zone:(0x001c 128-bits)
898f1919 0f760f6c 3108126c 811a0a0e
final test (FT) stage
最近编辑记录 xboot (2023-07-12 22:23:06)
离线
TVOUT efuse是用于设置TVE模块的bias
tvout:(0x002c 32-bits)
0000028f
离线
就是说编程 LCJS 之后,是启动SBROM,否则是启动BROM?
是的,关于rotpk,准确的表达是,全0,全1,或者没个字节都一样时,可以运行加密固件而不需要校验签名。只有每个字节,有一个不同时,才启用校验功能。
额,我发现加密安全引导漏洞了,我仅需将rotpk字段再次烧写为全1,那么就可以引导我自己的加密固件了,这全志的安全引导,真值得商榷。在加密模式只要可以引导自己的加密固件,那么所有的安全都形同虚设。
额,好吧,安全芯片,做好真心不太容易。
离线
@xboot
chipid是efuse,那岂不是所有芯片的chipid都可以被修改成ffffff,那岂不是只要有ffffff设备的密钥或证书,就能全部运行了?
是的,可以这么说,谁要愿意,可以去写一下chip id 看看
离线
我来当小白鼠了,CHIP ID是可以改写的。在T113芯片上测试
先读取出厂的CHIP ID,前4个字节为93406000
$ xfel extra efuse dump
chipid:(0x0000 128-bits)
93406000 0c004814 01426250 48671b4b
将前4个字节修改为0xffffffff
$ xfel extra efuse write32 0x00 0xffffffff
再次查看芯片的CHIP ID,已经被修改为0xffffffff了。
$ xfel extra efuse dump
chipid:(0x0000 128-bits)
ffffffff 0c004814 01426250 48671b4b
结论,关于CHIP ID,你真的可以用xfel工具,自己重写一个。如果全志出厂时,CHIP ID全0的话,你是真的可以完美复制出两个一模一样的芯片。
我印象中,当时还在研究D1,手上拿到了一颗F133样片,里面的SID就是全0,当时还很奇怪,为何没有SID呢,原来仅仅是没烧写。
一转眼,距离离研究D1芯片,已经过去2年了, 这该死的时间,也不慢一点。
最近编辑记录 xboot (2023-07-13 15:09:28)
离线
翻了一下,当时的《全志D1芯片之终极探索》,尽然记录了这个异常的CHIP ID。算是在两年后给了一个交代。
离线