STM32 BootLoader 刷新项目 (八) 读取Flash保护ROP-0x54
下面我们来介绍一下BootLoader一上电对芯片Option Byte操作的过程,Option Byte可以配置的功能包括**Read protection (RDP) **读出保护级别,**BOR级别(Brown-out Reset)**设置电压阈值,看门狗配置,Flash写保护。
在当今竞争激烈的市场中,软件供应商们正致力于开发具有自主知识产权的软件产品,尤其是那些在嵌入式系统中扮演关键角色的中间件产品。这些产品不仅需要具备高性能和稳定性,还需要确保其知识产权得到充分保护,以防止非法复制和滥用。随着基于微处理器的嵌入式产品对知识产权保护的需求日益增长,保护这些核心资产已成为供应商们的首要任务。
为了应对这一挑战,STM32系列微控制器(MCU)提供了一系列的安全特性,以帮助保护产品的知识产权。以下是STM32 MCU在知识产权保护方面的一些关键特性:
-
Read Protection (RDP):这是一种全面的芯片级保护机制,可以防止未经授权的读取操作。RDP能够限制对整个芯片的访问,包括Flash存储器、SRAM以及其他关键寄存器,确保只有授权的用户能够访问这些资源。
-
Write Protection:为了防止意外或恶意的擦除和编程操作,STM32 MCU提供了写保护功能。这项功能可以锁定Flash存储器的特定区域,防止未授权的写入,从而保护固件和配置数据不被篡改。
-
Proprietary Code Read Out Protection (PCROP):这是一种更为精细的保护机制,专门设计用来保护存储在Flash中的专有代码。与RDP不同,PCROP允许对Flash的特定区域进行读写保护,而不是整个芯片。这样,供应商可以保护包含关键算法和知识产权的代码段,同时仍然允许其他区域的代码进行正常的读写操作,便于进行后续的二次开发和维护。
PCROP的引入为STM32 MCU的用户带来了更多的灵活性和安全性。通过将关键代码放置在受PCROP保护的区域,供应商可以确保这些代码不会被轻易读取或复制,从而保护其知识产权不受侵犯。此外,PCROP还支持对代码的执行,这意味着受保护的代码可以被执行,但无法被读取或修改,这为嵌入式系统的安全性提供了额外的保障。
ST公司在其多个STM32产品系列中都集成了PCROP功能,包括但不限于STM32L1、STM32F4、STM32L4、STM32F7和STM32H7等。这些产品线的广泛支持表明了ST公司对于知识产权保护的重视,以及其在提供安全解决方案方面的承诺。
为了充分利用这些保护机制,软件供应商需要在设计和开发过程中采取相应的措施。这包括在编译和编程阶段正确配置RDP和PCROP,以及在产品发布前进行彻底的安全测试。通过这些努力,供应商可以确保他们的产品在面对日益复杂的安全威胁时,仍然能够保持其知识产权的安全和完整。
1. Option Byte介绍
STM32F407的Option Byte是STM32微控制器内部Flash中的一块特殊区域,用于存放一些配置信息。这些配置信息在每次上电复位时通过Option Byte Loader (OBL)读取,并写入到Flash的5个寄存器中,从而影响微控制器的行为。以下是STM32F407 Option Byte的一些详细介绍:
-
Option Byte区域位置:Option Byte位于STM32内部Flash的0x1FFF 7800地址处。
-
Option Byte的作用机制:每次上电复位时,微控制器会自动读取Option Byte区域的配置,并将其加载到特定的寄存器中,从而影响系统的行为。
-
Option Byte的配置内容:Option Byte可以配置的项目包括:
- 读出保护级别(RDP):可以设置不同的读出保护级别,以保护程序不被非法读取或篡改。
- BOR级别(Brown-out Reset):设置电压阈值,当电源电压下降到该阈值以下时,微控制器会自动复位。
- 看门狗配置:可以选择硬件看门狗或软件看门狗,并配置看门狗的行为。
- IWDG和WWDG的启动模式:配置看门狗在sleep/stop/standby模式下是否关闭。
- Flash写保护:可以设置Flash的写保护区域,防止非法写入。
-
编程Option Byte:编程Option Byte需要谨慎,因为一旦写入,更改较为困难。通常需要使用STM32的HAL库函数或直接操作Flash寄存器来完成。
-
Option Byte的安全性:Option Byte提供了一种保护机制,可以锁定微控制器,防止未授权的读取和写入,这对于保护知识产权和系统安全非常重要。
-
RDP的回归:如果需要从较高的读出保护级别降低到较低级别,会触发一次全Flash的擦除,因此在实施RDP回归功能时需要特别注意。
以上是STM32F407 Option Byte的一些基本介绍和配置信息,具体的配置方法和细节可以参考STM32F407的官方参考手册。
2. ROP 读保护Read protection
STM32F407的Option Byte中的RDP(Read-out Protection)是用于保护微控制器内部Flash存储器不被非法读取的一种安全特性。以下是RDP的详细介绍:
-
RDP保护级别:
- Level 0(无保护):RDP设置为0xAA时,没有启用读出保护。这是默认的设置,允许对内部Flash和备份SRAM的完整访问权限,包括通过调试接口的访问。
- Level 1(使能读写保护):除了内部Flash自举的情况外,任何尝试从外部访问内部Flash和备份SRAM的操作都被禁止,包括使用调试器或从内部SRAM自举时的读写和擦除操作。如果需要从Level 1降级到Level 0,需要将RDP重新设置为0xAA,但这会导致内部Flash和备份SRAM的内容被自动擦除,因此原Flash中的代码会丢失。
- Level 2(禁止调试):这是最高级别的读保护,一旦设置,无法再降级。它会永久禁止用于调试的JTAG接口,相当于物理熔断。设置为0xCC时,启用Level 2保护。
-
RDP的配置和修改:
- 要修改RDP的值,需要通过编程Option Byte来实现。这通常涉及到擦除Option Byte区域,然后写入新的RDP值。需要注意的是,一旦RDP被设置为非0xAA的值,就启用了读保护,此时无法通过调试接口访问内部Flash和备份SRAM。
- 在降级RDP级别时,从Level 1降到Level 0会导致内部Flash和备份SRAM的内容被擦除,因此这是一个不可逆的过程,需要谨慎操作。
-
RDP的安全性:
- RDP提供了一种防止未经授权的代码读取和复制的机制,这对于保护知识产权和系统安全至关重要。在产品发布时,启用RDP可以防止竞争对手或恶意用户通过读取Flash内容来复制或篡改程序。
-
RDP的注意事项:
- 在编程Option Byte后,需要重启微控制器以使新的RDP设置生效。一旦RDP被设置为Level 1或Level 2,就无法再通过调试接口进行访问,除非降级到Level 0,但这样做会丢失所有内部Flash的内容。
剩下还有STM32的其他Option Byte介绍,由于和本篇文章的内容不相关,后续大家可以自己阅读芯片手册。
3. 命令0x54介绍
在本篇文章,我们的主要是介绍0x54的命令,这个命令主要是读取STM32目前flash的保护等级。
通过上位机发送6 Byte的数据,其中第1 Byte为整个数据的长度,第2Byte为指令码,第3-6 Byte为前2个Byte的CRC校验值。上位机通过串口UART发送给下位机,下位机回复RDP 读保护的状态。
下面是整个程序执行读取RDP命令的流程图:
4. 程序设计
下面我们来进行程序设计,下面是读取上位机指令,并解析指令的过程,通过switch case判断执行哪种命令。
void bootloader_uart_read_data(void)
{uint8_t rcv_len=0;printmsg_Host("BL_DEBUG_MSG: Receive CMD\n\r");while (1){HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_RESET);memset(bl_rx_buffer, 0, 200);//here we will read and decode the commands coming from host//first read only one byte from the host , which is the "length" field of the command packetHAL_UART_Receive(C_UART,bl_rx_buffer,1,HAL_MAX_DELAY);rcv_len= bl_rx_buffer[0];HAL_UART_Receive(C_UART,&bl_rx_buffer[1],rcv_len,HAL_MAX_DELAY);switch(bl_rx_buffer[1]){case BL_GET_VER:bootloader_handle_getver_cmd(bl_rx_buffer);break;case BL_GET_HELP:bootloader_handle_gethelp_cmd(bl_rx_buffer);break;case BL_GET_CID:bootloader_handle_getcid_cmd(bl_rx_buffer);break;case BL_GET_RDP_STATUS:bootloader_handle_getrdp_cmd(bl_rx_buffer);break;default:printmsg("BL_DEBUG_MSG:Invalid command code received from host \n");break;}}
}
下面是过去rdp保护的函数,如果CRC校验正确,则进入到get_flash_rdp_level()的函数,获取RDP的Level。
/*Helper function to handle BL_GET_RDP_STATUS command */
void bootloader_handle_getrdp_cmd(uint8_t *pBuffer)
{uint8_t rdp_level = 0x00;printmsg("BL_DEBUG_MSG:bootloader_handle_getrdp_cmd\n");//Total length of the command packetuint32_t command_packet_len = bl_rx_buffer[0] + 1 ;//extract the CRC32 sent by the Hostuint32_t host_crc = *((uint32_t * ) (bl_rx_buffer + command_packet_len - 4) ) ;if (! bootloader_verify_crc(&bl_rx_buffer[0], command_packet_len-4, host_crc)){printmsg("BL_DEBUG_MSG:checksum success !!\n");bootloader_send_ack(pBuffer[0], 1);rdp_level = get_flash_rdp_level();printmsg("BL_DEBUG_MSG:RDP level: %d %#x\n",rdp_level,rdp_level);bootloader_uart_write_data(&rdp_level, 1);}else{printmsg("BL_DEBUG_MSG:checksum fail !!\n");bootloader_send_nack();}
}
下面是读取Option Byte的0x1FFFC000地址的高八位,其为RDP Level的等级。
/*This function reads the RDP ( Read protection option byte) value*For more info refer "Table 9. Description of the option bytes" in stm32f446xx RM*/
uint8_t get_flash_rdp_level(void)
{uint8_t rdp_status=0;volatile uint32_t *pOB_addr = (uint32_t*) 0x1FFFC000;rdp_status = (uint8_t)(*pOB_addr >> 8) ;return rdp_status;
}
5. 实操演练
下面是上位机的命令菜单,上位机链接下位机的串口号,即可进入命令界面:
在上位机中输入命令4,即为获取RDP状态命令0x54,MCU根据读取Option Byte中0x1FFF C000地址中的值,来告诉上位机当前读保护处于什么状态,由下图可以看出,当前状态为0xAA,处于为保护状态。
5. 系列文章
STM32 BootLoader 刷新项目 (一) STM32CubeMX UART串口通信工程搭建
STM32 BootLoader 刷新项目 (二) 方案介绍
STM32 BootLoader 刷新项目 (三) 程序框架搭建及刷新演示
STM32 BootLoader 刷新项目 (四) 通信协议
STM32 BootLoader 刷新项目 (五) 获取软件版本号-命令0x51
STM32 BootLoader 刷新项目 (六) 获取帮助-命令0x52
STM32 BootLoader 刷新项目 (七) 获取芯片ID-0x53