FreeRTOS系列(1):基础知识——中断嵌套
FreeRTOS系列文章(2):PendSV功能,为什么需要PendSV
FreeRTOS系列文章(3): 为什么将SysTick和PendSV的优先级设置为最低
FreeRTOS系列文章(4): MDK软件仿真 + Debug-(printf)-Viewer使用方法
FreeRTOS系列文章(5):C语言程序运行原理分析:汇编、栈、栈帧、进栈、出栈、保存现场、恢复现场、返回

前言

在深入分析RTOS调度之前,我们还需要了解一下Cortex-M3/4的工作模式以及双堆栈指针MSP和PSP,这些概念是非常重要的,如果不了解这些概念,是很难能够理解各种RTOS的底层调度实现原理的。

CM3内核为什么要有线程模式、handler模式

对于一些较真的程序员来说,如果只是告诉他就是这么设计的,就是这么规定的,显然是不够的,不利于程序员高阶操作,而我们的教科书恰恰就缺少这方面的讲解,都是照本宣科。这是题外话,我从自己的角度分析一下CM3/4内核为什么要对工作模式进行区分。

  1. 在早期没有OS之前,程序员都是用裸机写程序,不管程序写的多高级,多复杂,本质上是在main_loop里实现所有的功能,这个时候我们是不需要什么工作模式的,只有1个模式就好了,甚至于因为有了IDE的帮助,我们根本就不想知道什么工作模式。
  2. 随着有些大神级别的程序员,在裸机开发的基础上,他们设计了更加强大的OS,但是这里的OS也是在CPU的平台上实现的,换句话说,也只是用来一些复杂、巧妙的方式实现了OS的效果,可能这种用法连CPU的设计者都没有想到。
  3. CPU的设计不是闭门造车,CPU的设计者也要关注用户的使用习惯,当很多流行的OS在大量的产品上去用的时候,CPU厂商就会考虑,要不要锦上添花,为OS专门设计一些辅助功能,这显然是双赢的,OS运行更加方便,CPU的能力也能充分利用。举个例子,intel的CPU设计者肯定不想让他们的CPU跑裸机程序。所以,简单的说,是先有简单CPU,再有OS,然后CPU基于OS特点迭代优化设计,最终CPU与OS相辅相成,互相成就。
  4. 综上,CPU内核为什么要有线程模式、handler模式,原因是CPU内部架构需要,OS也需要,通过两种模式来区分不通的工作状态,或者说通过区分工作模式实现工作场景的模块化。中断或异常就是在handler模式,应用程序在线程模式,不通的模式权限不通,能干的事儿也不同。

CM3内核为什么要特权分级

仍然是前面提到的,CPU和OS需要这种机制,为了程序的健壮性,CPU索性就设计两种特权级别,内核态和用户态,只有一些核心的、经过大量验证足够稳定的程序(OS内核)才会赋予内核特权,而一般的应用程序则赋予用户态特权,这相当于在硬件机制上就屏蔽了很多因为程序员水平参差不齐而导致的误操作,压根就不给你那些可能会触发危险后果的权限。

CM3内核为什么需要两个SP(MSP和PSP)

仍然是前面提到的,CPU和OS需要这种机制,两个SP与工作模式是相呼应的.

  1. MSP用于线程模式 + handler模式。
  2. Handler模式下CPU会强制使用MSP。
  3. 线程模式下可以使用MSP,也可以使用PSP。
    举例:对于裸机程序,一直使用MSP。对于有OS的程序,OS内核和中断使用MSP,而应用程序task则使用PSP。

那双堆栈指针的作用是什么?答案是为了隔离OS和应用程序,程序的运行少不了堆栈,因为我们CPU只有少量的通用寄存器,当我们使用的临时变量比较多得时候,就需要将这些临时变量存储到堆栈里,而堆栈的push和pop都是通过SP来实现的,所以通过MSP和PSP就能实现OS内核与应用程序的隔离,应用程序task用PSP,而OS用MSP,这样会非常安全。因为应用程序再怎么折腾也只是在自己的堆栈内折腾,不会影响内核OS。

