当前位置: 代码迷 >> 综合 >> fans-rt 任务调度-堆栈切换篇(2)堆栈模型
  详细解决方案

fans-rt 任务调度-堆栈切换篇(2)堆栈模型

热度:48   发布时间:2024-01-20 12:15:48.0

前面我们提到,任务的切换就是堆栈的切换(当然首先是任务上下文的切换),也通过代码简单的描述了堆栈切换的切换过程。但是,要成功从一个任务切换到另一个任务还必须了解CPU当前运行模式下,中断处理时的特性。例如,进入堆栈时会保存哪些寄存器,CPU是否支持硬件双堆栈(甚至更多层次的堆栈),如果支持多层堆栈,那么在进入中断前,外层堆栈保存哪些寄存器,内层堆栈保存哪些寄存器,是否会将外层堆栈指针保存在内层堆栈中等等,这些特性决定断点现场的状态,也决定了操作系统代码在进行任务切换前需要将哪些不会被CPU自动保存的寄存器入栈,以及创建新任务时如何初始化新任务的堆栈。

在 fans-rt 源码路径的 /platform/board/stm32 下有5个子文件夹,这5个文件夹中都存在一个 kboard_interrupt.s 文件,每个文件的文件头注释中都有一段配置描述:

;    Configuration:
;     System global core stack                  YES/NO
;     The local core stack of general task      YES/NO
;     The loacl core stack of kernel task       YES/NO
;     The local user stack of general task      YES/NO
;     Hardware supported task switch IRQ        YES/NO
;     Hardware supported double stack           YES/NO
这是关于CPU堆栈模型的配置描述,这些配置与CPU特性相关,直接影响堆栈切换代码的实现。每个项描述对的含义以及影响如下:

第一项:系统全局内核栈

表明是否支持系统全局内核栈,如果该项为YES,则表明系统中只有一个内核堆栈,所有普通任务使用同一个内核堆栈(系统中同时只有一个任务能够请求内核功能,如果任务正在内核中执行,必须在内核功能执行完成,从软中断上下文返回任务时才能执行任务切换),实际上cortex-m3正好支持这种堆栈模型,CPU提供MSP和PSP两个堆栈指针,发生中断时自动从用户态的PSP切换到MSP,全局内核栈的好处是所有任务共享一个内核栈,内核的最大堆栈深度是可预估的,而不同的任务在非特权层执行的代码需要的堆栈容量不同,可以单独为每个任务配置不同的用户栈大小,这样既起到了对内核的保护作用,也可以避免需要大量任务的环境在堆栈空间上的浪费。

第二项:普通任务局部内核栈

表明系统是否支持每个任务一个内核栈,实际上cortex-m3硬件上并不能直接支持这种模型,因为cortex-m3硬件实现上并没有支持任务的概念,不能支持自动重载MSP,/platform/board/huge 中的代码是通过软件方式实现的。具备局部内核栈的堆栈模型在X86的CPU上可以得到支持,X86提供了一个称为任务状态段(TSS)的结构,通过装入TSS可以获得任何任务从 ring0-ring3 不同特权层的堆栈指针,并且硬件支持任务堆栈指针的自动切换。

第三项:内核任务局部内核栈

表明系统是否需要支持内核任务,所谓内核任务是指具备特权级的任务,任务在执行时可以访问内核能够访问的所有资源,此类任务是为后续驱动模型设计时预留(也许用不到,我希望能够将除系统服务之外的所有功能放到用户层实现),内核任务的堆栈初始化方法和普通任务不同(参考源码路径/platform/arch/stm32/karch-stack.c中的函数 CORE_FillStack),内核任务的中断返回LR值为0xfffffff9,普通任务返回用户层的LR值为0xfffffffd(X86上通过iretd指令获得ss和cs寄存器,并通过ss和cs的CPL确定返回的代码段的特权级)。内核任务在发生中断时,不进行堆栈切换,从中断返回时也不进行堆栈切换。

第四项:普通任务局部用户栈

表明系统是否支持局部用户栈(没有全局用户栈),如果支持局部用户栈,那么系统一定支持双堆栈,普通任务执行过程中发生中断时,需要将堆栈从用户栈切换到内核栈(软件实现切换或者硬件自动切换)。如果不支持局部任务用户栈,则所有任务均使用内核栈(每个任务一个内核栈),均拥有内核特权级,可以访问所有内核资源。该中断模型出现在不支持特权级的CPU平台上,例如intel 8086/8088。在小容量的cortex-m3芯片上支持该中断模型,对于极少任务需求的环境可以节省堆栈上的开销。

第五项:硬件支持任务切换

实际上就是指是否支持类似cortex-m3的PendSV中断,PendSV属于CPU平台的特性,不是所有平台都支持此类中断。如果支持,那么PendSV中断的出入栈方式和其他中断的出入栈方式不同。在此模型下,PendSV中断需要对所有CPU寄存器压栈,但其他中断可以只对使用到的寄存器压栈,因为其他中断中不会发生任务上下文切换,不需要构建任务切换场景的断点堆栈状态。

第六项:硬件支持双堆栈

就像cortex-m3能够有MSP/PSP,发生特权级变化时,自动进行堆栈切换。如果硬件不能支持双堆栈,而软件希望使用双堆栈以减少大量任务环境上堆栈对内存的开销,那么可以通过在中断服务程序的代码中实现软件堆栈切换(例如 /platform/board/stm32/soft的实现)。在进行堆栈切换前,中断处理程序先将当前任务的CPU寄存器保存到外层栈,然后切换到内层栈再调用中断服务程序,返回时取出保存在任务上下文中的外层栈指针,从外层栈恢复CPU寄存器,然后返回任务断点继续执行。

fans-rt 与堆栈相关的有六项配置,但这六项配置可以组合出很多种环境,而fans-rt在cortex-m3上实现了5种常见的环境,实际上这5种环境在cortex-m3上并不是都有意义,实现他们的目的只是为了验证当前fans-rt的内核代码在任务切换部分能否支持各种单片机硬件形态。