Security ID - 芯片ID
SID提供的功能可以分为四大部分:ChipID、SoC Version、efuse功能、一些状态位。
SID是一个比较独立的模块,在Linux内核中没有依赖其他子系统,在 sunxi 平台默认是 ko 方式 SID为其他模块提供API的调用方式。关系如下图:
- 
TV、Thermal、GMAC的校准参数保存在SID中; 
- 
Nand、SMP、VE需要读取 SoC Version;
- 
CE和HDMI会用到SID中的一些Key; 
- 
Sysinfo比较特殊,为了方便用户空间获取、调试SID信息,专门设计的一个字符型设备驱动。
Chip ID功能
对于全志的SoC来说,ChipID用于该SoC的唯一标识
ChipID由4个word(16个byte)组成,共128bit,通常放在efuse的起始4个word
SoC Version功能
严格讲SoC Version包含两部分信息:
- 
Bonding ID,表示不同封装。 
- 
Version,表示改版编号。 
BSP会返回这两个信息的组合值,由应用去判断和做出相应的处理。
efuse功能
对软件来说,efuse中提供了一个可编程的永久存储空间,特点是每一位只能写一次(从0到1)。efuse接口方式:efuse容量大于512bit采用SRAM方式。带有SRAM的硬件结构示意图如下:
一些状态位
Secure Enable标志位。
- 标明当前系统的 Security属性是否打开,即是否运行了SecureBoot和SecureOS。
- 芯片 SecureEnable状态位保存在SID模块的0xa0寄存器。
模块配置
驱动配置
驱动位于
SID Drivers ->
	<*> Allwinner SID Support
	< > Allwinner Set Efuse Power

