ThreadX源码:Cortex-A7的tx_thread_context_save.S(线程上下文保存)汇编代码分析

news2024/9/21 7:44:31

0 参考资料

Cortex M3权威指南(中文).pdf(可以参考ARM指令集用法)

1 前言

tx_thread_context_save.S是用来实现Cortex-A7下线程上下文保存的函数所在汇编文件。

2 源码分析

2.1 概述

_tx_thread_context_save函数用于在线程被中断打断后保存上下文,根据打断点所处的位置分为2种情况处理:
(1)非嵌套中断(首次触发中断,也就是从线程切换到IRQ模式)
(2)嵌套中断
其中,非嵌套中断中又分为2种情况:
(1)打断点处于线程调度执行期间
(2)打断点不处于线程调度执行期间

2.2 源码逐行分析

源码如下:

1.    .global _tx_thread_context_save
2.    .type   _tx_thread_context_save,function
3._tx_thread_context_save:

4.    /* Upon entry to this routine, it is assumed that IRQ interrupts are locked
5.       out, we are in IRQ mode, and all registers are intact.  */

6.    /* Check for a nested interrupt condition.  */

7.    PUSH    {r0-r3}                         // Save some working registers
8.#ifdef TX_ENABLE_FIQ_SUPPORT
9.    CPSID   if                              // Disable FIQ interrupts
10.#endif
11.    LDR     r3, =_tx_thread_system_state    // Pickup address of system state variable
12.    LDR     r2, [r3]                        // Pickup system state
13.    CMP     r2, #0                          // Is this the first interrupt?
14.    BEQ     __tx_thread_not_nested_save     // Yes, not a nested context save

15.    /* Nested interrupt condition.  */

16.    ADD     r2, #1                          // Increment the interrupt counter
17.    STR     r2, [r3]                        // Store it back in the variable

18.   /* Save the rest of the scratch registers on the stack and return to the
19.      calling ISR.  */

20.    MRS     r0, SPSR                        // Pickup saved SPSR
21.    SUB     lr, #4                          // Adjust point of interrupt
22.    PUSH    {r0, r10, r12, lr}              // Store other registers

23.    /* Return to the ISR.  */

24.    MOV     r10, #0                         // Clear stack limit

25.#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE))
26.    /* Call the ISR enter function to indicate an ISR is executing.  */
27.    PUSH    {lr}                            // Save ISR lr
28.    BL      _tx_execution_isr_enter         // Call the ISR enter function
29.    POP     {lr}                            // Recover ISR lr
30.#endif

31.    B       __tx_irq_processing_return      // Continue IRQ processing

32.__tx_thread_not_nested_save:

33.    /* Otherwise, not nested, check to see if a thread was running.  */
34.    ADD     r2, #1                          // Increment the interrupt counter
35.    STR     r2, [r3]                        // Store it back in the variable
36.    LDR     r1, =_tx_thread_current_ptr     // Pickup address of current thread ptr
37.    LDR     r0, [r1]                        // Pickup current thread pointer
38.    CMP     r0, #0                          // Is it NULL?
39.    BEQ     __tx_thread_idle_system_save    // If so, interrupt occurred in
40.                                            //   scheduling loop - nothing needs saving!

41.    /* Save minimal context of interrupted thread.  */

42.    MRS     r2, SPSR                        // Pickup saved SPSR
43.    SUB     lr, #4                          // Adjust point of interrupt
44.    PUSH    {r2, r10, r12, lr}              // Store other registers

45.    MOV     r10, #0                         // Clear stack limit

46.#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE))
47.    /* Call the ISR enter function to indicate an ISR is executing.  */
48.    PUSH    {lr}                            // Save ISR lr
49.    BL      _tx_execution_isr_enter         // Call the ISR enter function
50.    POP     {lr}                            // Recover ISR lr
51.#endif

52.    B       __tx_irq_processing_return      // Continue IRQ processing

53.__tx_thread_idle_system_save:

