DCSM模块使用说明

作者:华北区 EP 工程师 Brian Wang 华北区 C2000 工程师 Young Hu 

一、功能描述:

CSM加密是C2000系列芯片最基础的加密方式,也是在前代产品(如F2803x/F2806x)中广泛采用的加密方式。在最新的28004x、2837x等芯片中增加了双码安全模块(DCSM),该功能支持将芯片中的memory划为两个独立区域,并设置各自独立的的128位CSM密码。该功能可以阻止未授权人员访问加密内容,进而有效防止您的代码被重复或逆向编译;与此同时,需要维护与升级的代码可以存储于另一个独立区域内,并授权给相关人员使用。合理运用此功能,可以进一步地提高产品的安全性以及易用性。

 

二、功能使用:

2.1 芯片存储的分区设置

下面以Control Suite中TMS320F28377S的 blinky_with_DCSM工程为例,讲解DCSM模块的用法:

首先必须明确,虽然DCSM模块中设计了相关机制允许用户反复设置和使用该功能,但对于DCSM模块的不当操作仍然可能锁死芯片,因此建议您在工程开发的末尾阶段再进行DCSM模块的相关设置和操作。

为了充分发挥双码安全模块的作用,需要根据工程需要对MCU中的资源进行分区配置。通过配置GRABRAMx/GRABSECTx寄存器,按需求将RAM/FLASH分别划入不同的Zone中,从而实现用两套独立密码对不同区域分别进行安全管理。

图1 GRABRAMx/GRABSECTx寄存器设置

以工程blinky_with_DCSM为例,假如我们想要将FLASH A 分配至Zone1进行保护,FLASH B分配至Zone2进行保护。参考手册中关于Zx_GRABSECTR Register及Zx_GRABSECTR Register,需要对DCSM_Zx_ZoneSelectBlock.asm进行如下修改。将Zone 1GRABSECT中FLASH A对应的[1:0]位改为01或10;将Zone 2 GRABSECT中FLASH B对应的[3:2]位改为01或10;特别需要注意的是,由于.asm中一个section是按位写入的,因此在对.asm文件进行修改时,必须以section为单位进行修改,即便有reserve的部分也需要将注释删掉进行编译,否则写入时只会按位写入已编译的内容,发生错位,难以修改。

  1.       .sect "dcsm_zsel_z1"  
  2.      .long 0xFFFFFFFF      ;Z1-EXEONLYRAM  
  3.      .long 0xFFFFFFFF      ;Z1-EXEONLYSECT  
  4.      .long 0xFFFFFFFF      ;Z1-GRABRAM  
  5.      .long 0xFFFFFFFE      ;Z1-GRABSECT  

 

  1.       .sect "dcsm_zsel_z2"  
  2.      .long 0xFFFFFFFF      ;Z2-EXEONLYRAM  
  3.      .long 0xFFFFFFFF      ;Z2-EXEONLYSECT  
  4.      .long 0xFFFFFFFF      ;Z2-GRABRAM  
  5.      .long 0XFFFFFFF7      ;Z2-GRABSECT  

 

2.2分区的基本设置

在完成了对要保护存储的分区之后,我们需要了解如何给两个区域设置不同的密码。

对于两个保护Zone,每个都有一个专属的OTP Block,以对各Zone进行安全设置,具体包含的资源及作用如下:

Zx-LINKPOINTER1-3

配置Zx OTP中Zone Select Block的位置

Zx-PSWDLOCK

用于使能Password Lock

Zx-CRCLOCK

用于使能Safe CRC

ZoneSelectBlock(0x20-0x1F0)

Zone Select Block 预留位置

Zx-EXEONLYRAM

用于使能RAM的Execute-only 保护

Zx-EXEONLYSECT

用于使能FLASH的Execute-only 保护

Zx-GRABRAM

用于配置RAM的所在分区

Zx-GRABSECT

用于配置FLASH的所在分区

Zx-CSMPASSWORD

用于配置分区的CSM密码

 

 为了能够让用户多次使用该功能、设置不同的密码,如图2,28004x系列MCU在USERS OTP中设置了多个存储密码及相关信息的位置(ZoneSelect Block),用户可以通过LINKPOINTER自由选择当前使用哪一个Zone Select Block。

LINKPOINTER与Zone Select Block 对应关系如图3所示。作为一种校验措施三个LINKERPOINTER的值设为相同,若LINKERPOINTER1/2/3值不相同,则LINKPOINTER的值将被置为全1,系统将默认选择Zone-Select Block 1(0x20)。此外,由于Zx-LINKERPOINTER位于OTP区域,因此该寄存器的各位只能由1写成0,而不能逆向操作。因此,只有Zx-LINKPOINTER的值从“全F”写起,并在每次重新设置时按照下表顺序逐位写0,才能够充分利用到OTP中的所有Zone-Select Block。

 

图2 Zonex OTP Flash

图3 Zx-LINKPOINTER与Zone Select Block对应关系

