实战CRC校验 | 固件如何校验自身完整性?

来源:公众号【鱼鹰谈单片机】

作者:鱼鹰Osprey

在一些比较严格的行业里面,不是说你的程序能完成必要功能就可以,还需要添加一些额外的功能,比如最常见的看门狗功能,它可以在程序死机时完成重启,但也仅仅如此而已。很多异常它是无法检查的,比如程序偶然跑飞,ram 异常、flash异常等其他问题,只有程序hardfault或者其他严重问题导致程无法喂狗时才能起作用。

所以有些产品为了保障安全,会增加安规代码,保证程序能够正常运行(UL/CSA/IEC 60730-1/60335-1 B类认证)。

自检内容

MCU 安全检查一般包括以下几个方面:

1、CPU 自测(寄存器测试)
2、系统时钟频率测量(保证时钟正常工作,不快也不慢,GD 芯片在短路晶振后,程序暂停运行,无法检查,但是 ST 芯片会自动切换到内部时钟,可以由程序检查这种异常)
3、RAM 自检
4、FLASH 存储器完整性检查
5、独立看门狗、窗口看门狗检查
6、安全相关变量检查
7、中断检查
8、I/O 口检查
9、栈检查
10、程序流程控制
11、AD 口检查

你会发现真要完成这份安规代码,难度不是一般的大,不过一般芯片厂商会提供相关参考例程和相关文档,但不是说有了这些资料就完全没有问题了。

比如 ST 提供了一个参考例子,但是它使用的 HAL 库(事实上它还有标准库,当时不知道),如果原本程序用的标准库,那么就需要进行移植,这个工作量也不是一般大(首先要能理解程序,才能进行正确移植,而里面的逻辑还是很复杂的)。如果你不想移植,还有一个办法是使用 lib 库,就是将相关功能打包成一个库,虽然程序会大一些(毕竟很多底层代码和原来的重复了),但确实是比较简单的方法(前提是 flash 够大)。

鱼鹰走的是第一条路,移植,并且将相关的底层代码提供了接口,这样不管是用标准库还是 HAL 库,只要自己实现这这些特定的接口即可完成。

另外,参考例子只是实现了一个最基本的功能,在真正的产品不一定能适用。比如你的程序负载大,而里面为了测量时钟频率,几百微秒时间就要进入一次中断(即使是分频后),如果刚好在中断产生时,其他程序禁用了中断,运行这些代码有可能就会出现问题,很容易错过中断而导致复位。

在我一开始移植的时候就是如此,在一个简单的程序里面可以正常运行很长时间,但是移植到产品工程里面,时不时出现时钟检查不通过的时候,导致程序不停重启,最终鱼鹰通过 DMA 传输的方式解决了这个问题,再也不会因为时钟检查不通过导致重启了。

另外一个难点是对 .sct (分散加载)文件的理解,这个会在后面介绍。

