IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 嵌入式工程师实现一个简单的操作系统(一) -> 正文阅读

[嵌入式]嵌入式工程师实现一个简单的操作系统(一)

操作系统中的任务与任务切换

1. 为什么要有任务?

????我们常常见到操作系统,也常常要学习操作系统,从一个小白的角度看,任何事情都有其对立的东西,或者说事务都是一步步发展的,既然有操作系统这个东西,那么也必然有无操作系统的软件。

????如果大家都有学习把玩过单片机,比如51单片机或者是STM32单片机,那么应该是都有无操作系统时代这样的经历。无操作系统时代,可以看作是有一个任务的操作系统。无操作系统时,软件的流程是怎么样子的?

无操作系统,裸机环境

/*
?*????无操作系统:
?*????四个功能函数只能依次顺序执行,
?*????在任意一个函数功能中出现阻塞的事件的时候,
?*?????比如某些功能需要一些延时操作,就会照成空空占用处理器的时间
?*????其他功能都无法得到执行
?*/
while(1)
{
????taskA();

????taskB();

????taskC();

????taskD();
}

带操作系统环境

/*
?*????带操作系统:
?*????四个功能函数随时都有可能被执行,
?*????在任意一个函数功能中出现阻塞的事件的时候
?*????操作系统可以进行任务调度和切换,去执行其他的任务
?*????从宏观上可以当作四个功能任务可以同事工作执行
?*/
taskA();

taskB();

taskC();

taskD();

所以我们需要一个操作系统,来提高我们处理器的效率,把处理器的每一刻都去做有意义的事情。

相当于是间接的提高了处理器的性能。

综上所述,有操作系统与无操作系统,最大的区别就是操作系统下可以宏观上并行的执行多个任务,并可以在任务之间切换,选择合适的任务在处理器执行。


所以我们来实现的一个操作系统,首先就是实现以下功能

  • 可以创建任务
  • 可以在不同的任务之间进行切换

有了上面的功能,就可以说是实现了从无操作系统到操作系统的转变

操作系统就是一个上帝视角,每一个任务都是一个无线循环的函数功能

void?taskA()
{
????initA();
????while(1)
????{
????????aaa();
????}
}

void?taskB()
{
????initB();
????while(1)
????{
????????bbb();
????}
}

2. 任务切换怎么实现

2.1 任务切换过程

????不知道大家对函数,处理器运行相关的知识有多少的了解。任务切换有点类似与函数调用的过程,但是也会有很多不同
void?taskA()
{
????initA();
????while(1)
????{
????????aaa();
????????bbb();
????????ccc();
????????ddd();
????}
}

void?taskB()
{
????initB();
????while(1)
????{
????????xxx();
????????yyy();
????????zzz();
????}
}

假设上面有2个无限循环执行的任务,可能的执行过程是这样的

aaa -> xxx -> bbb -> ccc -> yyy -> zzz -> xxx -> ddd -> aaa -> yyy

如上的执行过程,处理器在2个循环中来回执行,一定是发生了任务切换的过程

处理器执行一个函数的时候,有几个重要的要素:

  • 堆栈
  • PC 程序指针
  • LR 程序返回指针
  • 其他的通用寄存器

每一个函数有输入自己的堆栈内容,咋进入函数时候,开辟出堆栈空间,堆栈存放以下内容:

  • 函数的参数
  • 函数内定义的局部变量

因为每一个函数的参数和局部变量都是该函数私有的,并且不能被随意修改,所以在进行任务切换时候,要考虑一下堆栈

接着就是 PC 程序指针,处理器执行那一段代码程序,就是有PC指针决定,处理器总是从PC指针存放的地址去取指令执行。

所以让处理器从一个任务切换到另一个任务去执行,可能会与PC指针有关系了

2.2 任务切换需要作什么

我们想想一下如何从一个任务切换到另一个任务?

1、保护堆栈、保存堆栈

????一般的处理器都会包含一个SP堆栈寄存器,该寄存器存放了当前堆栈的地址。我们现在要进行任务切换,一段时间过后还要从其他任务切换回来。所以我们需要在切换之前吧堆栈的指针保存,在切换过程中吧目标任务的堆栈指针恢复

2、跳转到目标任务

????我们从当前任务切换到目标任务,需要在切换之前把当前运行的地址也保存下来,同理目标任务也已经保存了运行地址,所以切换目标任务就是把目标任务的保存的运行地址恢复,并且是恢复到PC指针,让处理器执行目标任务

3、保存通用寄存器

????通用寄存器在函数执行过程中存放了一些有用的信息,在任务切换之前要保存起来,在切换到目标任务的时候要恢复回来

4、上面的信息保存在哪里

????为每一个任务定义并创建一个结构体,用于保存上述重要的信息

2.3 准备切换任务的材料

上面介绍了任务切换需要什么,既然知道需要什么,那我们就开始着手准备


  1. 定义一个保存任务的信息的结构体,包含上面需要的几个部分:
  • 堆栈指针
  • PC指针
  • 通用寄存器存放
struct?task{????void?*sp;????void?*pc;????uint64_t?regs[32];}
  1. 创建一个任务

创建任务,就需要填充任务的结构体,定义一个任务初始化函数,提供以下参数

  • 任务结构体
  • 堆栈地址
  • 任务入口地址
/**
?*?@brief?创建一个任务
?*
?*?@param?t?任务结构体变量指针
?*?@param?sp_addr?该任务的堆栈地址
?*?@param?pc_addr?该任务的起始地址
?*?@return?int
?*/
int?task_init(struct?task?*t,?void?*sp_addr,?void?*pc_addr)
{
????t->sp?=?sp_addr;
????t->pc?=?pc_addr;

????return?0;
}

上述函数完成了一个任务的初始化

现在,我们准备好了任务需要的材料,就可以开始进行切换了

2.4 进行切换任务实现

具体的任务切换又可以分成几个种类:

  • 从系统启动到第一个任务开始运行,当前没有任务,切换到第一个任务

    task_switch_to(struct?task?*task_to);
    
  • 当前正在一个任务中,切换到另一个任务

    task_switch_from_to(struct?task?*task_from,?struct?task?*task_to)
    

    我们应该去思考如何填充实现上面的函数,当然了,这一部分是与具体的处理器体系结构相关联最大的部分

可以去了解下常用的RTOS在各个架构下是如何实现上述的功能,尤其是AARCH64架构,因为我目前的操作系统就是基于aarch64处理器架构的

关于上面2个任务切换函数的实现,已经上传到github的项目代码中,可以浏览查看

//根据C语言和汇编语言的调用过程,第一个参数存放在x0寄存器中
//我们函数传递的是任务结构体指针
task_switch_to:
????ldr?x1,?[x0]????//任务的pc地址是第一个参数,读取到x1寄存器
????mov?x30,?x1?????//把pc地址放入到x30寄存器,x30寄存器是lr寄存器,稍后切换完成以后返回时候就会返回到任务中执行

????add?x0,?x0,?8???//sp参数在结构体中偏移是八字节
????ldr?x1,?[x0]????//取出并设置sp地址
????mov?sp,?x1

????ret?????????????//函数返回,跳转到x30寄存器存放地址去执行

如果对上面的步骤不是很清楚,可以使用vscode配合gdb进行调试,单步执行代码跟踪处理器执行的过程,尝试一下是否可以正确完成任务切换

目前已经在github的项目中已经实现了上面的代码,可以下载并尝试调试和执行

项目地址:https://github.com/jhbdream/armv8_os.git

欢迎关注 star

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-10-11 17:39:56  更:2021-10-11 17:39:58 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 4:43:56-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码