设备树配置
sid@3006000 {
	compatible = "allwinner,sun55iw3p1-sid", "allwinner,sunxi-sid";
	reg = <0x0 0x03006000 0 0x1000>;
	#address-cells = <1>;
	#size-cells = <1>;
	non-secure-maxoffset = <0x80>;
	non-secure-maxlen = <0x20>;
	secure_status {
		reg = <0x0 0>;
		offset = <0xa0>;
		size = <0x4>;
	};
            
	chipid {
		reg = <0x0 0>;
		offset = <0x200>;
		size = <0x10>;
	};
            
	rotpk {
		reg = <0x0 0>;
		offset = <0x140>;
		size = <0x20>;
	};
};
sram_ctrl: sram_ctrl@3000000 {
	compatible = "allwinner,sram_ctrl";
	reg = <0x0 0x03000000 0 0x184>;
	soc_ver {
		offset = <0x24>;
		mask = <0x7>;
		shift = <0>;
		ver_a = <0x00000000>;
		ver_b = <0x00000001>;
		ver_c = <0x00000002>;
	};
	soc_id {
		offset = <0x200>;
		mask = <0x1>;
		shift = <22>;
	};
	soc_bin {
		offset = <0x0>;
		mask = <0x3ff>;
		shift = <0x0>;
	};
};
驱动接口
在获取 Key 的时候,调用者需要知道 Key 的名称,以此作为索引的依据。Key名称详见 sunxi-sid.h
#define efuse_CHIPID_NAME            "chipid"
#define efuse_BROM_CONF_NAME         "brom_conf"
#define efuse_BROM_TRY_NAME          "brom_try"
#define efuse_THM_SENSOR_NAME        "thermal_sensor"
#define efuse_FT_ZONE_NAME           "ft_zone"
#define efuse_TV_OUT_NAME            "tvout"
#define efuse_OEM_NAME               "oem"
#define efuse_WR_PROTECT_NAME        "write_protect"
#define efuse_RD_PROTECT_NAME        "read_protect"
#define efuse_IN_NAME                "in"
#define efuse_ID_NAME                "id"
#define efuse_ROTPK_NAME             "rotpk"
#define efuse_SSK_NAME               "ssk"
#define efuse_RSSK_NAME              "rssk"
#define efuse_HDCP_HASH_NAME         "hdcp_hash"
#define efuse_HDCP_PKF_NAME          "hdcp_pkf"
#define efuse_HDCP_DUK_NAME          "hdcp_duk"
#define efuse_EK_HASH_NAME           "ek_hash"
#define efuse_SN_NAME                "sn"
#define efuse_NV1_NAME               "nv1"
#define efuse_NV2_NAME               "nv2"
#define efuse_BACKUP_KEY_NAME        "backup_key"
#define efuse_RSAKEY_HASH_NAME       "rsakey_hash"
#define efuse_RENEW_NAME             "renewability"
#define efuse_OPT_ID_NAME            "operator_id"
#define efuse_LIFE_CYCLE_NAME        "life_cycle"
#define efuse_JTAG_SECU_NAME         "jtag_security"
#define efuse_JTAG_ATTR_NAME         "jtag_attr"
#define efuse_CHIP_CONF_NAME         "chip_config"
#define efuse_RESERVED_NAME          "reserved"
#define efuse_RESERVED2_NAME         "reserved2"
/* For KeyLadder */
#define efuse_KL_SCK0_NAME           "keyladder_sck0"
#define efuse_KL_KEY0_NAME           "keyladder_master_key0"
#define efuse_KL_SCK1_NAME           "keyladder_sck1"
#define efuse_KL_KEY1_NAME           "keyladder_master_key1"
使用 DEMO
- 读取SoC信息节点 /sys/class/sunxi_info/sys_info
# cat /sys/class/sunxi_info/sys_info
sunxi_platform    : sun50iw10p1
sunxi_secure      : secure
sunxi_chipid      : 00000000000000000000000000000000
sunxi_chiptype    : 00000400
sunxi_batchno     : 0x1
- 获取 Key 的信息 /sys/class/sunxi_info/key_info
先写入 Key 的名称,再读取.
# echo chipid > /sys/class/sunxi_info/key_info ; cat /sys/class/sunxi_info/key_info
0xf1c1b200: 0x00000400
0xf1c1b204: 0x00000000
0xf1c1b208: 0x00000000
0xf1c1b20c: 0x00000000
以下是一个简单的C语言程序示例,用于读取SoC信息节点和获取Key信息:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_BUF 256
void read_soc_info() {
    FILE *file = fopen("/sys/class/sunxi_info/sys_info", "r");
    if (file) {
        char buffer[MAX_BUF];
        while (fgets(buffer, sizeof(buffer), file)) {
            printf("%s", buffer);
        }
        fclose(file);
    } else {
        printf("无法打开/sys/class/sunxi_info/sys_info\n");
    }
}
void get_key_info(const char *key_name) {
    char key_path[MAX_BUF];
    char command[MAX_BUF];
    snprintf(key_path, sizeof(key_path), "/sys/class/sunxi_info/key_info");
    FILE *file = fopen(key_path, "w");
    if (file) {
        fprintf(file, "%s", key_name);
        fclose(file);
        snprintf(command, sizeof(command), "cat %s", key_path);
        system(command);
    } else {
        printf("无法打开%s\n", key_path);
    }
}
int main() {
    printf("SoC信息:\n");
    read_soc_info();
    printf("\nKey信息:\n");
    get_key_info("chipid");
    return 0;
}
这个程序包含了两个函数:read_soc_info 用于读取SoC信息节点,并将内容打印到控制台;get_key_info 用于获取Key信息,首先写入Key名称,然后读取并显示Key的信息。
FAQ
当启用安全系统后,Non-Secure 空间将无法访问大部分的 efuse 信息,这个时候需要通过SMC指令来读取这些Key信息。此时不能再使用普通的寄存器读接口,而是调用的SMC接口:int sunxi_smc_readl(phys_addr_t addr)。目前,sunxi_smc_readl()的实现在bsp/drivers/smc/sunxi-smc.c。