任务切换的基础:模拟任务切换时寄存器的保存与恢复
文章目录
- 1 任务切换的基础:模拟任务切换时寄存器的保存与恢复
1 任务切换的基础:模拟任务切换时寄存器的保存与恢复
需求说明:使用PendSVC触发异常,在异常处理函数中,保存R4-R11寄存器到缓冲区,再恢复R4-R11寄存器,以模拟任务切换时的寄存器保存与恢复。
文件组织结构如下图:
main.c:
#define NVIC_INT_CTRL 0xE000ED04 // 中断控制及状态寄存器
#define NVIC_PENDSVSET 0x10000000 // 触发软件中断的值
#define NVIC_SYSPRI2 0xE000ED22 // 系统优先级寄存器
#define NVIC_PENDSV_PRI 0x000000FF // 配置优先级#define MEM32(addr) *(volatile unsigned long *)(addr)
#define MEM8(addr) *(volatile unsigned char *)(addr)void triggerPendSVC (void)
{MEM8(NVIC_SYSPRI2) = NVIC_PENDSV_PRI; // 向NVIC_SYSPRI2写NVIC_PENDSV_PRI,设置其为最低优先级MEM32(NVIC_INT_CTRL) = NVIC_PENDSVSET; // 向NVIC_INT_CTRL写NVIC_PENDSVSET,用于PendSV
}typedef struct _BlockType_t
{unsigned long * stackPtr;
}BlockType_t;BlockType_t * blockPtr;void delay (int count)
{while (--count > 0);
}int flag;unsigned long stackBuffer[1024];
BlockType_t block;int main ()
{block.stackPtr = &stackBuffer[1024];blockPtr = █for (;;) {flag = 0;delay(100);flag = 1;delay(100);triggerPendSVC();}return 0;
}
switch.c:
__asm void PendSV_Handler ()
{// blockPtr在main.c中定义,定义为:BlockType_t * blockPtr。// 在汇编代码中,如要引用C中的符号,必 须先用IMPORT导入。有些类似于在C语言中的externIMPORT blockPtr// 加载寄存器存储地址// LDR R0, =blockPtr ; 将blockPtr变量的地址加载到R0中// LDR R0, [R0] ; 再从该地址加载32位数据值,也就是将blockPtr的值加载到R0中。在main()中,我们已经设置:// BlockType_t block;// block.stackPtr = &stackBuffer[1024];// blockPtr = █// 所以,此时R0的值将会是block结构的起始地址。// LDR R0, [R0] ; 再次加载32位数据,显示此次就是从block结构开始处加载32位值,根据block结构的定义:// typedef struct _BlockType_t {// unsigned long * stackPtr;// }BlockType_t// 显然,此时R0的值就是stackPtr的值,也就是&stackBuffer[1024];LDR R0, =blockPtrLDR R0, [R0]LDR R0, [R0]// 保存寄存器// 此时R0的值就是&stackBuffer[1024]。然后,将R4, R5, .. R11写入到stackBuff缓冲区中,顺序不重要,你只需知道其与下面LDMIA的加载次序正好相反即可。写入前,以R0中地址为基准,每写入一个寄存器前,先对地址减去4,然后再写入寄存器值。完成所有写入之后,将最后的地址覆盖到R0寄存器中STMDB R0!, {R4-R11}// 将最后的地址写入到blockPtr中// LDR R1, =blockPtr ; 将blockPtr变量的地址加载到R1中// LDR R1, [R1] ; 再从该地址加载32位数据值,也就是将blockPtr的值加载到R1中。在main()中,我们已经设置:// BlockType_t block;// block.stackPtr = &stackBuffer[1024];// blockPtr = █// 所以,此时R1的值将会是block结构的起始地址。// STR R0, [R1] ; 将前面执行STM执行后,R0的值也就是最后写入的地址写入R1中地址指向的位置。// typedef struct _BlockType_t {// unsigned long * stackPtr;// }BlockType_t// 显然,此时R1的值就是block结构的地址,也就是向将R0的值写入到stackPtr。最终实现将最后的写stackBuff的 地址保存到block.stackPtrLDR R1, =blockPtrLDR R1, [R1]STR R0, [R1]// 修改部分寄存器,用于测试// 测试代码。用于检查前面的保存(STMDB),以及后面的恢复(LDMIA)是否正确。如果保存和恢复正确,那么执行LDMIA后,R4,R5的值应为恢复之前的值。// 如果需要,可在此添加对其它寄存器的修改测试代码。ADD R4, R4, #1ADD R5, R5, #1// 恢复寄存器// 与STMDB正好相反,从R0地址对应的存储单元中读取多个32位的单元,恢复到R4~R11寄存器。// 注意到,此时,R0为之前向存储单元写R4~R11的最后单元的地址,所以此时可以正确恢复。// 具体执行时,首先从当前地址对应的单元处加载数据恢复到寄存器,再将地址+4,如此反复,直到所有寄存器恢复完毕。LDMIA R0!, {R4-R11}// 异常返回// 异常返回指令,不同于从函数调用。此时LR的值不是函数的返回地址,而是一串特定的值,如0xFFFF_FFFxBX LR
}
参考资料:
- 【李述铜】从0到1自己动手写嵌入式操作系统
任务切换的基础:模拟任务切换时寄存器的保存与恢复相关推荐
- [ATF]-TEE/REE系统切换时ATF的寄存器的保存和恢复
ATF点滴 1.设置运行时栈SP 2.寄存器的保存和恢复的实现 3.寄存器的保存和恢复的使用场景 ★★★ 友情链接 : 个人博客导读首页-点击此处 ★★★ 1.设置运行时栈SP bl31_entryp ...
- [architecture]-ARMV7架构下SecureMonitor双系统切换时保存和恢复哪些寄存
★★★ 个人博客导读首页-点击此处 ★★★ . 文章目录 1.armv7的通用寄存器简介 2.寄存器的保存和恢复 3.参考代码: 1.armv7的通用寄存器简介 ARMV7处理器有40个32位寄存器, ...
- [architecture]-ARMV7架构下Linux Kernel的Userspace进程切换时保存和恢复哪些寄存器
★★★ 个人博客导读首页-点击此处 ★★★ . 文章目录 1.armv7的通用寄存器简介 2.寄存器的保存和恢复 3.Linux Kernel参考代码 1.armv7的通用寄存器简介 ARMV7处理器 ...
- (57)模拟线程切换
一.回顾 在之前的课程中,我们学习了 EPROCESS, ETHREAD, KPCR 等重要的内核结构体,学习了存储等待线程的等待链表和调度线程的调度链表,这些知识都是为了后面学习线程切换打的基础. ...
- (58)模拟线程切换——添加挂起、恢复线程功能
一.回顾 我们在上一篇博客分析了模拟线程切换的源码. <模拟线程切换> 我们着重分析了 Scheduling 和 SwitchContext 这两个函数,对线程切换的过程有了新的认识: 线 ...
- Windows进程与线程学习笔记(五)—— 模拟线程切换
Windows进程与线程学习笔记(五)-- 模拟线程切换 ThreadSwitch代码分析 ThreadSwitch.cpp ThreadCore.h ThreadCore.cpp 总结 Thread ...
- Ubuntu:成功解决ubuntu使用su切换root出现Authentication failure用户时认证失败
Ubuntu:成功解决ubuntu使用su切换root出现Authentication failure用户时认证失败 导读 最讨厌网上回答的啰嗦和不清晰!本人最讨厌啰嗦,直接上来,图文表达,简单明了, ...
- 进程线程003 模拟线程切换
文章目录 示例代码 关键结构体 调度链表 初始化线程堆栈 线程切换 被动切换 主动切换 线程调度 总结 之前我们已经了解过线程的等待链表和调度链表,为了更好的学习Windows的线程切换,我们要先读一 ...
- Compose 横竖屏切换时状态如何保存?rememberSaveable 实现原理分析
前言 在这篇文章中提到了 Navigation 的状态保存实际是由 rememberSaveable 实现的,有同学反馈希望单独介绍一下 rememberSaveable 的功能及实现原理.我们都知道 ...
最新文章
- python26 调用mysql 5.1
- C#之获取mp3文件信息
- Mina airQQ聊天 client篇(三)
- 【视频】云信CTO阙杭宁:IM云开发经验分享
- 微信小程序 html modal,微信小程序参考微信设计规范做的modal模态框
- preg_match进行正则表达式匹配
- SAP License:SAP项目文档的考核标准
- Android中Activity的四大启动模式实验简述
- L3G4200D + ADXL345 卡尔曼滤波
- c# 超时时间已到.在操作完成之前超时时间已过或服务器未响应,超时过期了。在操作完成或服务器没有响应之前经过的超时时间。声明已被终止...
- AEC产业未来发展的三大趋势,数字化只是其中之一
- php滚动播报,卫星云图滚动播放(实时更新)
- 计算机主机显卡装在哪,电脑显卡在主板上的哪个位置?怎么查看显卡的信息和更新驱动程序?...
- 《赖氏经典英语语法》第四集
- python图片保存pdf_python将JPG图片转换为PDF
- 【计算机组成原理】 数据的表示和运算
- 研究生必备的文献翻译软件知云文献翻译替代品--Mac monterey
- AUTOSAR CanNm Nm Configuration
- 极简浏览器主页网址导航自定义网址壁纸云端同步简洁清爽
- mysql 、pg 查询日期处理
热门文章
- 远程恢复服务器,Hyper-V主机启用“远程桌面”功能
- 基于单片机的c语言倒计时程序,30秒倒计时c语言51单片机实现.doc
- 【控制】《自动控制原理》胡寿松老师-第5章-线性系统的频域分析法
- 【arduino】继续蜂鸣器音乐播放,arduinoIDE里调用音乐播放库
- CYPRESS USB芯片win10驱动
- 第二十四章:页面导航(五)
- redis集群部署一直卡在Waiting for the cluster to join ......
- HTML5 元素选择流程图
- ASP.NET Core 中文文档 第四章 MVC(4.2)控制器操作的路由
- 升级OS10.11系统后 Xcode6.4的变化少了个按钮 could not launch “Xcode” Xcode 插件安装...