简易内核调度设计 --基于TQ2440(ARM9)的实现(1)

来源:互联网 发布:关于网络诈骗的作文800 编辑:程序博客网 时间:2024/04/24 07:16

作者:姜广伟
日期:2010-12-9
邮箱:Guangwei.jiang@gmail.com/jgw2008@126.com

**

1. 概述

**
多任务是现代操作系统的核心功能,深入理解多任务并非易事,但学习者如果能尝试去实现一个简易的多任务程序,对理解操作系统的“多任务”概念会有很大的帮助。若能进一步拓展这个多任务的程序,则可设计一个简易的内核(Kernel)。

本文就是介绍一个十分简易的多任务程序。

实验程序中共有2个任务,Task1和Task2:
Task1中,闪烁LED1灯3次后,主动将CPU使用权切换给Task2;
Task2中,闪烁LED2灯3次后,主动将CPU使用权切换给Task1。
从而,实现2个任务的交替执行。

实验环境说明:
本实验的操作平台为TQ2440(ARM9)开发板,程序代码在S3C2440“SteppingStone”的4KB内部RAM中运行。程序就是利用这4KB的空间来实现多任务的切换。
请选择从NAND Flash启动,并将生成的二进制文件烧到NAND Flash中。
当选择从NAND Flash启动CPU时,CPU会通过内部硬件将NAND Flash开始的4KB字节数据复制到“SteppingStone” 的4KB内部RAM中(此时内部RAM的起始地址是0),然后跳到地址0开始执行。

Task1和Task2的代码如下,
这里写图片描述

这里写图片描述

2. 详解设计/实现部分

程序分为3大部分,
**–初始化
–存储模型
–任务切换**

2.1 初始化
程序的初始化很简单,_start是CPU reset后运行的第一段代码。
a. 因为要调用C函数,必须要先设置了SVC模式下的堆栈(CPU reset后,默认进入SVC模式);
b. 为了防止CPU不断自动重启,需要关闭WatchDog;
c. 接下来初始化4个LED灯(关闭4个LED灯);
d. 最后,启动第一个任务Task1。
注意:Task1堆栈的初始化指针指向#4000,它工作在SVC模式中。

初始化代码(_start)如下,

这里写图片描述

2.2存储模型

Code存放区域: 0x00000000~0x000007FF (2KB);
Task2的堆栈区域: 0x00000C00~0x00000E03(516B);
Task1的堆栈区域: 0x00000E04~0x00000FA3(416B);
TCB指针存放区域: 0x00000FA4~0x00000FFF(92B)。

注意:
a. 栈的增长方向由高地址到低地址;
b. TCB指针存放区域,存放的是Task栈顶指针,如0x0000FFC保存Task1的栈顶指针;0x00000FF8保存Task2的栈顶指针。

存储划分图表如下,

这里写图片描述

2.3任务切换
运行新任务之前,必须要为每个新任务初始化PCB(Process Control Block)。PCB是一个保留在RAM的数据结构,用于保存所有ARM寄存器的一个副本(见下表)。

任务控制块(PCB, Process Control Block)
这里写图片描述

测试代码中,任务1是主程序并首先运行,不需要初始化PCB。
任务2运行之前,需要先初始化PCB,初始化代码如下,
这里写图片描述

其中,函数“TaskCreate”的3个参数含义如下:
void(*Task)(void): Task地址
unsigned long *p_Stack: Task堆栈指针
unsigned long *Task_STK_PTR: 保存Task栈顶指针的地址

下面以Task1切换到Task2为例,来说明任务切换的过程。
第一阶段,保存Task1运行的上下文(Context)。
将PC/LR/R0-R12/CPSR压入堆栈中,然后将栈顶指针保存起来。代码如下,
这里写图片描述

第二阶段,恢复Task2的运行上下文(Context)。
首先取出Task2的栈顶指针;然后,PSR先出栈并恢复CPSR;接着R0-R12/LR/PC依次出栈。
至此,Task2恢复了之前的运行上下文并接管CPU的控制权。

这里写图片描述

这里写图片描述

本文源代码可以从作者的github下载,链接如下
https://github.com/GuangweiJiang/diy_kernel/tree/master/01_TaskSwitch

1 0
原创粉丝点击