For most cases, it is not necessary to use the PSP if the application doesn’t require an embedded OS. Many simple applications can rely on the MSP completely.
The PSP is normally used when an embedded OS is involved, where the stack for theOS kernel and application tasks are separated. The initial value of PSP is undefined,and the initial value of MSP is taken from the first word of the memory during the reset sequence

接下来引入《The definitive guide to ARM Cortex-M3/4》10.2章节的一段话来进一步说明SP,MSP,PSP的作用:

翻译过来,有如下关键信息:

  1. MSP是默认使用的堆栈指针,可以工作在线程模式,而handler模式一定是使用MSP。
  2. PSP只能用于线程模式。
  3. MSP和PSP的切换有2种情况:
    (1)发生异常或中断时,CPU自动进入Handler模式,CPU会自动设置CONTROL bit[1] 为0,使用MSP。
    (2)OS或程序员将 CONTROL bit[1] 设置为1, 则进入线程模式,则使用PSP。
  4. 在RTOS下,OS为每个task都会分配堆栈空间,各task运行的时候,使用PSP,而在异常中断、OS内核下,则使用MSP。

SP与MSP、PSP拓扑结构

我们先看下寄存器内部的结构

我们可以进一步细化一下,如下图所示:

为了方便理解,我们可以简单的这么想:

  1. 在CPU中,堆栈寄存器SP一共有3个,分别为SP、MSP、PSP。
  2. SP是对外使用的寄存器,或者认为SP始终指向各种模式、各种场景下使用的堆栈指针,只不过在OS或Handler模式下,SP先指向MSP,或者说SP拷贝了MSP的值,可以直接访问主堆栈。而在线程模式下,SP拷贝了PSP的值,可以直接访问线程(任务)堆栈。
  3. 即SP是MSP和PSP的代言人,即SP是MSP和PSP的逻辑地址,对于裸机程序,我们只需要知道SP即可,而对于OS系统,尤其涉及中断、任务上下文切换时,就需要知道PSP和MSP了,OS底层也会直接针对PSP进行编程。这里后续分析FreeRTOS调度实现原理时再详细解释。

[重要知识] 进入中断前后MSP,PSP的切换

在前面的分析中我们知道,MSP用于线程模式+Handler模式,尤其在Hander模式下,CPU会自动切换到MSP,只有在OS系统中,任务task才会使用PSP,即PSP是专门为OS系统设计的,用于任务运行。
在发生中断或异常时,CPU需要自动的保存一半的现场寄存器值,R0~R3, R12, R13(SP), R14(LR)、R15(PC)到堆栈。这部分工作是CPU的硬件实现的。然后才执行中断服务程序。在这个过程中,我们写汇编程序的时候,其实只关心SP,但是内部,尤其是有OS系统的时候,其实是有区别的:

  1. 在发生中断时,CPU硬件需要自动保存现场,此时SP指向MSP还是PSP,取决于发生中断前正在使用的堆栈,即如果发生中断前,正在运行线程模式,而且是task任务运行,则使用PSP,而如果进入中断前,使用的MSP,这里就继续使用MSP。
  2. 一旦开始执行中断服务程序,即handler模式,则一定使用MSP,也就是,如果是有OS的情况下,正在运行task的时候,发生了中断,CPU先使用PSP自动保存现场,跳入到中断服务程序后,就从PSP切换到MSP,所有中断服务程序用到的临时变量都存放到MSP里。

上述两种情况MSP和PSP使用示意图如下:
裸机程序,一直使用MSP

OS系统下,MSP/PSP切换

上图中,stacking就是CPU自动保存现场的过程,此处仍然是使用PSP,只有进入到中断后,才会使用MSP。

Cortex-M3 内核工作模式、特权分级

内核工作模式

内核有2中工作模式,分别为线程模式(Thread Mode)、中断异常模式(Handler Mode)模式,从字面意思就能看出:

线程模式:正常应用程序运行时的模式,应用程序包括程序员编写的应用程序,也包括OS的部分程序。
Handler模式:出现异常、中断时工作模式。

特权分级

Cortex-M3/M4内核特权分级有两种,分别是特权(privileged)和非特权(unprivileged),很多书籍会将这两种特权分为内核态、用户态。

工作模式、特权分级示意图


从上图就能清晰的看出,只有在发生中断、异常时,CPU才会进入Handler模式,其他则是Thread模式,而Thread模式既可以运行在内核态(privileged),也可以运行在用户态(unprivileged)。

  1. 如果我们编写的是裸机程序,其实我们是不需要关注这些东西的,我们的程序移植运行在内核态,权限最高,程序是thread模式,而异常或中断则是handler模式。
  2. 如果我们使用了RTOS,RTOS的代码部分工作在内核态(核心调度部分),而部分(组件)工作在用户态,而我们的应用任务则一般工作在用户态。

线程模式与Handler模式的切换方法

从上图可以看出,是CPU自动切换的,发生异常或中断时,CPU自动进入Handler模式,中断退出是,CPU自动进入Thread模式。

内核态与用户态的切换方法

从内核态到用户态,通过特殊的寄存器【CONTROL】来实现,而用户态无法直接切换内核态,实在要切,也需要异常中断调用,比如SVC。

小结

  1. 本文的内容有些枯燥,因为一般的程序员根本就不关注这些,但是如果要写一个RTOS或者想要理解RTOS底层调度机制,这些概念必须要深入的理解,否则我们是看不懂RTOS底层的汇编代码的。
  2. SP是MSP和PSP的逻辑地址,始终指向当前正在使用的堆栈栈顶,可能是MSP,也可能是PSP。我们写代码的时候,可以只使用SP,也可以通过MRS、MSR来直接操作PSP或MSP.
  3. MSP和PSP 双堆栈机制是为了OS设计的,是为了让OS、中断与应用程序代码运行解耦,增加整体程序的健壮性。
  4. 在发生中断时,CPU会自动的保存现场,这部分工作是硬件自动完成的,而SP到底是指向PSP还是MSP,则是根据在发生中断前是使用MSP还是PSP,比如发生中断前,正在运行RTOS的task,即在使用PSP,那么CPU保存现场也是使用PSP,然后进入中断服务程序,此时会从PSP切换到MSP。
  5. 特权状态和非特权,即内核态和用户态的设计也是为了OS设计的,让整个程序分层,整体程序更加健壮。