安规相关的内容实在是太多,要写的话可以写成一个系列了,如果各位道友感兴趣的话,多多转发支持一下鱼鹰,如果效果不错,鱼鹰会考虑完成后续的其它部分。(这里有一份比较全面但简单一些的参考文章可以看看 http://news.eeworld.com.cn/mp/STM32/a80041.jspx,只介绍如何做,没怎么介绍为什么这么做)

资料

ST 相关资料可以查看以下内容(www.st.com,下载时需要注册邮箱才行,鱼鹰公众号后台提供了部分资料,可自行领取)

《AN4435 应用笔记》中文版,《AN277》(ROM Self-Test)
STM8-SafeCLASSB
https://www.st.com/en/embedded-software/stm8-safeclassb.html

STM32-CLASSB-SPL(基于标准外设库)
https://www.st.com/en/embedded-software/stm32-classb-spl.html#tools-software

X-CUBE-CLASSB(基于HAL库)
https://www.st.com/en/embedded-software/x-cube-classb.html(不同版本有不同芯片,比如 2.2.0 版本的是 Fx 相关的,2.3.0 是H7、G0 相关的)

当然国产芯片也一般会提供例程。

本篇笔记只介绍其中一个内容,即 FLASH 检查,换句话说就是程序完整性检查。

FLASH 检查

我们以比较复杂的 boot + app + rtos ,开发环境 keil 、stm32f103 为例介绍相关知识。

一般 boot 和 app 部分是用不同工程管理的,所以 app 部分代码只能检查自身的完整性,而不能检查 boot 部分。

并且 app 的 flash 区也不是完全检查的,有一小部分是也没法检查的,但这并不影响它的功能(既然已经跳转到 app 里面了,那么 boot 部分 flash 即使在运行时有问题也不影响功能,而如果变量初始值的flash有问题就是关键变量检查的问题了)。

现在就是如何检查的问题了。

如何检查 | 基本原理

校验手段有很多,比如 和校验、MD5 校验、CRC 校验,这里我们使用 CRC,因为一般芯片内部会内置该外设硬件计算(如果没有,可以纯 CPU 计算)。

然后我们需要了解完整性检查的基本原理。

所谓程序完整性检查,就是在下载代码前,先用工具把要校验的部分通过计算公式计算出一个值,保存在某个地方(flash),然后程序在运行的时候,自己也去读取要校验的 flash 部分,通过同样的计算公式计算出一个值,然后将这个值和保存在 flash 里面的值进行比较,就可以看出代码是否存在异常了,有异常及时处理,没有异常就继续重新检查。

而检查分成两个步骤:

1、开机时,一次性完成所有计算,保证运行前完整。

2、正常运行时,定时计算,每次计算一个小块,当计算完最后一块时才比较结果,成功就重新继续计算,失败则终止程序运行,周而往复(计算需要较长的时间,分时计算可以不影响程序正常功能),这样可以保证程序在运行时也能检查 FLASH 的完整性,防止 FLASH 运行过程中破坏掉。

现在有个问题,CRC 保存在何处才是合适的?

随便保存在一个地方肯定是不行的。假设这个位置在要校验代码部分的里面,那么当工具计算这个值时,又会篡改掉校验部分里面的数据(因为你把 CRC 值放到里面了),那么你的程序校验时,肯定不通过,因为你读了一个被改变的 CRC 值。所以这个值一定要放在代码的最后面才行。

另外前面说过,运行时会一小块一小块,所以要保证你的 CRC 值存放位置应该在小块大小的边界位置上。比如一次计算 16 字节,那你存放的位置应该是 16 的倍数才是正常的。

所以,CRC 存放位置存在这两个限制。

另外,如何提前计算好 CRC 的值呢?IAR 内置该功能,而 KEIL 我们可以借助强大的开源工具 SRecord《功能强大的 HEX 开源转换工具,你值得拥有》(一转眼,这篇文章差不多鸽了四个多月了)帮助我们计算。

基本知识都了解的差不多了,接下来就是如何操作的问题。

实操

1、固定 CRC 位置。

我们可以在启动文件的最后加入以下代码(END 前)

这里默认是 0x3D334398,但会在后续修改成正确的 CRC 值

;*******************************************************************************; User Checksum - must be placed at the end of memory;*******************************************************************************                AREA    CHECKSUM, DATA, READONLY, ALIGN=6                EXPORT  __Check_Sum
; Alignement here must correspond to the size of tested block at FLASH run time test (16 words ~ 64 bytes)!!!                ALIGN
__Check_Sum     DCD     0x3D334398;                  ; Check sum computed externaly

这里保证了 __Check_Sum 的地址是 2 ^ 6 大小对齐,所以你的计算小块可以这个大小,当然也可以小一些,比如 2 ^ 5 等。这样就可以将检查部分分成固定的小块,不会多,也不会少,刚刚好(必须)。

那么如何将这个地址固定在代码最后呢?这个时候就需要我们的 .sct 文件发挥作用了(ClassB_stm32F10x.sct)。

ER_IROM1 0x08000000 0x10000  {  ; load address = execution address*.o (RESET, +First)*(InRoot$$Sections).ANY (+RO)*.o (CHECKSUM, +Last) ;放置在最后}

我们用了 +Last 将其放置在代码的最后部分,你想把它放置在 bin 文件最后面?暂时鱼鹰还没想到怎么做,有知道的道友可以告诉鱼鹰(通过 sct 的方式)。

2、CRC 计算脚本
在 windows 叫批处理,.bat ,我们可以在参考例程中找到。crc_gen_keil.bat

我们需要需改三个位置

第一个是你的计算工具的路径,里面应该要有计算工具。

第二个就是你的工程名字,我们通过下面位置确定(鱼鹰用的 Main):

最后是工程路径。一般在 Objects 文件夹里面,而 map 文件一般在 Listings 文件夹里面。

说白了,这些变量就是为了让脚本能够找到 map、hex 文件和工具。但一般默认工程,这两个文件可能不在一个文件夹里面,所以我们可以对例子中的批处理文件 crc_gen_keil.bat 进行适当修改。

map 文件的作用是为了让脚本能够搜索到 __Check_Sum 的地址,然后就可以计算 CRC 并修改 HEX 里面这个值了。

另外还有新增了一个变量 HEX_ADRR,当我们的计算位置不是从 0x08000000 开始时(比如 app 起始地址在 0x08009000),我们就可以修改这个变量值。还有我们希望在计算完并修改 CRC 后可以自己生成 bin 文件方便我们更新固件,还需要加入转化成 bin 的命令。

其中为了下载修改(CRC)后的 HEX 文件,我们还需要简单修改一下,用于判断工具是否存在,不存在,直接删除 hex 和 axf 文件(防止下载未修改的文件)。
%xxx% 类似脚本中的 $xxx

if not exist %SREC_PATH% (echo %SREC_PATH% is not exit, exitecho ----------------------------------------del %INPUT_HEX% -- %AXF_FILE% ---------------del %INPUT_HEX% %AXF_FILE%exit
)

这样可以保证,一定能够正确下载 HEX 文件,而不是下载默认的 axf 文件。
否则,下载的默认 axf 文件会因为 CRC 未修改,程序将不断重启。
完整的修改(可以自行对比官方例程文件):

@echo offECHO Computing CRCECHO -------------------------------------REM Batch script for generating CRC in KEIL projectREM Must be placed at MDK-ARM folder (project folder)
REM Path configurationSET SREC_PATH=C:\SRECSET MAP_NAME=STM3210C_EVALSET MAP_PATH=STM3210C_EVALSET TARGET_NAME=STM3210C_EVALSET TARGET_PATH=STM3210C_EVALSET BYTE_SWAP=1SET COMPARE_HEX=1SET CRC_ADDR_FROM_MAP=1REM Not used when CRC_ADDR_FROM_MAP=1SET CRC_ADDR=0x08007ce0
REM Derived configurationSET HEX_ADRR=0x08000000SET MAP_FILE=%MAP_PATH%\%MAP_NAME%.mapSET AXF_FILE=%TARGET_PATH%\%MAP_NAME%.axfSET INPUT_HEX=%TARGET_PATH%\%TARGET_NAME%.hexSET OUTPUT_HEX=%TARGET_PATH%\%TARGET_NAME%_CRC.hexSET OUTPUT_BIN=.\%TARGET_NAME%_CRC.binSET TMP_FILE=crc_tmp_file.txt
if not exist %SREC_PATH%\srec_cat.exe (    echo %SREC_PATH% is not exit, exit    echo ----------------------------------------del %INPUT_HEX% -- %AXF_FILE% ---------------    del %INPUT_HEX% %AXF_FILE%    exit)
IF NOT "%CRC_ADDR_FROM_MAP%"=="1" goto:end_of_map_extractionREM Extract CRC address from MAP fileREM -----------------------------------------------------------REM Load line with checksum location to crc_search variableECHO Extracting CRC address from MAP fileFINDSTR /R /C:"^  *CHECKSUM" %MAP_FILE%>%TMP_FILE%SET /p crc_search=<%TMP_FILE%DEL %TMP_FILE%REM remove '(' character and string after, which causes errorsfor /f "tokens=1 delims=(" %%a in ("%crc_search%") do set crc_search=%%aREM remove CHECKSUM string from variableSET crc_search=%crc_search:CHECKSUM=%REM get first word at line, which should be CRC address in HEX formatfor /f "tokens=1 delims= " %%a in ("%crc_search%") do set CRC_ADDR=%%aREM -----------------------------------------------------------REM End of CRC address extraction:end_of_map_extraction
REM Compute CRC and store it to new HEX fileECHO CRC address: %CRC_ADDR%if "%BYTE_SWAP%"=="1" (REM ECHO to see what is going onECHO %SREC_PATH%\srec_cat.exe ^  %INPUT_HEX% -intel ^  -crop %HEX_ADRR% %CRC_ADDR% ^  -byte_swap 4 ^  -stm32-b-e %CRC_ADDR% ^  -byte_swap 4 ^  -o %TMP_FILE% -intel  %SREC_PATH%\srec_cat.exe ^  %INPUT_HEX% -intel ^  -crop %HEX_ADRR% %CRC_ADDR% ^  -byte_swap 4 ^  -stm32-b-e %CRC_ADDR% ^  -byte_swap 4 ^  -o %TMP_FILE% -intel  ) else (REM ECHO to see what is going onECHO %SREC_PATH%\srec_cat.exe ^  %INPUT_HEX% -intel ^  -crop %HEX_ADRR% %CRC_ADDR% ^  -stm32-l-e %CRC_ADDR% ^  -o %TMP_FILE% -intel%SREC_PATH%\srec_cat.exe ^  %INPUT_HEX% -intel ^  -crop %HEX_ADRR% %CRC_ADDR% ^  -stm32-l-e %CRC_ADDR% ^  -o %TMP_FILE% -intel)ECHO %SREC_PATH%\srec_cat.exe ^  %INPUT_HEX% -intel -exclude -within %TMP_FILE% -intel ^  %TMP_FILE% -intel ^  -o %OUTPUT_HEX% -intel%SREC_PATH%\srec_cat.exe ^  %INPUT_HEX% -intel -exclude -within %TMP_FILE% -intel ^  %TMP_FILE% -intel ^  -o %OUTPUT_HEX% -intelREM Delete temporary fileDEL %TMP_FILE%ECHO Modified HEX file with CRC stored at %OUTPUT_HEX%
REM Compare input HEX file with output HEX fileif "%COMPARE_HEX%"=="1" (ECHO Comparing %INPUT_HEX% with %OUTPUT_HEX%%SREC_PATH%\srec_cmp.exe ^  %INPUT_HEX% -intel %OUTPUT_HEX% -intel -v)
del %INPUT_HEX%
ECHO %SREC_PATH%\srec_cat.exe ^  %OUTPUT_HEX% -intel -offset -%HEX_ADRR% -o %OUTPUT_BIN% -binary%SREC_PATH%\srec_cat.exe ^  %OUTPUT_HEX% -intel -offset -%HEX_ADRR% -o %OUTPUT_BIN% -binary
ECHO -------------------------------------

3、 CRC 计算部分代码(摘自官方例程)
完整计算


分小块计算

需要注意的是,每次全部检查完之后得复位一下 CRC 外设,否则会继续用之前的结果继续计算。

4、工程配置
准备好前面的内容后,即可进行工程配置。
生成 HEX

使用 debug 按钮时下载的文件:
crc_load.ini (需要根据自己的工程自行修改)

特别注意里面的双反斜杠,没有它,将找不到正确路径。这里以工程文件(.uvprojx)所在路径为相对路径。

使用 load 按钮时下载配置:

不然你下载(点击 load)的时候,就会下载默认的 axf 文件,而 axf 里面的 CRC 值也是默认的,并没有被修改,所以这一步也是必须的。

使用修改的分散加载文件,这可以保证我们的 CRC 存放位置在代码最后面。

最后一步,当编译完成后,让工具帮我们自动计算 CRC 值,并将值修改到 HEX 文件里面。

添加我们前面的批处理文件:

这样所有的工程配置就完成了。

效果

我们可以看看效果。

首先,我们并没有添加工具,我们可以看到,脚本自动退出了,并且删除了 hex 文件和 axf 文件,这样就不会下载错误的 HEX 文件了(点击下载会发现找不到 axf 文件)。

当我们在 C 盘添加工具后编译:

从这里我们可以得到几点信息:
1、计算范围 0x08000000 ~ 0x08007640。
2、CRC 存放位置在 0x08007640,四个字节
3、可以使用 srec_cmp.exe 比较两个 HEX 文件的区别(修改前和修改后)。这里的区别在 0x08007640 ~ 0x8007643。
4、生成的 bin 文件和 hex 文件相对存放路径。

大功告成!

工具命令解释

现在我们可以从这里了解到三个命令。

C:\SREC\srec_cat.exe   STM3210C_EVAL\STM3210C_EVAL.hex -intel   -crop 0x08000000 0x08007640   -byte_swap 4   -stm32-b-e 0x08007640   -byte_swap 4   -o crc_tmp_file.txt -intel

这个命令用于截取 0x08000000~0x08007640 的内容并计算 CRC 值,并且在 0x08007640 位置处写入 CRC 值。0x08007640 由 map 文件得出,即 __Check_Sum 的地址。

C:\SREC\srec_cat.exe STM3210C_EVAL\STM3210C_EVAL.hex -intel -exclude -within crc_tmp_file.txt -intel   crc_tmp_file.txt -intel -o STM3210C_EVAL\STM3210C_EVAL_CRC.hex -intel

该命令用于将两个 HEX 文件合并,如果以 crc_tmp_file.txt 文件为基准,即同一个地址的值如果不同,则保留 crc_tmp_file.txt 里面的(里面有正确的 CRC),-intel 代表 HEX 文件类型。

C:\SREC\srec_cmp.exe   STM3210C_EVAL\STM3210C_EVAL.hex -intel STM3210C_EVAL\STM3210C_EVAL_CRC.hex -intel -v

终于搞定啦,可以放下这个了。

—— The End ——


推荐阅读:

专辑|Linux文章汇总

专辑|程序人生

专辑|C语言

我的知识小密圈

关注公众号,后台回复「1024」获取学习资料网盘链接。

欢迎点赞,关注,转发,在看,您的每一次鼓励,我都将铭记于心~

嵌入式Linux

微信扫描二维码,关注我的公众号

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/465502.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

想一个颠覆性技术方向建议,你能想到什么?

如上图&#xff0c;是这次文章的主题。我对这个问题是有想法的&#xff0c;我现在是做音频研究&#xff0c;但是我觉得未来核心的方向一定是能源。试想一下&#xff0c;现在的手机功能越来越多&#xff0c;移动设备将会占领我们未来很长一段时间&#xff0c;那么手机的电池要如…

centos 安装idea 非可视化_太厉害了!目前 Redis 可视化工具最全的横向评测

转自&#xff1a;一入码坑深似海链接&#xff1a;www.jianshu.com/p/cb9f4dcb3b921. 命令行不知道大家在日常操作redis时用什么可视化工具呢&#xff1f;以前总觉得没有什么太好的可视化工具&#xff0c;于是问了一个业内朋友。对方回&#xff1a;你还用可视化工具&#xff1f;…

解决克隆clone github 仓库速度过慢的问题

解决克隆clone GitHub 仓库速度过慢的问题 由于大家都懂的原因&#xff0c;我们访问GitHub的速度确实有点慢&#xff0c;特别是克隆比较大的仓库的时候&#xff0c;那速度简直无法直视。 今天我就给大家带来一个邪门歪道&#xff0c;不通过FQ来解决速度问题。 先说结论吧&#…

聊聊身边的嵌入式,自拍神器自拍杆

曾几何时&#xff0c;自拍杆风靡世界&#xff0c;火当然是有原因的&#xff0c;这么一个小装备&#xff0c;极大的满足了人们爱拍照的需求&#xff0c;方便好用、经济实惠。恰巧我手上也有一个&#xff0c;收起来时很小、不占地方打开后可随意调节拍照同时它有个隐藏式三脚架功…

大恶人吉日嘎拉之走火入魔闭门造车之.NET疯狂架构经验分享系列之(十二)多语言支持...

虽然平时很少接触老外的项目、也很少碰到老外&#xff0c;但往往赚大钱的人是经常跟老外做买卖的人居多&#xff0c;他们大多需要网站是全英文的&#xff0c;我们往往上手有一个成熟的中文的网站或者软件&#xff0c;例如成熟的B2C网上购物系统&#xff0c;但是没办法也没精力再…

lisp用entmake生产圆柱体_德BBG公司开发用于CFRP储罐模块生产过程的自闭合HPRTM模具...

自主概念、足以批量生产、可以降低投资成本。每次操作最多可同时生产15个气瓶。照片来源&#xff1a;BBG机械制造商BBG GmbH&Co.KG(德国明德尔海姆)于9月16日提出了一种自动闭合高压树脂传递模塑(HP-RTM)模具的概念&#xff0c;该模具能够快速、重复地制造各种车辆用的紧凑…

【深度剖析】小米CyberDog四足机器人的AI运动系统的实现

2021年8月10日&#xff0c;雷军进行继宣布造车之后的第二次演讲。在这场以“我的梦想&#xff0c;我的选择”为主题的演讲上&#xff0c;雷军详细讲述了创业后的故事&#xff0c;发布了一系列全新产品。其中&#xff0c;给人最大惊喜同时也给人带来诸多疑问的就是我们这篇推文的…

变更控制管理流程图_制度是最好的老板,流程就是最好的管理!流程建立法则(附案例)...

为什么很多企业制定了战略&#xff0c;一线执行却没有到位&#xff1f;为什么员工办事拖拉&#xff0c;执行力不到位&#xff1f;为什么总有下属在等待老板分配任务&#xff0c;不能主动地去工作&#xff1f;为什么一些企业的老板处于很忙碌的的糟糕状态&#xff1f;上述这样问…

第二节:Css重写样式

一丶 进入浏览器---->F12----->找到要修改的区域的Style 进行重写Css样式 二丶打开新页面 window.open("/Persitent/OtherIndex?connectionId" connectionId,"_blank"); 转载于:https://www.cnblogs.com/chenze-Index/p/9309775.html

我的Linux内核学习笔记

在开始今天的内容之前&#xff0c;其实有一些题外话可以和大家分享一下。自从工作以来&#xff0c;我个人一直都有一个观点。那就是怎么样利用简单的代码来说明开发中的问题&#xff0c;或者是解释软件中的原理&#xff0c;这是一个很高的学问。有些道理看上去云里雾里说不清楚…

10 文件无效_新手必看!10个CAD常见问题解决技巧

对于很多刚接触CAD的萌新来说&#xff0c;学习过程遇到的问题总是很多。如果没有老师解答的话&#xff0c;上百度搜索也常常不得要领&#xff0c;所以今天为大家做了大概的问题总结&#xff0c;主要是以下几个问题&#xff1a;1多线段合并A&#xff0e;输入命令“PE”B&#xf…

TurboMail手机客户端—强大的附件文档阅读能力

2019独角兽企业重金招聘Python工程师标准>>> 对于频繁使用邮件的用户而言&#xff0c;收发附件已是家常便饭&#xff0c;但对于手机查看附件&#xff0c;用户却遇到了很多问题。稍微低端的手机&#xff0c;除了txt格式的文本&#xff0c;基本上其他格式的文档&#…

连不上机器判断机器状态_如何准确估计机器人的状态,增强机器人控制的精度及稳定性...

在机器人学中&#xff0c;状态估计和控制一样&#xff0c;是无法避开的问题。 任何传感器的精度都是有限的&#xff0c;如何利用传感器信息&#xff0c;尽可能准确地估计一组完整描述机器人随时间运动的物理量&#xff0c;如位置、速度、加速度、角度、角速度等&#xff0c;是状…

2个字符串相等 swift_Swift快速入门(一)之 Swift基础语法

Swift快速入门&#xff08;一&#xff09;之 Swift基础语法近期重新学习了一遍Swift语言&#xff0c;主要以《Swift编程权威指南&#xff08;第2版&#xff09;》为教程&#xff0c;学习过程中结合比对Java语言特性将学习心得作为三篇笔记&#xff1a;Swift基础语法&#xff0c…

bootstrap switch只出现一个对号_python:34.第一个只出现一次的字符位置

题目描述在一个字符串(0<字符串长度<10000&#xff0c;全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1&#xff08;需要区分大小写&#xff09;.解析暴力解法&#xff0c;时间复杂度是 。# -*- coding:utf-8 -*- class Solution:def Fi…

mac系统如何进入系统偏好设置_MacOS Big Sur 系统偏好设置无法解锁Bug解决

前不久&#xff0c;MacOS推送正式版Big Sur&#xff0c;我满怀期待的更新。更新的过程很平缓&#xff0c;一切都很顺利。但在使用时&#xff0c;出现了一个问题&#xff0c;系统偏好设置的锁无法解除&#xff0c;导致有些软件需要权限&#xff0c;却不能正常允许通过&#xff0…

事务嵌套问题_注意Spring事务这一点,避免出现大事务

背景本篇文章主要分享压测的(高并发)时候发现的一些问题。之前的两篇文章已经讲述了在高并发的情况下&#xff0c;消息队列和数据库连接池的一些总结和优化&#xff0c;有兴趣的可以在我的公众号中去翻阅。废话不多说&#xff0c;进入正题。事务&#xff0c;想必各位CRUD之王对…

多布局怎么搭建_怎么制作网页?网页制作基本步骤

怎么制作网页?网页制作基本步骤&#xff0c;互联网时代&#xff0c;各行各业的企业为了适应时代的发展&#xff0c;纷纷从线下转移至线上来拓展自己的业务。若想让更多人了解自己的企业&#xff0c;拥有一个专属网站至关重要。网站不仅可以详细介绍企业信息&#xff0c;更重要…

能运行shell吗_terminal, shell, bash, zsh

##秋天的第一杯奶茶梗?Terminal: shell运行在里面。A terminal refers to a wrapper program that runs a shell.Shell:The shell is the program that actually processes commands and returns outputs. Most shells also manage foreground and background processes, comm…

OSPF的虚链路配置

OSPF的虚链路配置<?xml:namespace prefix o ns "urn:schemas-microsoft-com:office:office" />OSPF多区要求普通区域必须和骨干区域&#xff08;area 0&#xff09;相连&#xff0c;如果一个区域不能和骨干区域直接相连&#xff0c;可以使用虚链路把该区域逻…