fans-rt 任务调度-堆栈切换篇(4)tiny模型详细分析
来源:互联网 发布:python urllib2 post 编辑:程序博客网 时间:2024/06/05 21:12
优化后的Tiny模型代码:
;; Copyright(C) 2013-2015, Fans-rt development team.;; All rights reserved.;; This is open source software.; Learning and research can be unrestricted to modification, use and dissemination.; If you need for commercial purposes, you should get the author's permission.;; Configuration:; System global core stack NO; The local core stack of general task YES; The loacl core stack of kernel task YES; The local user stack of general task NO; Hardware supported task switch IRQ NO; Hardware supported double stack NO;; date author notes; 2015-06-25 JiangYong new file; 2015-07-07 JiangYong rename to kboard_interrupt.s; 2015-07-11 JiangYong code optimization; INCLUDE kirq_define_enum.inc EXPORT UsageFault_Handler EXPORT BusFault_Handler EXPORT MemManage_Handler EXPORT HardFault_Handler EXPORT SysTick_Handler EXPORT PendSV_Handler EXPORT SVC_Handler EXPORT CORE_Switch2UserMode IMPORT CORE_EnterIRQ IMPORT CORE_LeaveIRQ IMPORT CORE_TickHandler IMPORT CORE_TaskScheduling IMPORT CORE_HandlerLPC IMPORT CORE_SwitchTask IMPORT CORE_SetTaskStackPosition IMPORT CORE_GetTaskStackPosition IMPORT CORE_GetCoreStackPosition IMPORT CORE_CheckMustbeSchedule PRESERVE8 AREA |.text|, CODE, READONLY ALIGN 4 THUMBCORE_Switch2UserMode PROC MOV R0, #0 ; MSR PRIMASK, R0 ; Enable IRQ BX LR ; return ENDPPendSV_Handler PROC BX LR ; Not support PendSV IRQ ENDPSVC_Handler PROC CPSID I ; Why to disable IRQ ? Guess !<span style="color:#ff0000;"> MOV R0, SP ; R0 = Offset of {R0 - R3} PUSH {LR, R12} ; Why to push 12? Guess ! MOV R12, R0 ; R12 = Offset of {R0 - R3}</span> BL CORE_EnterIRQ ; Set current interrupt nest layer CPSIE I ; Enable IRQ<span style="color:#ff0000;"> LDMFD R12, {R0-R3} ; Resume R0 - R3 to call service</span> BL CORE_HandlerLPC ; Call system service<span style="color:#ff0000;"> B ST_L1 ; The next step same as system tick handler</span> ENDPSysTick_Handler PROC CPSID I ; Why to disable IRQ ? Guess !<span style="color:#ff0000;"> PUSH {R12, LR} ; Why to push R12?</span> BL CORE_EnterIRQ ; Set current interrupt nest layer BL CORE_TickHandler ; Inc the system tick CPSIE I ; Enable IRQ BL CORE_TaskScheduling ; Find the new task will be scheduling<span style="color:#ff0000;">ST_L1</span> CPSID I ; Disable IRQ BL CORE_LeaveIRQ ; Set and get current interrupt nest layer CBNZ R0, ST_LE ; Nest layer != 0 then leave this interrupt BL CORE_CheckMustbeSchedule ; Check need schedule CBZ R0, ST_LE ; Must schedule = FALSE then leave this interrupt<span style="color:#ff0000;"> PUSH {R4 - R11} ; nest layer = 0 and Must schedule = TRUE then scheduling</span> MRS R0, MSP ; R0 = Core stack for old task MRS R1, PSP ; R1 = User stack for old task BL CORE_SwitchTask ; CORE_SwitchTask(CoreStack, UserStack); ; No need check the task permssion BL CORE_GetTaskStackPosition ; R0 = User stack for new task(no need) MOV R1, R0 ; R1 = User stack for new task(no need) BL CORE_GetCoreStackPosition ; R0 = Core stack for new task MSR PSP, R1 ; Update user stack(no need) MSR MSP, R0 ; Update core stack<span style="color:#ff0000;"> POP {R4 - R11} ; Restore new task registers</span>ST_LE POP {R12, LR} ; Resume break point CPSIE I ; Enable IRQ BX LR ; Return to task break point ENDPHardFault_Handler PROC B . ENDPMemManage_Handler PROC B . ENDPBusFault_Handler PROC B . ENDPUsageFault_Handler PROC B . ENDPALIGN END
代码中,红色部分为第一个版本与优化后的主要差异点,为什么这么优化呢?在我们分析完代码执行过程中的堆栈环境就明白了。Tiny模型所有任务只有一个堆栈,本文将所有任务堆栈按照内核堆栈进行分析。
首先,进入中断时的堆栈状态:
; |-----------------------|; | ........ |; |-----------------------|; | xPSR | <<= SP + 0x1C; |-----------------------|; | PC | <<= SP + 0x18; |-----------------------|; | LR | <<= SP + 0x14; |-----------------------|; | RC | <<= SP + 0x10; |-----------------------|; | R3 | <<= SP + 0x0C; |-----------------------|; | R2 | <<= SP + 0x08; |-----------------------|; | R1 | <<= SP + 0x04; |-----------------------|; | R0 | <<= SP + 0x00; |-----------------------|; | ........ |; |-----------------------|; 中断入口的堆栈映像,由CPU自动保存
从堆栈映像图可以看出,SP 刚好指向保存 R0 的位置, 所以 SVC_Handler 中断入口在执行
<span style="color:#ff0000;">MOV R0, SP ; R0 = Offset of {R0 - R3}</span> PUSH {LR, R12} ; Why to push 12? Guess ! <span style="color:#ff0000;">MOV R12, R0 ; R12 = Offset of {R0 - R3}</span>
后, R12就指向堆栈中保存R0-R3寄存器的首地址,在调用 CORE_HandlerLPC之前,通过
<span style="color:#ff0000;"> LDMFD R12, {R0-R3} ; Resume R0 - R3 to call service</span> BL CORE_HandlerLPC ; Call system service即可恢复R0-R3寄存器,以便作为参数传递给 CORE_HandlerLPC。
当代码执行完 LR 和 R12 寄存器的入栈操作后堆栈如下:
; |-----------------------|; | ........ |; |-----------------------|; | xPSR | <<= SP + 0x24; |-----------------------|; | PC | <<= SP + 0x20; |-----------------------|; | LR | <<= SP + 0x1C; |-----------------------|; | RC | <<= SP + 0x18; |-----------------------|; | R3 | <<= SP + 0x14; |-----------------------|; | R2 | <<= SP + 0x10; |-----------------------|; | R1 | <<= SP + 0x0C; |-----------------------|; | R0 | <<= SP + 0x08; |-----------------------|; | LR | <<= SP + 0x04; |-----------------------|; | RC | <<= SP + 0x00; |-----------------------|; | ........ |; |-----------------------|; LR 和 R12 入栈后修改前的代码SVC_Handler和SysTick_Handler分别对R4和R0入栈,并未对R12入栈。为什么修改为对R12入栈呢?因为任务切换时需要构造断点堆栈映像如下:
; |-----------------------|; | ........ |; |-----------------------|; | xPSR | <<= SP + 0x54; |-----------------------|; | PC | <<= SP + 0x50; |-----------------------|; | LR | <<= SP + 0x4C; |-----------------------|; | RC | <<= SP + 0x48; |-----------------------|; | R3 | <<= SP + 0x44; |-----------------------|; | R2 | <<= SP + 0x40; |-----------------------|; | R1 | <<= SP + 0x3C; |-----------------------|; | R0 | <<= SP + 0x38; |-----------------------|; | LR | <<= SP + 0x34; |-----------------------|; | RC | <<= SP + 0x30; |-----------------------|; | RB | <<= SP + 0x2C; |-----------------------|; | RA | <<= SP + 0x28; |-----------------------|; | R9 | <<= SP + 0x24; |-----------------------|; | ........ |; |-----------------------|; | R0 | <<= SP + 0x00 (It's the old task break point); |-----------------------|; | ........ |; |-----------------------|; 断点堆栈映像在确认需要调度后,会对 R4-R11进行入栈以构造断点堆栈映像,而已入栈的R12刚好在断点堆栈映像中正确的位置。所以,相比修改前,节省了R4/R0的入栈和出栈动作。
优化点:
1.中断入口的入栈由R4/R0修改为R12,减少R0/R4的入栈和出栈消耗
2.在 SVC_Handler 中,对R0-R3的入栈和出栈修改为由R12寻址的LDMFD指令,通过两次寄存器访问来减少对内存的4次访问
3.减少冗余代码,SVC_Handler和SysTick_Handler共用中断下半部代码。
0 0
- fans-rt 任务调度-堆栈切换篇(4)tiny模型详细分析
- fans-rt 任务调度-堆栈切换篇(2)堆栈模型
- fans-rt 任务调度-堆栈切换篇(1)任务切换的基本原理
- fans-rt 任务调度-堆栈切换篇(3)关于cortex-m3堆栈的入栈顺序说明
- FANS-RT 任务同步对象设计方案
- RT任务调度概览
- 深入分析任务切换与堆栈
- fans-rt 介绍(4)-源码文件夹介绍
- RT-thread任务调度算法
- 【open】fans-rt 任务销毁的对象释放流程
- Fans-rt 任务局部变量特性设计方案(需求分解)
- fans-rt 介绍(1)-什么是fans-rt
- fans-rt 0.11内核架构设计缺陷分析
- FreeRTOS 任务调度 任务切换
- oracle的UTL_mail与任务调度详细分析实例
- rt-thread的位图调度算法分析
- rt-thread的位图调度算法分析
- rt-thread线程调度器源码分析
- UNIX环境高级编程之----多线程技术(1)
- 安装sqlserver 2008出现的问题
- .net学习之ASPX页面属性
- LeetCode 24: Swap Nodes in Pairs
- 内存管理
- fans-rt 任务调度-堆栈切换篇(4)tiny模型详细分析
- Android 自定义控件打造史上最简单的侧滑菜单
- 1.Hibernate初始化
- Test
- UML类图几种关系
- 架构设计:负载均衡层设计方案(4)——LVS原理
- 使用GridView实现九宫格的菜单
- HDU 4341 Gold miner (分组背包)
- 读陈浩的《C语言结构体里的成员数组和指针》总结,零长度数组