欢迎大家关注STM32L5课程。本期我们会介绍STM32L5的内核,Cortex-M33。它是ARM在MCU架构上增加了TrustZone这个安全扩展的一种内核实现。
从这一期开始,我们进入技术部分的学习。L5快速入门,会由5期的介绍组成,会着重讲解L5的TrustZone安全扩展。除此之外,L5新增了内置SMPS,进一步提高平台的低功耗特性。
Cortex-M33内核
Cortex-M33,在以往传统的Cortex-M系列内核基础上最大的扩展是新增对TrustZone的支持:从硬件实现角度来说,内核会新增一些外设,并且原来已有的外设也做了相应更新,来支持TZ。从用户角度,即编程模型来说,一方面有新增寄存器、新增指令需要操作,另一方面在中断响应机制、存储区映射上都有新的概念提出,需要开发者理解和运用。
近些年,ARM在MCU领域的内核架构设计,从V6-M、V7-M到V8-M,实现了丰富的内核软IP。从入门型的CM0、CM0+内核,到主流型CM3、CM4、CM7内核,再到支持TrustZone安全扩展的CM33内核,ST都有具体的产品线。
这两年主推的新产品,G0、G4、WB、WL,还有新一代H7,都是基于V6-M和V7-M架构。STM32L5是ST首款基于CM33内核的MCU产品。
通常意义来讲,CM33可以看做是CM4内核基础上新增了TrustZone安全扩展。那么我们接下来看看具体有哪些新增的功能和特性。
CM33内核比CM4内核新增和改进的地方,是图中绿色高亮出来的部分。
对TrustZone的支持,内核会引入“安全状态” 和“非安全状态”的概念,硬件方面,SAU和IDAU是随着新增的硬件单元。TrustZone是Cortex M33内核的一个可选模块,STM32L5实现的CM33内核是包括了TZ的。L5的用户可以通过选项字节,来设定是否使能这个内核的安全扩展。
堆栈溢出检查,在CM33内核里新增了额外的堆栈指针stack limit,分别指向MSP和PSP堆栈空间最后一个地址。因为Cortex-M内核的堆栈定义,是向下生长的,因此堆栈空间的尽头就是最小的那个地址。当CPU执行某条指令,导致当前堆栈指针越过了stack limit的值,会触发内核异常,exception。
Enhanced debug,配合TrustZone扩展,可以仅开放用户对非安全代码的调试
NVIC,在CM33内核支持更多的用户中断线。我们的STM32L5上目前可以产生109条用户中断。最重要的是,为了配合TrustZone安全扩展,CM33内核里的NVIC可以把内核异常(Core exception)和用户中断(interrupt),target到安全状态或者非安全状态的中断处理函数中。“中断的retarget” 这个概念很新,后面讲到内核中断时,我们会展开来说。
新一代MPU,基于PMSA v8架构,以前是v7架构。v8架构给用户带来的最为便利之处在于,对MPU管理的区域的范围设置更加灵活。后面专门有一页会来讲。
AHB总线,从AHB lite升级到AHB 5,总线上会新增额外的信息,来指示当前CPU访问的安全状态。
第一次接触CM33内核,或者TrustZone的概念,大家可能会对刚才提到的诸多新概念有点懵,什么SAU、IDAU,什么叫做CPU访问的安全状态,什么叫做中断target到安全状态或者非安全状态。如果现在你觉得听得有点一头雾水的感觉,没有关系,后面我们对这些概念,都会掰开揉碎,结合实例来展开阐述。
现在我们先来理解什么是TrustZone,什么是安全世界和非安全世界 。
TrustZone
什么是 TrustZone?它是一个和安全相关的概念。
大家还记得2008年北京奥运会的口号吗? “One World One Dream” ,同一个世界,同一个梦想。
TrustZone的概念,用类似的语言来表达,就是:one CPU, two world。这里的two world,两个世界,就是指的安全世界和非安全世界,它们同时存在于同一颗芯片上,但是物理机制又保证了两个世界有可靠的隔离。人类命运共同体,要求我们要有同一个世界同一个梦想的理念;但是从信息安全的角度,两个隔离的世界,是信息安全的基石保证。最近大家的生活,相信也已经深刻体会到了“隔离”机制,对安全的重要意义。
基于具有隔离能力的硬件基础,我们在其上设计应用程序时,就可以把软件分成两部分: >> 可信的软件和普通软件。可信的软件,通常经过严格的code review,甚至经过实验室的审查和认证,因为它要访问关键资源,比如敏感数据,敏感外设模块。什么是敏感数据,加解密操作用到的密钥、用户的隐私数据,通常是具有Confidentiality安全属性的资产,是我们要极力保护其“Confidentiality” 和,或者“Integrity” 安全属性的资源。敏感模块,通常是连接到外部关键设备的,比如控制门禁的制动器。 >> 普通软件,是用户应用中的另外一个组成部分,刨去了可信软件的,其余的都算在普通软件里面。
TrustZone的基本原则,就是把应用中的关键操作代码,和其他应用程序隔离开来,避免恶意应用程序的攻击,或者由于应用程序本身的设计漏洞,对敏感操作代码的攻击。
如果大家以前有接触过Cortex-A架构上的TZ,那么L5上Cortex-M架构上的TZ和它概念上是差不多的,不同的地方在于M架构上的TZ是通过memory map来划分两个世界各自的地盘,CPU在两个世界执行时,其安全状态的切换是硬件自动完成的,这一点是最大的区别所在。
如果大家以前没有接触过TZ的概念,那么现在你可以暂时理解为一个芯片上有两个物理隔离开来的区域,分别存放安全程序、敏感资源,以及普通程序,普通资源。
Flash就那么一块flash,ram就那么一块ram,以往那些GPIO、RTC、DMA外设,如何区别哪些flash和ram区域,哪些外设是安全的;哪些又是不安全的呢?一颗CPU又是如何在两个世界进行切换的呢?
我们先来回答第一个问题:如何划分“安全世界”和“非安全世界”各自的地盘呢? 答案是按照4G地址空间里的地址范围来区分。可以设定哪些地址空间,在内核看来是安全的世界;哪些地址空间,在内核看来是不安全的世界。执行安全世界的代码时,CPU自己处于安全状态;执行非安全世界的代码时,CPU自己处于非安全状态。
处于安全状态的CPU,从内核看来,是可以访问所有资源的,无论这个资源是在安全世界里,还是非安全世界里。而处于非安全状态的CPU,从内核看来,只能访问非安全世界里的资源。注意,以上这几句话,多次出现了“在内核看来”这五个字的限定语。内核通过寄存器SAU,和IDAU模块, 把地址范围划分出来,那么所有看到的或者认为的安全还是不安全的地址,都是从内核看出去的视角。
内核看出去的视角,具体哪些区域是安全的世界,哪些是非安全世界,由SAU和IDAU一起定义。SAU是内核里面的一个模块,用户可以通过寄存器来配置。它有点类似MPU,可以通过起始和结束地址设定几个区域的范围,然后执行该区域是安全世界还是非安全世界。IDAU在内核之外,是芯片在实现时,就由芯片厂家设置好的安全属性控制模块,一般不对用户开放设置。它们分别就是左边图里,两个蓝色的方框,Security Attribute Unit,就是SAU;System level control就是IDAU。
根据CPU要访问的地址,SAU和IDAU根据目标地址的安全属性,以及当前CPU的安全状态,会决定该访问的transaction,是否批准,如果批准的话,这个transaction的安全属性如何?是安全transaction,还是非安全transaction?
根据不同的安全属性,由不同的MPU来进一步审查该transaction,是否符合受该MPU管理的目标地址所在区域的访问控制。比如,经过SAU和IDAU的判断,这是一个安全的取指令的transaction,那么Secure MPU就会看目标地址所在的区域是否可执行,如果是XN,execute never,该transaction就被Secure MPU给block住,就不会走到下一步,到AHB总线上了。如果这个安全的取指令transaction,在Secure MPU检查后放行,那么这个secure的transaction就可以来到AHB总线上了。这也是为什么我们会在左边的图里,看到两个MPU模块的原因。这也正是CM33内核为支持TrustZone安全扩展而新增的内核模块。
需要注意的是,对4G地址空间的安全属性设置,只能在安全世界执行。而CM33内核,如果支持并使能了TrustZone这个安全扩展,上电启动的时候,内核是在安全状态,即上电时的启动地址,是默认处于安全世界的。
IDAU,全名:implementation defined attribute unit。用户拿到一颗芯片时,IDAU的配置已经由芯片厂家设置好了。
它设置了哪些区域是Secure的;哪些是NSC,NSC是Non-securable callable的简称;哪些区域是Non-secure的。NSC区域也属于安全世界,执行NSC区域的代码时,CPU是处于安全状态的。IDAU的设置属于上电即生效的。由于是芯片厂家的设置,它的粒度比较粗,是以64MB为最小单位。每个厂家的设置可能稍有不同。
SAU,全名:security attribute unit。它是CM33内核的一个模块,有寄存器供用户在上电后编程设置。这提供给用户一个机会,来按照自己的意愿对4G空间上的自己选择的8个区域做精确的安全属性调整。大家查看内核SAU寄存器可以发现:SAU所设置的区域的起始地址,只要是32字节对齐即可,区域大小最小粒度可以精确到32字节。
当同一个区域范围,被SAU和IDAU定义了不同的安全属性,则取安全性要求更高的那个属性。显而易见,Secure高于NSC,NSC又高于Non-secure。
如图所示:0x0c00 0000到0x1000 0000这个范围内的区域,IDAU定义的是NSC属性,而SAU把其中的高地址部分定义成Secure属性,那么二者共同作用后,这段区域就选取安全性更高的Secure这个属性。
这里再次强调一下,就算最后IDAU和SAU共同定义出了一个区域的安全属性,那也仅仅是从CPU内核看出去的,这个目标地址是安全还是非安全地址。实际上这个地址,如果是落在flash或者ram的某个区域,或者是落在某个外设寄存器身上,这个地址本身是安全还是不安全的,要看实际物理实现它的flash、ram或者外设的设置。这个是每个芯片厂家各自发挥的舞台了,我们的STM32L5是怎样的,会在下一集来讲。
TrustZone 技术,在一个单独的芯片上,按照地址,实现了两个世界,安全世界和非安全世界。但是一个地址,它的安全属性,却有三种。前一页已经提到过了,分别是Secure,Non-Secure callble,和 Non-secure。前面两个都是绿色标识的,按照我这节胶片里的 color legend,应该知道,都是属于安全世界的。Secure 属性的区域里面放置经过code review的可信软件,执行涉及敏感数据或者敏感外设的关键操作。Non-secure属性的区域里,放置普通应用软件,这很好理解。那么为什么还有一个同属于安全世界,但是安全属性定义是NSC的区域呢?
原因就是,TZ隔离出来安全和非安全两个世界,两个世界的代码可以互相调用。安全世界可以随意调用非安全世界的代码,谁要人家安全等级高呢。而CPU在非安全世界里的执行的时候,要调用安全世界的代码,就不是那么随意了。调用是可以调用,但是只能调用安全世界给你展现出来的API。比如,安全世界里有10个函数,但是只有2个是export出来可以给非安全世界调用的,如图里的Sec_ABC_API和Sec_XYZ_API。另外,非安全世界,即左边红色框里的程序,是不能直接调用右边深绿色区域,即Secure区域的这两个API,必须要先执行一条指令:SG。SG是secure gate的简称。顾名思义,它是作为安全世界的大门。要从非安全世界进入安全世界,必须走这个大门进,因此CPU从非安全世界进入安全世界,执行的第一条指令,一定要是SG。而SG指令作为操作码,无非也就是32位或者16位的01序列,为了防止其他二进制数据,比如具有与SG指令的操作码相同值的查找表,被用作安全状态的入口函数,因此定义出这样一个NSC区域,里面就是放SG指令和随后的跳转指令。
说到 IDAU,它除了是芯片厂家给4G地址空间,粗粒度地预先设置了区域的安全属性的作用之外,它还给带来一个好处,就是大大减轻了SAU区域个数的负担。SAU会影响CPU的速度,因此SAU区域的个数,不是越多越好。大多数芯片厂家在实现芯片时,把SAU的个数定义在8,也是一个权衡的结果。如果没有IDAU,我们来想象一下。按照以往ARM内核的存储空间定义,0x2000 0000 到0x4000 0000这块区域是SRAM。SRAM通常是BB属性,即block base的存储器件,可以按照每个page,独立定义其安全属性。如果一个应用,需要芯片上的SRAM,比如256K,每个page 2K,间隔地具有安全、非安全、这样的属性配置。如果紧靠SAU来设置,就需要N=128个region,N等于SRAM的page数目。这是远远大于8这个数字的。
有了IDAU,芯片厂家可以预先对几个大区域进行设置,如图所示。以往的Code区域,512M空间,平分两半。低地址部分,定义成NS,高地址部分定义为S。对SRAM和外设,也是如此。N个page的这块SRAM,它物理上就只有这么一块SRAM,它的默认地址是0x2000 0000开始。但是它有一个别名区,是从0x3000 0000开始。从0x2000 0000和从0x3000 0000去访问,都是访问的同一个物理地址,即这一块物理SRAM的首地址。但是访问transaction本身的安全属性,从CPU看来是不同的。
在这样的情况下,再来看,刚才同样的用户应用需求,需要芯片上SRAM,每个page,间隔具有安全和非安全属性。SAU只需要设置2个region,分别cover到从0x2000 0000开始到0x2003 FFFF这个区域,和从0x3000 0000开始到0x3003 FFFF的区域即可。
只需要从低地址访问page1/3/5/7,从高地址访问2/4/6,从CPU看来,就能对每个page间隔,有不同的访问安全属性。 如果大家现在听得还是有点糊涂,没有关系,后面我们会结合STM32L上真实的物理SRAM,和物理Flash,在hands-on环节,具体来体会。
|