以工程blinky_with_DCSM为例,假如是第一次使用DCSM功能,为了充分利用所有Blocks,选取Zone_Select Block0作为当前使用的Block,在DCSM_Zx_ZoneSelectBlock.asm中保证Z1-LINKPOINTER值为全F,此时选取的Zone_Select Block起始地址为0x70820。

  1.   .sect "dcsm_otp_z1_linkpointer"  
  2. .long 0x1FFFFFFF     ;Z1-LINKPOINTER1  
  3. .long 0xFFFFFFFF     ;Reserved  
  4. .long 0x1FFFFFFF     ;Z1-LINKPOINTER2  
  5. .long 0xFFFFFFFF     ;Reserved  
  6. .long 0x1FFFFFFF     ;Z1-LINKPOINTER3  
  7. .long 0xFFFFFFFF     ;Reserved  

类似地,如果后续工程需要对密码以及分区情况进行修改,我们可以启用Zone_Select Block1,将LINKERPOINTER的最后一位写0,对应的修改如下:

  1.   .sect "dcsm_otp_z1_linkpointer" 
  2. .long 0x1FFFFFFE     ;Z1-LINKPOINTER1  
  3. .long 0xFFFFFFFF     ;Reserved  
  4. .long 0x1FFFFFFE     ;Z1-LINKPOINTER2  
  5. .long 0xFFFFFFFF     ;Reserved  
  6. .long 0x1FFFFFFE     ;Z1-LINKPOINTER3  
  7. .long 0xFFFFFFFF     ;Reserved  

此时需要注意还需要将CMD文件中对应Zone Select Block地址的内容进行修改,保证写入的Flash地址与当前的Zone Select Block正确对应。

  1. /* DCSM Z1 Zone Select Contents (!!Movable!!) */  
  2. /* Z1 OTP.  Z1 password locations / Flash and RAM partitioning */  
  3. DCSM_ZSEL_Z1_P0         : origin = 0x78030, length = 0x000010  

最后在SECTIONS中将要写入区域对应处的type=DSECT 删除,否则FLASH写入不会进行。

  1. SECTIONS  
  2. {  
  3.    b0_dcsm_otp_z1_linkpointer   : > B0_DCSM_OTP_Z1_LINKPOINTER   PAGE = 0, type = DSECT
  4. /* Delete type=DSECT when writing in OTP */    

特别需要注意的是:由于以上涉及到的寄存器都位于OTP(One-Time Programmable)FLASH中,不能进行反复更改,因此建议在开发后期代码以及内存分配确定之后,再进行相关的设置。

 

2.3 加密功能及其使用

在完成了对MCU中memory的分区以及Zone Select Block位置的设置后,下面来看DCSM所支持的几种加密模功能:

1)CSM密码加密与解密:

CSM加密是DCSM加密的基础,在完成对MCU 存储的分区之后,需要为分区设置各自的密码才能使能加密功能。密码寄存器Zx-CSMPSWD0/1/2/3位于各自的OTP的Zone Select Block中,具体位置由该区域的LINKPOINTER决定。对于2837x系列,当Zx-CSMPSWD0/1/2/3的值为默认值1,该区域处于解锁状态。当寄存器值为全0,该区域会被锁死,因此用户不应当使用全0密码。

以工程blinky_with_DCSM为例,要设置Zone1的密码,我们需要在DCSM_Zx_ZoneSelectBlock.asm中将Zx-CSMPSWDx寄存器改为想要设置的密码:

  1. .sect "dcsm_zsel_z1"  
  2.   
  3.       .long 0xFFFFFFFF      ;Z1-EXEONLYRAM  
  4.       .long 0xFFFFFFFF      ;Z1-EXEONLYSECT  
  5.       .long 0xFFFFFFFF      ;Z1-GRABRAM  
  6.       .long 0xFFFFFFBF      ;Z1-GRABSECT  
  7.   
  8.       .long 0x11223344      ;Z1-CSMPSWD0 (LSW of 128-bit password)  
  9.       .long 0x11223344      ;Z1-CSMPSWD1  
  10.       .long 0x55667788      ;Z1-CSMPSWD2  
  11.       .long 0x55667788      ;Z1-CSMPSWD3 (MSW of 128-bit password)  

同样需要在CMD中对相应的dcsm_zsel_zx 的sections 进行修改,删除type=DSECT,对FLASH的操作才能够进行。这样就完成了Zonex 密码的设置工作。

  1.      b0_dcsm_zsel_z1      : > B0_DCSM_ZSEL_Z1_P0            PAGE = 0

进行加密后,通过仿真器读取Zone 1 OTP Flash结果如下:

图3 加密后的OTP区域

可以看到此时Zone 1 OTP Flash中除了 CSMPSWDx寄存器中的密码,其它部分均进行了加密操作。之所以采用这样的设计,是为了在开发初期开发者可以利用这一特性随时查看CSM,避免因为密码遗忘或者写入操作造成芯片被锁死。对于密码区域的加密需要通过Password Lock 功能进行,将在后文进行进一步描述。

此时,如果试图通过仿真器读取加密区域Flash B,可以看到Flash区域也进行了加密(返回全0):

图3 未加密的Flash(左)与加密后的Flash(右)

