ZYNQ7000器件是ARM和FPGA合在一起的单芯片解决方案,又是以ARM为中心的解决方案,FPGA只是作为ARM的一个可编程的外设部分;系统首先启动的是ARM处理器,FPGA是在ARM处理器的控制下进行选择加载;本文首先对ZYNQ7000器件的启动过程做些了解和分析,然后着重分析应用中怎样对设计进行加密保护,并在MYD-C7Z010/20开发板上进行验证,因为在现代系统设计中越来越注重对设计的保护,这是为了防止产品在投放市场后出现有人抄袭我们的设计;在设计保护方面ZYNQ7000器件已经提供了一套解决方案,我们需要研究并加以应用到产品中去。
一、启动过程概述
ZYNQ7000器件支持从NAND、Parallel NOR、Serial NOR(Quad-SPI) 、SD卡和JTAG等多种设备启动,这通过系统上电复位后由PS采样专用的boot strapping signals引脚电平来决定从什么设备上引导启动Zynq处理器。参考Xilinx官方提供的文档《UG585 - Zynq-7000 SoC Technical Reference Manual (V1.12.2)》的第6章Boot and Configuration内容可知引导模式按如下表格决定:
可以看到ZYNQ 7000启动模式主要由MIO[5-3]来决定,而MIO6决定PLL是否使能,MIO[8-7]决定BANK1和BANK0电压,MIO2决定了JTAG 的Cascade和Independent模式,这里Cascade和Independent是指PS和PL的JTAG是否分开,MYD-C7Z010/20开发板上提供的JTAG端口是接在PL_JTAG端口上,如果你需要在这个端口上访问PS处理器,则必须使用Cascade mode。
具体的启动配置过程可以分为3个阶段,其中Stage2看应用场景是否需要有时可以省略,各阶段功能描述如下:
Stage0:称为BootROM,这一阶段控制最初的器件启动,BootROM是不可改动的可执行代码(即由XILINX厂家固化的引导代码,对用户来说完全不可控制和修改),处理器在上电复位和热重启之后执行。Stage-0阶段的主要功能是根据BOOT引脚选择的启动设备初始化相关外设,然后从启动设备中查找有效的镜像文件,并拷贝下一阶段引导程序到片上存储器(OCM)上。
Stage1:通常称为第一阶段引导程序(FirstStage Boot Loader,FSBL),它可以是任何用户可控的代码。由于FSBL是在Stage0拷贝到OCM(片上存储器)上,受限于OCM256KB的空间大小限制,FSBL的代码的大小被限制在192KB。Stage-1阶段的主要功能是进行系统的初始化和使用比特流文件进行PL的配置,然后拷贝“裸奔”(bare-metal)应用代码或者如有第二阶段引导加载程序的话拷贝第二阶段引导代码到DDR存储,最后调转到DDR入口位置执行“裸奔”(bare-metal)应用代码或者第二阶段引导加载程序。 在XILINX的SDK软件新建工程时是有提供一个FSBL的启动代码模板帮助用户快速实现自己的需求, 这个经常会用到。
Stage2:该阶段通常开始执行用户所设计的处理系统,但是它也可以是第二阶段引导程序(Second Stage Boot Loader,SSBL)。这一阶段完全在用户的控制之下,一般ZYNQ LINUX开发的话这个阶段为U-BOOT代码。
二、实现设计保护的原理
Zynq-7000器件内含AES-256解密引擎和HMAC认证引擎,并支持Secure Boot启动方式,在设计保护方面主要的方法就是AES-256加密与HMAC代码认证,RSA用户认证。
AES-256加解密用的密钥是用户自己定义的,可以存储在FPGA内部的eFuse或者BBRAM(battery-backed RAM)上,都不能被外部JTAG或FPGA逻辑读取,eFuse仅支持一次可编程,掉电内容不丢失。BBRAM可支持反复编程,但是掉电内容丢失,因此需要外接一个备份电池进行持续供电。
系统启动时,Zynq-7000首先执行芯片内部BootRom中的代码。BootRom中的代码由Xilinx开发并保证安全;代码保存在只读存储器中,用户无法修改,BootRom中的代码通过判断启动映像的加密状态位来决定是否加密启动,启动映像的加密状态位偏移位文件头0x28位置,这个字的有效值是0xA5C3C5A3或者0x3A5C3C5A表示映像是加密的,如果是非加密的映像,这个值是0,如果是其它值则是非法的,将引起锁定BootRom。这有效值为0xA5C3C5A3表示密钥存储在片内的eFuse,有效值为0x3A5C3C5A表示密钥存储在片内的BBRAM。
当BootRom判断为加密启动时,Boot Rom会关闭PS DAP和PLTAP控制器而不使能JTAG接口,这时无法通过JTAG接口读取Zynq-7000内部的信息,无论是软件二进制可执行代码,AES-256密钥,还是FPGA的配置信息,然后会打开AES解密引擎和HMAC认证引擎,这要求PL部分必须上电,因为器件是在FPGA部分执行AES-256解密和HMAC认证算法。对Boot Image中被加密的各个分区的数据用eFuse或BBRAM内的密钥进行AES-256解密,然后用HMAC引擎认证完整性,只有通过认证认为是合法并完整的代码(一般为FSBL(First Stage Boot Loader))才能被加载并执行。FSBL需要加载的Second Stage Boot Loader, 操作系统和应用可以是明文的,也可以是加密的,一般情况下还是继续加密的。XINLINX最新2018.03 的U-BOOT已经支持命令行下对bitstream/images 进行authenticate 和 decrypt (zynqrsa和zynqaes 命令),这样可以实现网络加载系统映像时的传输过程也是完全加密的。
三、实验操作
米尔科技的MYD-C7Z010/20只提供了2种启动模式:SD卡启动模式和QSPI启动模式。并没有JTAG模式,那怎么使用JTAG端口呢?按上面描述在加密启动模式下JTAG端口是不可以用的,所以我们要在MYC-C7Z010/20使用JTAG,就需要制作一个非安全模式的FSBL,让FSBL跑起来之后,就可以通过JTAG端口下载调试其他应用程序了,注意如果ZYQN启动时,在SD卡或者QSPI启动设备中没有找到有效的FSBL,JTAG也是禁止的。另外我们实验的话密钥不能存储在eFuse上,因为eFuse是一次性的编程,烧写后不可更改,选择存储密钥在BBRAM,掉电后清零对开发板没有什么影响,这个要特别注意下。
下面为具体的Step by Step实验步骤:
1、新建Vavido工程例化ZYQN硬核,这里ZYNQ IP设置可以使用开发板配套光盘MYD-C7Z01020_V08_20181220\05-Programmable_Source\7Z010\hello_world.rar压缩包下的helloworld.tcl脚本,使能了UART1和SD0外设,再运行SDK软件新建ApplicationProject应用工程, 工程名为FSBL, 代码模板选择Zynq FSBL, 然后再新建一个Application Project应用,工程名为hello_world, BoardSupport Package选择用Use existing FSBL_bsp, 代码模板选择Hello World,详细步骤可以参考之前的试用报告DDR3测试,这里不再截图赘述。
2、在SDK软件左侧工程浏览区点击hello_world工程,右键选择Create boot Image,如下图示:
3、在弹出界面直接点击CreateImage可以生成没有加密的 BOOT.bin 启动文件,把该文件拷贝到SD卡,把开发板JP2闭合、JP3断开跳线为SD卡启动模式, 插好SD卡到开发板,连接好串口线后上电就可以看到每秒打印一次hello world,如下图示:
4、重复第2步,在弹出的Create Boot Image对话框选择Security, 如下图示:
这里的Authentication是指用RSA鉴权认证,各密钥缩写说明一下:
PPK: RSAPrimary Public Key
SPK: RSASecondary Secret Key
PSK: RSA Primary Secret Key
SSK: RSA Secondary Public Key
Zynq-7000器件用primary RSA key去鉴权认证secondary keys,secondary keys才是真正用于映像各分区的鉴权认证,要使用RSA鉴权这里要打勾选择使能并填写密钥相关信息,由于要用RSA鉴权认证必须写相关信息到PS eFUSE array内,由于eFUSE是一次性编程的,并且开启RSA鉴权认证后是无法关闭的,我们实验不使用RSA鉴权认证。
5、点对话框旁边的Encryption选项,勾选上使用Encryption, Key file栏填入生成的密钥文件名: test.nky, Part name栏填实际器件的型号:xc7z010,Key store密钥存储位置选择BBRAM, 如下图所示:
点击Create Image可以生成加密的 BOOT.bin 启动文件和test.nky密钥文件,在工程目录的bootimage文件下可以看到生成的BOOT.bin、hello_world.bif、test.nky三个文件,如下图示:
我们把加密的BOOT.bin拷贝到SD卡,按步骤3可以看到系统不能起来没有hello world打印。
6、烧写密钥到Zynq器件上,前面已经分析了MYD-C7Z010/20开发板只支持SD卡启动模式和QSPI启动模式这两种模式,要访问JTAG只能在非加密模式下, 所以我们第一步是先用QSPI启动为非加密模式,然后用JTAG烧写密钥到Zynq器件的BBRAM内,由于MYD-C7Z010/20开发板没有备用电池来维持BBRAM的内容,这里我们不能掉电,只能把跳线帽重新设置为SD卡启动后按复位按键重新启动,为了防止带电插拔SD卡,需要在整个操作前把存储有加密的BOOT.bin 启动文件的SD卡先插上。
把开发板JP2和JP3断开跳线为QSPI启动模式,插上SD卡,连接好串口线和JTAG下载器,然后给开发板上电,双击桌面Vavido2018.3图标,选择打开硬件管理器,如下图示:
在硬件管理器界面点Open target后选择Auto Connect, 如下图示:
右键点击自动扫描出来的xc7z010器件选择Program BBR Key…, 在弹出界面选择第5步生成的test.nky密钥文件后按OK就会把密钥下载到器件上,如下图示:
然后把跳线帽JP2闭合,按RESET按键重新启动,这时是从SD卡启动,可以再次看到连续打印hello world, 如下图表示:
关闭电源后密钥消失,重新上电系统不能从SD卡驱动,验证了密钥和加密方法有效。再次用JTAG下载器连接器件提示没有找到器件,验证了加密启动状态下JTAG不可用。
四、主要参考文献
1、AES-256算法标准:“Advanced Encryption Standard (AES): FIPS PUB 197”, 2001
2、SHA256算法标准: “Secure Hash Standard: FIPS PUB 182-2”, 2002
3、HMAC算法标准:“The Keyed-Hash Message Authentication Code (HMAC): FIPS PUT 198”,2002
4、XILINX: UG585(V1.12.2)- Zynq-7000 SoC Technical Reference Manual
5、XILINX: UG470(V1.13.1)- 7 Series FPGAs Configuration User Guide
6、XILINX: UG821(V12.0) - Zynq-7000 All Programmable SoC SoftwareDevelopers Guide
7、XILINX: XAPP1175(V2.1) - Secure Boot of Zynq-7000SoC