RTOS系列文章(6):Cortex-M3/4之SP,MSP,PSP,Thread模式、Handler模式、内核态、用户态相关推荐

  1. RTOS系列文章(2):PendSV功能,为什么需要PendSV

    背景 大多数嵌入式RTOS在Cortex-M3/M4上的移植都需要PendSV,比如uCOS.RT-Thread.FreeRTOS等,本文就对PendSV的功能作用,以及为什么需要PendSV进行详细 ...

  2. 雷达基础系列文章之一:雷达信号的波形、调制形式以及工作模式

    雷达起源于二战英国对抗德国空军,在长达一个世纪的发展中,逐步变得更加精确和复杂.其基本原理始终没变,利用TOA时间获取目标到自身的距离,利用多普勒效应获取目标的速度.为了更好地学习甚至设计雷达,就需要 ...

  3. RTOS系列(12):使用SVC或PendSV启动OS流程详细分析

    RTOS系列(1):基础知识--中断嵌套 RTOS系列文章(2):PendSV功能,为什么需要PendSV RTOS系列文章(3): 为什么将SysTick和PendSV的优先级设置为最低 RTOS系 ...

  4. Cortex、ARMv8、arm架构、ARM指令集、soc?Cortex A8、A9都是ARMv7a 架构;Cortex M3、M4是ARMv7m架构;前者是处理器(内核)后者是指令集的架构(架构)

    架构组成元素的指令集状态或者语法thumb指令集与arm指令集的区别例如thumb指令集是什么_thumb指令集与arm指令集的区别以及thumb-2的关系在下一文中介绍,本文暂时不讨论 有粉丝问我到 ...

  5. Cortex‐M3的Faults异常究竟是什么?

    关注+星标公众号,不错过精彩内容 作者 | strongerHuang 微信公众号 | strongerHuang 有许多朋友在学习,或者开发STM32时都遇到过HardFault_Handler的情 ...

  6. cortex m3 开源_开源增强现实耳机,Steam的125M有效帐户等

    cortex m3 开源 您好,开放游戏迷! 在本周的版本中,我们将了解Steam的1.25亿活跃帐户和Game Developers Conference,这是一个开源增强现实头戴设备,Linux游 ...

  7. 【SemiDrive源码分析】系列文章链接汇总(全)

    注意:兄弟们,因为要换工作了,本专栏暂时先不更新了,如果后续工作也涉及芯驰平台的话,那我还会继续更新下去. 有好工作机会的兄弟,也可以私信介绍给我,可以聊聊 谢谢!!! 注意:兄弟们,因为一些其他原因 ...

  8. ARM 架构、ARM7、ARM9、STM32、Cortex M3 M4 、51、AVR 有啥区别

    ARM架构.ARM7.ARM9.STM32.Cortex M3 M4.51.AVR之间有什么区别和联系? ARM架构:由英国ARM公司设计的一系列32位的RISC微处理器架构总称,现有ARMv1~AR ...

  9. ARM 架构、ARM7、ARM9、STM32、Cortex M3 M4 、51、AVR 之间有什么区别和联系?

    本文转自嵌入式资讯精选公众号,特别鸣谢, 编者按:初学习ARM单片机的同学们可能会对ARM的架构定义并不是很明确,形形色色的名词背后到底代表什么含义呢?请听听这位嵌入式工程师的经验总结. ARM架构: ...

最新文章

  1. pandas 绘图 机器学习看特征相关性
  2. git把本地代码上传(更新)到github上
  3. 【Linux】一步一步学Linux——ipcs命令(141)
  4. Windows驱动开发技术详解笔记
  5. shell中source与sh区别
  6. 用C#在STM32上写第一个Hello world
  7. 验证部分表单是否重复
  8. leetcode三道shell题
  9. php moodle mysql_PHP+XAMPP+MYSQL:从MOODLE数据库提取数据并利用jpgraph生成柱状成绩对比图...
  10. 深度学习最常用的10个激活函数!
  11. Python模块(四)操作redis
  12. redis和php有什么,redis主要用来做什么
  13. 常见的ASCII码值
  14. “两两”求和问题技巧
  15. 妙不可言,这4款小众良心软件,值得你用心体会
  16. spring boot 项目重新搭建----------mvc配置:拦截器
  17. Unity学习之Physic.Raycast(射线检测)个人理解分享
  18. 基于Python的统计建模
  19. 渝海手机号码归属地查询工具php版 v1.1
  20. Binggo公开课 “CODEX创新体系”的实战演练-中关村创业大街

热门文章

  1. 机场无人便利店在上海虹桥机场正式开业
  2. php现场大屏幕互动系统
  3. 阿里腾讯外包Java怎样_阿里Java岗、腾讯后台开发岗面经(拿到AT双Offer)
  4. Win系统MDM服务器创建,使用 MDM 橋接器 WMI 提供者建立Windows 10資訊 (Windows 10) - Configure Windows | Microsoft Docs...
  5. 为什么需要运营商级NAT设备?
  6. 收费站计算机安全应急预案,收费站突发事 件应急处置预案.doc
  7. 最TOP小程序排行榜出炉
  8. router学习(二): 路由导航守卫
  9. matlab读mif文件,MATLAB将mif文件转换成coe文件(原创)
  10. ESP32Arduino学习(三).ESP32驱动WS2812第一个灯绿色问题的解决(Adafruit_NeoPixel库)