arm cortex-m架构 SVC指令详解以及其在freertos的应用
1. 前置知识
本文基于arm cortex-m架构描述, 关于arm cortex-m的一些基础知识可以参考我另外几篇文章:
- arm cortex-m 架构简述
- arm异常处理分析
- c语言函数调用规范-基于arm 分析
2 SVC指令
2.1 SVC指令位域表示

- bit15 - bit12:条件码(Condition Code),用于控制指令的条件执行(EQ,NE,… )。
- bit11- bit8:固定编码0111,用于标识这是一个SVC指令。
- bit7- bit0:8位立即数(imm8),svc指令一般用于实现系统调用,imm8用来指定系统调用号。
2.2 SVC指令用途简述
- ARM中的SVC(Supervisor Call)指令,一般用于实现系统调用, 在执行SVC指令时会触发一个SVC异常。
- 在cortex-m架构中,异常/中断服务 总是处于总是处于 Privileged(特权) 模式,系统调用也是利用这一特性从用户态 进入 内核态 ,然后根据系统调用号执行特定的系统调用。 关于cortex-m架构和中断的其他信息可以参考我的另外两篇文章:
- arm cortex-m 架构简述
- arm异常处理分析
- 站在硬件的角度SVC指令就是实现了一个软件中断,SVC异常和其他异常处理并无不同,硬件并没有做类似 传递系统调用号 这样的操作,系统调用号imm8也只是和指令码"打包"在一起放在代码段,在进入内核态之后 获取系统调用号 的操作是由 软件完成 的。
2.3 SVC使用示例
- SVC中断触发示例
SVC #0x01 ; 执行SVC指令,SVC号为0x01 SVC #0x02 ; 执行SVC指令,SVC号为0x02 - SVC中断服务函数示例
- 我在代码中加了注释,如果还是不理解,可以看看我 第一节 所推荐的文章。
SVC_Handler:; TST指令解释:; 将 "LR" 与 "立即数4" 进行 "按位与" 操作; 结果更新条件标志寄存器(CPSR); 注:在发生异常时 LR 存储的是 EXC_RETURN , 这条代码主要看在发生异常时使用的是哪个栈,MSP或者PSPTST LR, #4; 依据TST LR, #4 的执行结果选择将 MSP或PSP加载到R0中; ITE: "If-Then-Else" 的缩写,用于创建一个条件执行块(IT块)。; EQ: 条件码,表示 "Equal"(相等),即当条件码寄存器(CPSR)的零标志(Z)被设置时,条件为真。; 用C语言描述一下下面三行汇编:; if(Z) {; MRS R0, MSP; } else {; MRS R0, PSP; }; 举一反三: ITTE: "If-Then-Then-Else" ITE EQMRS R0, MSP ; LR&4 或者说 EXC_RETURN&4 为 0 ,说明在在执行SVC异常时使用的栈是 MSPMRS R0, PSP ; LR&4 或者说 EXC_RETURN&4 为 0 ,说明在在执行SVC异常时使用的栈是 PSP; 获取返回地址 (原理是与发生异常时硬件压栈的顺序相关); 这里获得返回地址的原因是为了定位产生异常前执行的最后一条指令,也就是SVC指令LDR R1, [R0, #24] ; 获取SVC指令的低8位,也就是系统调用号,返回地址的上一条就是SVC指令,LDRB R1, [R1, #-2] ; 依据不同的系统调用号执行不同的系统调用CMP R1, #0x01BEQ SVC_01_HandlerCMP R1, #0x02BEQ SVC_02_HandlerSVC_01_Handler:; 处理SVC号为0x01的服务请求SVC_02_Handler:; 处理SVC号为0x02的服务请求
3. SVC指令在freertos中的应用
freertos只使用了一次 SVC指令 也可以理解为 freertos中只实现了一个系统调用,且只使用一次,就是在完成任务创建后发起的第一次任务调度时使用。
3.1 在freertos中SVC中断的触发位置
- freertos使用 SVC指令是在 prvPortStartFirstTask 函数中使用,目的是开始第一次调度,发生在创建任务完成后的第一次调度,我会为这段代码加上注释,如果还存在看不懂的情况,建议先看看我的其他文章或者自行查阅资料学习。
- 在freertos中的调用关系是:
vTaskStartScheduler ---> ---> xPortStartScheduler ---> ---> prvPortStartFirstTaskstatic void prvPortStartFirstTask( void ) {__asm volatile (/* * - 0xE000ED08是 SCB 模块 VTOR 寄存器的地址* - 这句汇编目的是把 0xE000ED08(VTOR的地址) 保存到 R0 寄存器* - 执行完这句指令(伪指令),后 R0 寄存器保存的是 0xE000ED08(VTOR的地址)*/" ldr r0, =0xE000ED08 \n"/* * - 将 0xE000ED08 地址的值(中断向量表的地址) 放到 R0 寄存器中* - 执行完这句指令,后 R0 寄存器保存的是 中断向量表的地址*/" ldr r0, [r0] \n"/* * - 将 中断向量表 第一项的值 放到 R0 寄存器中* - 中断向量表第一个字保存的 是栈顶地址(cortex-m是满减栈,栈顶即栈的开始)* - 初始转态下使用的是MSP* - 执行完这句指令,后 R0 寄存器保存的是栈顶地址*/" ldr r0, [r0] \n"/* * - 将 R0的值写入 MSP 中。* - 此时 R0 内存储的是 栈顶地址,这一步其实就是把 MSP 中已经存好的内容完全销毁。* - 因为在这段代码中,在执行完SVC指令后,会由调度器完全接管代码,这里的SVC异常永远也不会返回*/" msr msp, r0 \n"/* * - 将 control 寄存器清零* - control 寄存器有三位,分别是:* . FPCA - 标志位,用于指示在前文中是否使用过 FPU(浮点运算单元),如果使用过,dang发生异常硬件压栈的时候,会基于此位决定是否保存浮点运算单元上下文,又此时使用的SVC异常是不会返回的,所以也不必保存,保存了也是浪费空间。* 0:前文没有使用浮点运算单元,产生异常时硬件不用保存浮点上下文* 1:前文使用了浮点运算单元,产生异常时硬件要保存浮点上下文* . SPSEL - 控制位,控制在 Thread mode 下使用 MSP 还是 PSP , Handler mode 一定使用 PSP* 0: MSP* 1: PSP* . nPRIV - 控制位,控制在 Thread mode 下是 Privileged(特权级) 还是 Unprivileged(非特权级) , Handler mode 下一定是 Privileged(特权级)* 0: Privileged(特权级)* 1: Unprivileged(非特权级)*/" mov r0, #0 \n"" msr control, r0 \n"/* 开启全局中断 */" cpsie i \n" /* 开启fpu */" cpsie f \n" /* 数据同步隔离,确保上面的配置生效 */" dsb \n" /* 指令同步隔离,清空流水线 */" isb \n" /* 触发0号系统调用,永远也不会返回, 从此处开始代码由freertos全面接管 */ " svc 0 \n"/* svc 不会返回,永远也不会运行到这里 */" nop \n"/* 这是一条伪指令,由汇编器处理,目的是告诉汇编器,把字面量池(常量)放到这个位置, 避免字面量池离使用它的指令太远,超出了寻址范围而导致错误。ARM的ldr指令寻址范围有限*/" .ltorg \n"); }
3.2 freertos中断服务函数解析
- 我会为这段代码加上注释,如果还存在看不懂的情况,建议先看看我的其他文章或者自行查阅资料学习。
void vPortSVCHandler( void ) {/** 思考:在汇编中能用C语言的变量吗,为什么,C语言中的变量和符号在汇编中代表了什么* 答案:应考虑如下几点* - C语言和汇编在整个编译过程中是在不同的阶段进行的* - C语言是在 编译阶段 进行处理的,C语言会被编译为汇编* - 汇编 是在汇编阶段进行的,会生成可重定位的目标文件,最终会在 链接阶段 由链接器为所有符号分配 绝对地址。* - 我们在写汇编时,会用一些符号代表地址,那些符号会由 链接器 最终分配绝对地址。* - c语言中定义的 变量名 函数名 在经过 编译器 编译为 汇编 之后,那些变量名, 函数名都代表一个地址,最后由 链接器 分配绝对地址。* 所以,在汇编中使用的C语言符号,可以理解为那个变量或者函数的 地址。*//** 先看一下最后一句汇编 "pxCurrentTCBConst2: .word pxCurrentTCB \n"* - pxCurrentTCB:在c语言中定义,它是一个指针,一个描述 任务 的结构体指针* - 在汇编中使用 pxCurrentTCB 这个符号, 就相当于使用这个符号的地址,在这里可以理解为一个二重指针* - 上述汇编可以这么理解:* . 使用 .word 分配一个字的空间,用来放 “下一个要执行的任务结构体” 指针的指针(二重指针).* . 将这个二重指针 使用符号 pxCurrentTCBConst2 表示*/__asm volatile (/* * - 将要执行任务的结构体 的 指针的指针(二重指针) 保存到 R3寄存器 */" ldr r3, pxCurrentTCBConst2 \n"/* * - 将要执行任务的结构体 的 指针(一重指针) 保存到 R1寄存器 * - 也可以理解为将 要执行任务的结构体 的第一个元素的地址保存到 R1 寄存器* - 结构体第一个元素 保存将要执行任务的栈指针* - 所以这一句是将 栈指针(SP) 的地址(是栈指针的存放地址,而不是栈指针) 放到R1中。*/" ldr r1, [r3] \n"/* * - 将栈指针 SP 保存到 R0寄存器 */" ldr r0, [r1] \n"/* * - 将栈指针中的地址按顺序弹栈(要执行的任务的栈)到{r4-r11, r14}* - 这里是要弹栈的内容是 创建任务时 伪造的上下文 (此处先不展开,后面降到任务的创建过程会展开来讲)*/" ldmia r0!, {r4-r11, r14} \n"/* 将 PSP 指向弹完栈后的地址 */" msr psp, r0 \n"/* 指令同步隔离,清空流水线 */" isb \n"/* 将basepri寄存器设为0,打开所有中断 */" mov r0, #0 \n"" msr basepri, r0 \n"/* * - 异常返回, 这时r14(LR)中存放的是一个 EXC_RETURN 值,这个值是在创建任务时伪造的。* - EXC_RETURN 的值决定了任务使用的栈* - 伪造栈的内容会在后面将创建任务时讲*/" bx r14 \n"" \n"" .align 4 \n""pxCurrentTCBConst2: .word pxCurrentTCB \n"); }
相关文章:
arm cortex-m架构 SVC指令详解以及其在freertos的应用
1. 前置知识 本文基于arm cortex-m架构描述, 关于arm cortex-m的一些基础知识可以参考我另外几篇文章: arm cortex-m 架构简述arm异常处理分析c语言函数调用规范-基于arm 分析 2 SVC指令 2.1 SVC指令位域表示 bit15 - bit12:条件码&#…...
k8s笔记——kubernetes中的三种IP
kubernetes概念 Master:集群控制节点,每个集群需要至少一个master节点负责集群的管控 Node:工作负载节点,由master分配容器到这些node工作节点上,然后node节点上的docker负责容器的运行 Pod:kubernetes的…...
Golang | Leetcode Golang题解之第127题单词接龙
题目: 题解: func ladderLength(beginWord string, endWord string, wordList []string) int {wordId : map[string]int{}graph : [][]int{}addWord : func(word string) int {id, has : wordId[word]if !has {id len(wordId)wordId[word] idgraph a…...
微服务中feign远程调用相关的各种超时问题
1. 引言 在spring cloud微服中,feign远程调用可能是大家每天都接触到东西,但很多同学却没咋搞清楚这里边的各种超时问题,生产环境可能会蹦出各种奇怪的问题。 首先说下结论: 1)只使用feign组件,不使用ribbion组件&…...
springboot整合chatgpt,并且让其可以记录上下文
整合很简单,不过需要几个小条件 1.必须要有openai官方的key 2.国内需要有代理服务器或者国外的服务器把项目部署出去也没问题 我没有使用spring的springAI,听说很方便,日后有机会去体验体验,我今天用了两种方式整合了gpt 1.Ch…...
CTP前端:解码数字世界的魔法师
CTP前端:解码数字世界的魔法师 CTP前端,一个充满神秘与魅力的职业,他们在数字世界中挥舞着魔法棒,创造着令人惊叹的奇迹。那么,CTP前端究竟是做什么的呢?让我们从四个方面、五个方面、六个方面和七个方面&…...
rabbitmq的交换机类型以及他们的区别
RabbitMQ中有四种主要的交换机类型,它们是:Direct,Topic,Fanout,Headers。 Direct(直连交换机):接收到消息后,会将消息发送到与消息的routing key完全匹配的队列上。Dire…...
理解不同层的表示(layer representations)
在机器学习和深度学习领域,特别是在处理音频和自然语言处理(NLP)任务时,"层的表示"(layer representations)通常是指神经网络不同层在处理输入数据时生成的特征或嵌入。这些表示捕获了输入数据的…...
原生js访问http获取数据的方法
在原生JavaScript中,直接通过浏览器端的JavaScript访问HTTP接口获取数据通常涉及XMLHttpRequest对象或现代的fetch API。 1. 使用XMLHttpRequest XMLHttpRequest是一个老旧的API,但在某些情况下仍然很有用。以下是一个简单的例子: javascr…...
Windows 2000 Server:安全配置终极指南
"远古技术,仅供娱乐" 💭 前言:Windows 2000 服务器在当时的市场中占据了很大的比例,主要原因包括操作简单和易于管理,但也经常因为安全性问题受到谴责,Windows 2000 的安全性真的那么差吗&#x…...
基于 FastAI 文本迁移学习的情感分类(93%+Accuracy)
前言 系列专栏:【深度学习:算法项目实战】✨︎ 涉及医疗健康、财经金融、商业零售、食品饮料、运动健身、交通运输、环境科学、社交媒体以及文本和图像处理等诸多领域,讨论了各种复杂的深度神经网络思想,如卷积神经网络、循环神经网络、生成对抗网络、门控循环单元、长短期记…...
集成Google Authenticator实现多因素认证(MFA)
目录 参考1、应用背景2、多因素认证3、谷歌google authenticator集成用法3.1、原理3.2、 MFA绑定3.2.1、 用户输入用户名密码登录3.2.2、检查是否已经绑定MFA(检查数据库是否保存该用户的google secret)3.2.3、谷歌身份证认证器扫描绑定3.2.4、手动测试验…...
网关(Gateway)- 自定义过滤器工厂
自定义过滤工厂类 DemoGatewayFilterFactory package com.learning.springcloud.custom;import org.apache.commons.lang.StringUtils; import org.springframework.cloud.gateway.filter.GatewayFilter; import org.springframework.cloud.gateway.filter.GatewayFilterChai…...
HTML静态网页成品作业(HTML+CSS)—— 香奈儿香水介绍网页(1个页面)
🎉不定期分享源码,关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 🏷️本套采用HTMLCSS,未使用Javacsript代码,共有1个页面。 二、作品演示 三、代…...
C++11 lambda表达式和包装器
C11 lambda表达式和包装器 一.lambda表达式1.lambda表达式的引入2.基本语法和使用1.基本语法2.使用1.传值捕捉的错误之处2.传引用捕捉 3.lambda表达式的底层原理4.lambda的特殊之处5.lambda配合decltype的新玩法 二.function包装器1.概念2.包装函数1.包装普通函数2.包装成员函数…...
3. MySQL 数据表的基本操作
文章目录 【 1. MySQL 创建数据表 】【 2. MySQL 查看表 】2.1 查看表的属性DESCRIBE/DESC 以表格的形式展示表属性SHOW CREATE TABLE 以SQL语句的形式展示表属性 2.2 查看表的内容 【 3. MySQL 修改数据表结构 】3.1 修改表名3.2 修改表字符集3.3 添加字段在末尾添加字段在开头…...
Linux命令篇(一):文件管理部分
💝💝💝首先,欢迎各位来到我的博客,很高兴能够在这里和您见面!希望您在这里不仅可以有所收获,同时也能感受到一份轻松欢乐的氛围,祝你生活愉快! 文章目录 1、cat命令常用参…...
IP协议1.0
基本概念: • 主机: 配有IP地址, 但是不进⾏路由控制的设备; • 路由器: 即配有IP地址, ⼜能进⾏路由控制; • 节点: 主机和路由器的统称; IP协议的报头 • 4位版本号(version): 指定IP协议的版本, 对于IPv4来说, 就是4. • 4位头部⻓度(header length): IP头部的⻓…...
源码编译安装LNMP
LNMP包含: linux、Nginx、Mysql、php LNMP的工作原理 : 由客户端发送页面请求给Nginx,Nginx会根据location匹配用户访问请求的URL路径判断是静态还是动态,静态的一般是以 .html .htm .css .shtml结尾,动态的一般是以 .…...
安装Chrome扩展程序来 一键禁用页面上的所有动画和过渡。有那些扩展程序推荐一下
要安装Chrome扩展程序来一键禁用页面上的所有动画和过渡,以下是一些推荐的扩展程序: Toggle CSS Animations and Transitions 功能:此扩展程序允许用户轻松地在网页上切换CSS动画和过渡的开启与关闭状态。使用方法:安装后&#x…...
国防科技大学计算机基础课程笔记02信息编码
1.机内码和国标码 国标码就是我们非常熟悉的这个GB2312,但是因为都是16进制,因此这个了16进制的数据既可以翻译成为这个机器码,也可以翻译成为这个国标码,所以这个时候很容易会出现这个歧义的情况; 因此,我们的这个国…...
模型参数、模型存储精度、参数与显存
模型参数量衡量单位 M:百万(Million) B:十亿(Billion) 1 B 1000 M 1B 1000M 1B1000M 参数存储精度 模型参数是固定的,但是一个参数所表示多少字节不一定,需要看这个参数以什么…...
如何在看板中有效管理突发紧急任务
在看板中有效管理突发紧急任务需要:设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP(Work-in-Progress)弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中,设立专门的紧急任务通道尤为重要,这能…...
React19源码系列之 事件插件系统
事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...
【论文笔记】若干矿井粉尘检测算法概述
总的来说,传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度,通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...
AI书签管理工具开发全记录(十九):嵌入资源处理
1.前言 📝 在上一篇文章中,我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源,方便后续将资源打包到一个可执行文件中。 2.embed介绍 🎯 Go 1.16 引入了革命性的 embed 包,彻底改变了静态资源管理的…...
稳定币的深度剖析与展望
一、引言 在当今数字化浪潮席卷全球的时代,加密货币作为一种新兴的金融现象,正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而,加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下,稳定…...
算法:模拟
1.替换所有的问号 1576. 替换所有的问号 - 力扣(LeetCode) 遍历字符串:通过外层循环逐一检查每个字符。遇到 ? 时处理: 内层循环遍历小写字母(a 到 z)。对每个字母检查是否满足: 与…...
Elastic 获得 AWS 教育 ISV 合作伙伴资质,进一步增强教育解决方案产品组合
作者:来自 Elastic Udayasimha Theepireddy (Uday), Brian Bergholm, Marianna Jonsdottir 通过搜索 AI 和云创新推动教育领域的数字化转型。 我们非常高兴地宣布,Elastic 已获得 AWS 教育 ISV 合作伙伴资质。这一重要认证表明,Elastic 作为 …...
归并排序:分治思想的高效排序
目录 基本原理 流程图解 实现方法 递归实现 非递归实现 演示过程 时间复杂度 基本原理 归并排序(Merge Sort)是一种基于分治思想的排序算法,由约翰冯诺伊曼在1945年提出。其核心思想包括: 分割(Divide):将待排序数组递归地分成两个子…...
