【海思篇】【Hi3516DV300】九、根据OTP实现加密芯片功能

 

为了保护硬件flash上的数据,防止被HACKED,我们产品大都需要一个加密芯片。而海思本身就有OTP功能,我们完全可以把它利用起来。此外, 我们可以在OTP里保存一些特定的信息,例如设备信息、秘钥等信息。

目录

1 相关寄存器定义

2 寄存器读写函数

3 otp初始化实现

4 读取otp的lock状态

5 加在otp的key到加密模块

6 烧写KEY、JTAGID、PASSWORD到OTP

7 KEY、JTAGID、PASSWORD的CRC校验

8 使能标志位烧写模式

9 用户预留空间烧写模式

10 用户预留空间回读模式

11 样例及源码传送门


本文代码实现参考《Hi35xx Camera Soc 用户指南.pdf》

1 相关寄存器定义

主要有otp时钟和otp_ctrl寄存器组

#define HAL_SET_BIT(src, bit)               ((src) |= (1<

2 寄存器读写函数

#define PAGE_SIZE_MASK (~(0xfff))
#define PAGE_SIZE 0x1000

#define HAL_CIPHER_ReadReg(addr, result)    (*(result) = *(volatile unsigned int *)(addr))
#define HAL_CIPHER_WriteReg(addr,result)    (*(volatile unsigned int *)(addr) = (result))

HI_VOID *g_pOtpRegBase = NULL;
static const char dev[]="/dev/mem";

HI_VOID * COMM_MMAP(HI_U32 u32RetAddr)
{
	HI_S32 fd = open (dev, O_RDWR | O_SYNC);
	if (fd < 0)
	{
	    printf("open %s error!\n", dev);
	    return NULL;
	}
    
	/* addr align in page_size(4K) */
	HI_U32 phy_addr_in_page;
	HI_U32 page_diff;
	phy_addr_in_page = u32RetAddr & PAGE_SIZE_MASK;
	page_diff = u32RetAddr - phy_addr_in_page;

	/* size in page_size */
	HI_U32 size_in_page;
	HI_U32 size = PAGE_SIZE;
	size_in_page =((size + page_diff - 1) & PAGE_SIZE_MASK) + PAGE_SIZE;

	HI_VOID *addr = mmap((void *)0, size_in_page, PROT_READ|PROT_WRITE, MAP_SHARED, fd, phy_addr_in_page);
	if (addr == MAP_FAILED)
	{
	    printf("mmap @ 0x%x error!\n", phy_addr_in_page);
	    close(fd);
	    return NULL;
	}
	return addr+page_diff;
}

HI_VOID COMM_MUNMAP(HI_U32 u32RegAddr)
{
	munmap((HI_VOID*)u32RegAddr, PAGE_SIZE);
}

3 otp初始化实现

/* OTP init */
HI_S32 HI_OTPMNG_Init(HI_VOID)
{
    HI_U32 CrgValue = 0;
    HI_U32 *pu32SysAddr = HI_NULL;

    pu32SysAddr = COMM_MMAP(REG_SYS_OTP_CLK_ADDR_PHY);
    if (pu32SysAddr == HI_NULL)
    {
        printf("[ERROR] u32SysAddr ioremap with nocache failed!!\n");
        return HI_FAILURE;
    }

    HAL_CIPHER_ReadReg(pu32SysAddr, &CrgValue);
    //printf("clk 0x%x\n", CrgValue);
    CrgValue |= OTP_CRG_CLOCK_BIT;   /* set the bit 0, clock opened */
    HAL_CIPHER_WriteReg(pu32SysAddr, CrgValue);

    COMM_MUNMAP((HI_U32)pu32SysAddr);

    g_pOtpRegBase = COMM_MMAP(OTP_REG_BASE_ADDR_PHY);
    if (g_pOtpRegBase == HI_NULL)
    {
        printf("[ERROR] osal_ioremap_nocache for OTP failed!!\n");
        return HI_FAILURE;
    }

    return HI_SUCCESS;
}

HI_VOID HI_OTPMNG_Uninit(HI_VOID)
{
	if(g_pOtpRegBase) 
    {
    	COMM_MUNMAP((HI_U32)g_pOtpRegBase);
    	g_pOtpRegBase = NULL;
    }
}

4 读取otp的lock状态

 

HI_S32 HI_OTPMNG_GetLockStat(HI_U32 *pu32LockSta)
{
    if(HI_FAILURE == HI_OTPMNG_WaitFree())
    {
            return HI_FAILURE;
    }

    if(HI_OTPMNG_SetMode(OTP_READ_LOCK_STA_MODE))
    {
        return HI_FAILURE;
    }

    HI_OTPMNG_OP_Start();

    if(HI_OTPMNG_Wait_OP_done())
    {
            return HI_FAILURE;
    }


    HAL_CIPHER_ReadReg(OTP_USER_LOCK_STA0, pu32LockSta);
    return HI_SUCCESS;
}

5 加在otp的key到加密模块