54.    /* Interrupt occurred in the scheduling loop.  */

55.    /* Not much to do here, just adjust the stack pointer, and return to IRQ
56.       processing.  */

57.    MOV     r10, #0                         // Clear stack limit

58.#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE))
59.    /* Call the ISR enter function to indicate an ISR is executing.  */
60.    PUSH    {lr}                            // Save ISR lr
61.    BL      _tx_execution_isr_enter         // Call the ISR enter function
62.    POP     {lr}                            // Recover ISR lr
63.#endif

64.    ADD     sp, #16                         // Recover saved registers
65.    B       __tx_irq_processing_return      // Continue IRQ processing

2.1 _tx_thread_context_save函数主干

逐行分析:

1.    .global _tx_thread_context_save

说明:

.global 用于定义全局符号,以便于被其他文件引用;.local 用于定义局部符号, 仅在当前文件使用。

2.    .type   _tx_thread_context_save,function

说明:

.type用于设置符号的type属性,可选值为function或object(函数或对象(如全局变量))

3._tx_thread_context_save:

指示_tx_thread_context_save函数入口。

7.    PUSH    {r0-r3}                         // Save some working registers

功能:
将一些_tx_thread_context_save函数会使用到的寄存器入栈。

8.#ifdef TX_ENABLE_FIQ_SUPPORT
9.    CPSID   if                              // Disable FIQ interrupts
10.#endif

功能:
如果使能了FIQ中断,则在进入IRQ之后同时将FIQ失能,这个语句是将IRQ和FIQ全部失能(进入IRQ硬件会自动失能IRQ)。
CPSID用法如下:
在这里插入图片描述

11.    LDR     r3, =_tx_thread_system_state    // Pickup address of system state variable
12.    LDR     r2, [r3]                        // Pickup system state
13.    CMP     r2, #0                          // Is this the first interrupt?
14.    BEQ     __tx_thread_not_nested_save     // Yes, not a nested context save

操作如下:
(1)将_tx_thread_system_state变量的内存地址写入r3
(2)将r3存储的内存地址对应的内存数据写入r2
(3)判断r2的值是否为0
(4)如果(3)中结果为真则跳转到__tx_thread_not_nested_save处执行
功能如下:
判断_tx_thread_system_state变量的值是否为0,如果为0则执行__tx_thread_not_nested_save函数,也就是非嵌套中断的上下文保存函数。

16.    ADD     r2, #1                          // Increment the interrupt counter
17.    STR     r2, [r3]                        // Store it back in the variable

操作如下:
(1)将r2的值+1
(2)将r2的值写入r3存储的内存地址对应的内存
功能如下:
将_tx_thread_system_state的值+1。

20.    MRS     r0, SPSR                        // Pickup saved SPSR
21.    SUB     lr, #4                          // Adjust point of interrupt
22.    PUSH    {r0, r10, r12, lr}              // Store other registers

操作如下:
(1)将SPSR(程序状态保存寄存器)的值写入r0
(2)将lr的值-4
(3)将lr、r12、r10、r0依次入栈
功能如下:
保存上下文,lr寄存器保存的是当前中断打断位置的下一条指令,SPSR寄存器在发生嵌套中断时会被破坏,因此也需要入栈。

24.    MOV     r10, #0                         // Clear stack limit

操作如下:
(1)将r10的值设置为0
功能如下:
将栈极限设置为0(ThreadX构建了一个中断帧,r10表示栈极限)。

25.#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE))
26.    /* Call the ISR enter function to indicate an ISR is executing.  */
27.    PUSH    {lr}                            // Save ISR lr
28.    BL      _tx_execution_isr_enter         // Call the ISR enter function
29.    POP     {lr}                            // Recover ISR lr
30.#endif