要对CSM进行解密,需要经过Password match flow(PMF)流程,程序将从两个Zone读取CSM PWL并与写入CSMKEYx寄存器的密码进行比对,若密码完全一致,则为该区域解密,否则解密失败。

图4 Password Match Flow 流程图

解密操作可以通过几种方法进行,首先可以在debug界面单击tools -> on chip flash -> 在对应位置处输入密码,点击Unlock:

图5在On chip flash中进行密码匹配

也可以在.gel文件中找到写入csmkey寄存器的代码段,并自行修改密码:

  1. *(unsigned long *)0x5F010 = 0x11223344;  // Virtual password
  2. *(unsigned long *)0x5F012 = 0x55667788;  
  3. *(unsigned long *)0x5F014 = 0x11223344;  
  4. *(unsigned long *)0x5F016 = 0x55667788;  

另外,也可以通过在芯片内部执行一段解密程序完成解密操作,具体代码可参照.gel文件。

以blinky_with_DCSM为例,如果把代码段写入FLASH A,并将FLASH A划入Zone1设置密码保护。在正确输入密码时,烧录操作可以正常进行。

而在不输入正确密码时,会出现解锁失败的提示,烧录也会报错。

图6 未解锁状态下进行烧录报错

NOTE:特别需要注意的是,在使用280049系列芯片时,与传统C2000系列芯片不同,其ZxOTP_CSMPSWD1寄存中写入的默认密码不是全“1”。由于OTP寄存器的特殊性,只能在默认设置的基础上将1改成0,否则可能发生FLASH写入错误。

图8 28004x CSMPWSD1默认密码表(部分)

2)仿真代码保密逻辑 Emulation Code Security Logic(ECSL)

在CSM的基础上,芯片利用CSM密码的后64位设计了仿真加密逻辑。如果试图在加密代码中Halt就会触发该保护,断开仿真连接。用户需要在CSMKEY(0/1)中写入正确的64位密码才能启用仿真,但此时并不会解锁CSM保护,对CSMKEY(0/1)的写入方法可以参考上一条。

图8 在加密代码中Halt触发仿真保护

特别注意,在debug一个加密MCU时,仿真器需要一些时间控制CPU,但此时CPU可能已经运行并触发ECSL保护导致断连。要解决此问题,请使用Wait Boot Mode boot选项,在此模式中,CPU会运行在一个循环中而不进入应用程序,从而避免触发保护。具体设置方法请参考技术手册Boot Rom部分,Launchpad可以通过拨动相应的开关进入此模式。

 

3)CPU加密逻辑 CPU Secure Logic(CPUSL)

CPU加密逻辑可以防止未授权者通过Watch Window读取CPU寄存器,在程序指针指向保护区域时,所有对于CPU寄存器的访问都被禁止(程序指针除外)。在此情况下,最好不要对CPU寄存器进行写入。另外,如果CSM被解锁,此外,CPUSL也将被关闭。

图8 加密代码运行过程中CPU Registers不可见

4)仅执行保护 Execute-Only Protection

对于存储关键数据的RAM或FLASH,TI提供了Execute-Only Protection。当该逻辑启用,任何对该区域数据的读取都将被禁止。例如如果试图使用另一个加密区域中的代码对Execute-Only Protection加密区域中的代码进行复制、读取等操作都将被禁止。通过写入EXEONLYSECT以及EXEONLYRAM寄存器对应位的值,可以启用该功能。

5)密码锁 Password Lock

如前文所述,若只采用CSM加密,可以通过Memory Browser发现此时对应CSM密码的位置并没有进行加密。在开发完成后,开发者需要通过Password Lock功能对此区域进行加密,以防他人读取密码并进行解密。启用该保护的方法是向对应区域的PSWDLOCK寄存器0:3位写入0xF以外的值。

图9 未开启Password Lock时的ZSB0寄存器值

以blinky_with_DCSM为例,要设置Zonex的密码,需要在DCSM_Zx_ZoneSelectBlock.asm中将Zx-PSWDLOCK[3:0]该为非全1,并在CMD中删去相应部分的.DSECT:

  1. .sect "dcsm_otp_z1_pswdlock"  
  2. .long 0xFFFFFFFE     ;Z1-PSWDLOCK  
  3. .long 0xFFFFFFFF     ;Reserved  

图10开启Password Lock时的ZSB0寄存器值

至此,我们就完成了DCSM中各种安全功能的介绍和设置,特别注意,由于PSWDLOCK等寄存器并不位于Zone Select Block当中,因此只能进行一次写入,不能进行更改,因此应该在程序开发后期再加此类保护。

 

三、小结

DCSM加密相较于传统的CSM加密具有更完善的保密措施和更灵活的使用方法。双密码的引入允许用户用不同密码管理不同部分的代码,为产品的代码安全以及后期的升级维护都带来了极大的便利。本实例以2837x系列芯片为对象,描述了DCSM模块常见的使用方法。28004x系列芯片仅在DCSM OTP区域的数量和使用方法上与2837x略有不用,也可参照此说明进行相应操作。

另外部分C2000芯片也可以使用Unique ID作为种子进行进一步的加密,具体方法不在此展开。