HI_S32 HI_OTPMNG_LoadCipherKey(HI_U32 opt_id)
{
    if(opt_id > OTP_USER_KEY3)
    {
        opt_id = OTP_USER_KEY0;
    }

    if(HI_FAILURE == HI_OTPMNG_WaitFree())
    {
        return HI_FAILURE;
    }
    HI_OTPMNG_CHOOSE_OTP_key(opt_id);

    if(HI_OTPMNG_SetMode(OTP_LOCK_CIPHER_KEY_MODE))
    {
        return HI_FAILURE;
    }

    HI_OTPMNG_OP_Start();

    if(HI_FAILURE == HI_OTPMNG_Wait_OP_done())
    {
        return HI_FAILURE;
    }

    return  HI_SUCCESS;
}

6 烧写KEY、JTAGID、PASSWORD到OTP

HI_S32 HI_OTPMNG_WriteKey(HI_U32 enWhichKey, HI_U32 *pu32key, HI_U32 u32KeyArrayLen)
{
    HI_U32 u32LockStatus;
    HI_S32 i;

    if(HI_OTPMNG_GetLockStat(&u32LockStatus))
    {
    	return HI_FAILURE;
    }

    if(HI_OTPMNG_Is_Locked(enWhichKey,u32LockStatus))
    {
    	return HI_FAILURE;
    }

    if(HI_OTPMNG_WaitFree())
    {
    	return HI_FAILURE;
    }

    HI_OTPMNG_CHOOSE_OTP_key(enWhichKey);

    for(i = 0; i < u32KeyArrayLen; i++)
    {
    	HAL_CIPHER_WriteReg(OTP_USER_KEY_DATA0+i*4, pu32key[i]);
    }

    if(HI_OTPMNG_SetMode(OTP_WRITE_KEY_ID_OR_PASSWD_MODE))
    {
    	return HI_FAILURE;
    }

    HI_OTPMNG_OP_Start();

    return HI_OTPMNG_Wait_OP_done();
}

7 KEY、JTAGID、PASSWORD的CRC校验

HI_BOOL HI_OTPMNG_CRC16(HI_U32 enWhichKey, HI_U16 u16CRC)
{
	if(HI_OTPMNG_WaitFree())
    {
    	return HI_FALSE;
    }

    HI_OTPMNG_CHOOSE_OTP_key(enWhichKey);

    if(HI_OTPMNG_SetMode(OTP_KEY_ID_OR_PASSWD_CRC_MODE))
    {
    	return HI_FALSE;
    }

    HI_OTPMNG_OP_Start();

    if(HI_OTPMNG_Wait_OP_done())
    {
        return HI_FALSE;
    }

	return HI_OTPMNG_Wait_Is_CRC_ok();
}

8 使能标志位烧写模式

我对这部分文档中的理解还没到位,暂不实现。

9 用户预留空间烧写模式

8Kbit大小供开发者使用,也就是1KBytes,足够用。1K分为256块,每块32bit,每块可独立烧写。

产品型号、sensor、厂家、主板等信息可以烧入此空间。

// return -1 failed, 0 success, 1 has locked
HI_S32 HI_OTPMNG_WriteUserData(HI_U32 u32UserRegIdx, HI_U32 u32UserRegData)
{
	if(HI_OTPMNG_WaitFree())
    {
    	return HI_FAILURE;
    }

    HAL_CIPHER_WriteReg(OTP_USER_REV_ADDR, u32UserRegIdx);
	HAL_CIPHER_WriteReg(OTP_USER_REV_WDATA, u32UserRegData);

    if(HI_OTPMNG_SetMode(OTP_WRITE_USER_ROOM_MODE))
    {
    	return HI_FAILURE;
    }

	HI_OTPMNG_OP_Start();

	if(HI_OTPMNG_Wait_OP_done())
    {
        return HI_FAILURE;
    }

    return HI_OTPMNG_Wait_Is_Userlocked();
}

10 用户预留空间回读模式

HI_S32 HI_OTPMNG_ReadUserData(HI_U32 u32UserRegIdx, HI_U32 *pu32UserRegData)
{
	if(HI_OTPMNG_WaitFree())
    {
    	return HI_FAILURE;
    }

    HAL_CIPHER_WriteReg(OTP_USER_REV_ADDR, u32UserRegIdx);

    if(HI_OTPMNG_SetMode(OTP_Read_USER_ROOM_MODE))
    {
    	return HI_FAILURE;
    }

	HI_OTPMNG_OP_Start();

	if(HI_OTPMNG_Wait_OP_done())
    {
        return HI_FAILURE;
    }

    HAL_CIPHER_ReadReg(OTP_USER_REV_RDATA, pu32UserRegData);

    return HI_SUCCESS;
}

11 样例及源码传送门

static HI_VOID VIO_TestOTP()
{
	printf("=========VIO_TestOTP=============\n");
	if(HI_OTPMNG_Init() == HI_SUCCESS)
	{
                // 注意用户空间有256个块,每块大小为32bit
                // 每块只可以烧写一次,下次烧写会打印已锁定
                HI_OTPMNG_WriteUserData(0, 0x12345678);

		HI_S32 i;
		HI_U32 u32UserRegData;
                // 打印所有user
		for(i = 0; i <= 255; i++)
		{
			HI_OTPMNG_ReadUserData(i, &u32UserRegData);
			printf("\t %0*x: %0*x\n", 2, i, 8, u32UserRegData);
		}

		HI_OTPMNG_Uninit();
	}
}

源码传送门:https://download.csdn.net/download/cocoron/12325676

你可能感兴趣的:(【海思篇】【Hi3516DV300】九、根据OTP实现加密芯片功能)