操作如下:
(1)将lr入栈
(2)跳转到_tx_execution_isr_enter函数,告知进入了中断服务函数
(3)将lr出栈
功能如下:
如果定义了TX_ENABLE_EXECUTION_CHANGE_NOTIFY或TX_EXECUTION_PROFILE_ENABLE宏,则会通过_tx_execution_isr_enter函数告知ThreadX内核现在进入了中断服务函数。

31.    B       __tx_irq_processing_return

操作/功能如下:
(1)跳转到__tx_irq_processing_return函数,结束上下文保存。

2.2 _tx_thread_context_save函数分支__tx_thread_not_nested_save非嵌套上下文保存

32.__tx_thread_not_nested_save:

33.    /* Otherwise, not nested, check to see if a thread was running.  */
34.    ADD     r2, #1                          // Increment the interrupt counter
35.    STR     r2, [r3]                        // Store it back in the variable
36.    LDR     r1, =_tx_thread_current_ptr     // Pickup address of current thread ptr
37.    LDR     r0, [r1]                        // Pickup current thread pointer
38.    CMP     r0, #0                          // Is it NULL?
39.    BEQ     __tx_thread_idle_system_save    // If so, interrupt occurred in
40.                                            //   scheduling loop - nothing needs saving!

操作如下:
(1)将r2的值+1
(2)将r2的值写入r3存储的内存地址对应的内存
(3)将_tx_thread_current_ptr变量的内存地址写入到r1
(4)将r1存储的内存地址对应的内存数据写入r0
(5)判断r0的值是否为0
(6)如果(5)中结果为真则跳转到__tx_thread_idle_system_save处执行
功能说明:
如果IRQ非嵌套中断,判断_tx_thread_current_ptr的值是否为空,如果发生在线程调度期间,则不需要保存任何数据(线程调度在非IRQ模式下执行,进入前线程栈已经保存)。

42.    MRS     r2, SPSR                        // Pickup saved SPSR
43.    SUB     lr, #4                          // Adjust point of interrupt
44.    PUSH    {r2, r10, r12, lr}              // Store other registers

操作如下:
(1)将SPSR(程序状态保存寄存器)值写入r2
(2)将lr的值-4
(3)依次将lr、r12、r10、r2入栈
功能如下:
保存上下文,lr寄存器保存的是当前中断打断位置的下一条指令,SPSR寄存器在发生嵌套中断时会被破坏,因此也需要入栈。

45.    MOV     r10, #0                         // Clear stack limit

(1)将r10的值设置为0
功能如下:
将栈极限设置为0(ThreadX线程构建了一个中断帧,r10表示栈极限)。

46.#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE))
47.    /* Call the ISR enter function to indicate an ISR is executing.  */
48.    PUSH    {lr}                            // Save ISR lr
49.    BL      _tx_execution_isr_enter         // Call the ISR enter function
50.    POP     {lr}                            // Recover ISR lr
51.#endif

操作如下:
(1)将lr入栈
(2)跳转到_tx_execution_isr_enter函数,告知进入了中断服务函数
(3)将lr出栈
功能如下:
如果定义了TX_ENABLE_EXECUTION_CHANGE_NOTIFY或TX_EXECUTION_PROFILE_ENABLE宏,则会通过_tx_execution_isr_enter函数告知ThreadX内核现在进入了中断服务函数。

52.    B       __tx_irq_processing_return      // Continue IRQ processing

操作/功能如下:
(1)跳转到__tx_irq_processing_return函数,结束上下文保存。

2.3 _tx_thread_context_save函数分支__tx_thread_idle_system_save

53.__tx_thread_idle_system_save:

54.    /* Interrupt occurred in the scheduling loop.  */

55.    /* Not much to do here, just adjust the stack pointer, and return to IRQ
56.       processing.  */

57.    MOV     r10, #0                         // Clear stack limit

58.#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE))
59.    /* Call the ISR enter function to indicate an ISR is executing.  */
60.    PUSH    {lr}                            // Save ISR lr
61.    BL      _tx_execution_isr_enter         // Call the ISR enter function
62.    POP     {lr}                            // Recover ISR lr
63.#endif

