当前位置: 首页 > news >正文

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		--->
    --->	prvPortStartFirstTask
    
    static 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…...

今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存

文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...

Python基于历史模拟方法实现投资组合风险管理的VaR与ES模型项目实战

说明:这是一个机器学习实战项目(附带数据代码文档),如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在金融市场日益复杂和波动加剧的背景下,风险管理成为金融机构和个人投资者关注的核心议题之一。VaR&…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...

【Linux】自动化构建-Make/Makefile

前言 上文我们讲到了Linux中的编译器gcc/g 【Linux】编译器gcc/g及其库的详细介绍-CSDN博客 本来我们将一个对于编译来说很重要的工具:make/makfile 1.背景 在一个工程中源文件不计其数,其按类型、功能、模块分别放在若干个目录中,mak…...

人工智能 - 在Dify、Coze、n8n、FastGPT和RAGFlow之间做出技术选型

在Dify、Coze、n8n、FastGPT和RAGFlow之间做出技术选型。这些平台各有侧重,适用场景差异显著。下面我将从核心功能定位、典型应用场景、真实体验痛点、选型决策关键点进行拆解,并提供具体场景下的推荐方案。 一、核心功能定位速览 平台核心定位技术栈亮…...

负载均衡器》》LVS、Nginx、HAproxy 区别

虚拟主机 先4,后7...

DAY 45 超大力王爱学Python

来自超大力王的友情提示:在用tensordoard的时候一定一定要用绝对位置,例如:tensorboard --logdir"D:\代码\archive (1)\runs\cifar10_mlp_experiment_2" 不然读取不了数据 知识点回顾: tensorboard的发展历史和原理tens…...

python读取SQLite表个并生成pdf文件

代码用于创建含50列的SQLite数据库并插入500行随机浮点数据,随后读取数据,通过ReportLab生成横向PDF表格,包含格式化(两位小数)及表头、网格线等美观样式。 # 导入所需库 import sqlite3 # 用于操作…...

Element-Plus:popconfirm与tooltip一起使用不生效?

你们好&#xff0c;我是金金金。 场景 我正在使用Element-plus组件库当中的el-popconfirm和el-tooltip&#xff0c;产品要求是两个需要结合一起使用&#xff0c;也就是鼠标悬浮上去有提示文字&#xff0c;并且点击之后需要出现气泡确认框 代码 <el-popconfirm title"是…...

Pandas 可视化集成:数据科学家的高效绘图指南

为什么选择 Pandas 进行数据可视化&#xff1f; 在数据科学和分析领域&#xff0c;可视化是理解数据、发现模式和传达见解的关键步骤。Python 生态系统提供了多种可视化工具&#xff0c;如 Matplotlib、Seaborn、Plotly 等&#xff0c;但 Pandas 内置的可视化功能因其与数据结…...