64.    ADD     sp, #16                         // Recover saved registers
65.    B       __tx_irq_processing_return      // Continue IRQ processing

操作/功能如下:
(1)将r10的值设置为0
(2)将lr入栈
(3)跳转到_tx_execution_isr_enter函数,告知进入了中断服务函数
(4)将lr出栈
(5)将sp的值+16(之前入栈的4个寄存器无需出栈,直接将栈指针+16空出栈空间即可)
(6)跳转到__tx_irq_processing_return函数,结束上下文保存

3 总结

_tx_thread_context_save函数主要功能就是实现上下文保存。上下文的保存又分为嵌套中断上下文保存和非嵌套中断上下文保存,如果是嵌套中断上下文保存则只需要入栈lr和SPSR即可,如果发生了非嵌套中断且不是发生在线程调度期间,要保存lr和SPSR,如果发生在线程调度期间则无需保存lr和SPSR(线程调度期间已经做了这部分工作)。

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

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

相关文章

「Next.js中文文档」网站发布

大家好,我是程普(weijunext),我联合“阿伟dev”搭建了一个「Next.js 中文文档」网站👇 这个网站我们设计得很特别: 样式很特别 我们模仿 Next.js 官方网站样式,努力做到除了语言不同&#xff…

进程相关的系统调用

文章目录 进程进程相关的系统调用wait函数waitpid函数示例--使用wait fork函数创建子进程并使用宏验证子进程的退出状态信息示例--使用waitpid函数检测子进程是否进入暂停状态 exec族函数示例--exec族函数的使用 system函数示例--使用system函数执行外部指令 进程状态切换 进程…

Vue2电商平台项目 (三) Search模块、面包屑(页面自己跳自己)、排序、分页器!

文章目录 一、Search模块1、Search模块的api2、Vuex保存数据3、组件获取vuex数据并渲染(1)、分析请求数据的数据结构(2)、getters简化数据、渲染页面 4、Search模块根据不同的参数获取数据(1)、 派发actions的操作封装为函数(2)、设置带给服务器的参数(3)、Object.assign整理参…

第十一章 【后端】商品分类管理微服务(11.1)——创建父工程

第十一章 【后端】商品分类管理微服务 11.1 创建父工程 项目名称:EasyTradeManagerSystem:Easy 表示简单易用,Trade 表示交易,Manager 表示管理,System 表示系统,强调系统在商品交易管理方面的便捷性,简称 etms。 新建工程 yumi-etms yumi-etms 作为所有模块的父工程,…

基于java 的医院排号管理系统设计与实现

博主介绍:专注于Java .net php phython 小程序 等诸多技术领域和毕业项目实战、企业信息化系统建设,从业十五余年开发设计教学工作 ☆☆☆ 精彩专栏推荐订阅☆☆☆☆☆不然下次找不到哟 我的博客空间发布了1000毕设题目 方便大家学习使用 感兴趣的可以…

1863. 找出所有子集的异或总和再求和

目录 一:题目: 二:代码: 三:结果: 一:题目: 一个数组的 异或总和 定义为数组中所有元素按位 XOR 的结果;如果数组为 空 ,则异或总和为 0 。 例如&#x…

C++--类的实例化

一、实例化的概念 用类类型在屋里内存中创建对象的过程,称为类实例化出对象 类是对对象进行一种抽象描述,是一个模型一样的东西,限定了类有哪些成员变量,这些成员变量只是声明,没有分配空间,用类实例化出…

【C++前后缀分解 动态规划】2100. 适合野炊的日子|1702

本文涉及知道点 C前后缀分解 C动态规划 LeetCode2100. 适合野炊的日子 你和朋友们准备去野炊。给你一个下标从 0 开始的整数数组 security ,其中 security[i] 是第 i 天的建议出行指数。日子从 0 开始编号。同时给你一个整数 time 。 如果第 i 天满足以下所有条件…

2024最新版MySQL详细学习教程

MySQL数据库提供了很多函数包括: 数学函数;字符串函数;日期和时间函数;条件判断函数;系统信息函数;加密函数;格式化函数; 一、数学函数 数学函数主要用于处理数字,包括…

基于paddleocr的批量图片缩放识别

说明 在进行ocr文字识别的时候,有时候我们需要使用批量测试的功能,但是有些图片会识别失败或者个别根本识别不出来,这时候我们可以通过对原图片进行缩放,提高图像的分辨率,然后再次识别,这样可以大大提高图…

Vue学习记录之一(介绍及脚手架的使用)

一、背景知识介绍 1、构建工具介绍 Vite, Webpack,Rollup, Parce 构建工具优点缺点Vite- 快速启动,秒级热更新,更快的构建速度,更好的开发体验;- 支持 Vue3 和 ES modules 的原生特性,轻松实现按需加载。- 对于单页…

项目实现:云备份②(文件操作、Json等工具类的实现)

云备份 前言文件操作实用工具类设计文件属性的获取文件的读写操作文件压缩与解压缩的实现文件目录操作 Json 实用工具类设计编译优化 前言 如果有老铁不知道当前项目实现的功能是什么的话,可以先移步这篇文章内容: 云备份项目的介绍 其中介绍了云备份项…

【吊打面试官系列-MySQL面试题】简述在 MySQL 数据库中 MyISAM 和 InnoDB 的区别?

大家好,我是锋哥。今天分享关于【简述在 MySQL 数据库中 MyISAM 和 InnoDB 的区别?】面试题,希望对大家有帮助; 简述在 MySQL 数据库中 MyISAM 和 InnoDB 的区别? MyISAM: 不支持事务,但是每次查…

跳出大厂圈子——普通程序员如何开启逆袭之路

时间:2024年09月16日 作者:小蒋聊技术 邮箱:wei_wei10163.com 微信:wei_wei10 音频:喜马拉雅 大家好,欢迎来到“小蒋聊技术”!今天咱们聊点特别现实的事儿——普通程序员的出路。互联网时代…

化学实验室器具识别系统源码分享

化学实验室器具识别检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Comput…

android设置实现广告倒计时功能

文章目录 CountDownTimer基本使用增加基础BaseActivity增加固定活动 在Android中,CountDownTimer 是一个用于计时的类,它允许你在指定的时间段内执行某些操作。通常用于倒计时功能,例如显示一个倒计时进度条或者在倒计时结束后执行某个动作。…

采用qt做一个命令行终端

qt做一个类似系统命令行终端的工具,方便集成到自己的软件里使用,这样能保证软件的整体性,而且是真正的做到和系统命令行终端一样的交互方式,而不是单独搞个编辑框的方式输入命令(大部分博客都是做成这个样子&#xff0…

不善言辞的程序员适合做项目经理吗?

项目经理的角色需要承担多重任务,包括团队协调、资源调配、风险管理、沟通与汇报等。因此,很多人认为项目经理需要较强的沟通能力和外向性格。然而,不善言辞的程序员是否适合这一职位,实际上取决于多个因素。以下从不同角度进行分…

程序设计题(25-32)

第二十五题 题目 请编写函数fun,其功能是:在一个含有11个四位数的数组中,统计出这些数的奇数、偶数个数,然后计算出个数多的那些数的算数平均值并由函数返回,个数通过yy传回。 例如,若11个数据为:1101, 1202, 1303,…

AI+RPA 实战揭秘:DrissionPage 助力 CSDN 热榜数据抓取与 AI 结合

在前一篇文章《AIRPA:开启智能自动化新时代》 发布之后,今天我们将以实战的方式深入介绍数据分析中的RPA究竟是怎样抓取数据的,以及它与 AI 又是如何紧密结合的。首先,让我们来认识一个重要的工具包 ——DrissionPage。 一、Dris…