(1)Asymptote——站在巨人的肩膀上编写一个属于自己的linux操作系统!
一. 前言
最近无意间看到了一本书,《linux内核完全剖析》,竟然是零几年写的,真是深深佩服作者!这本书是基于早期的0.11版内核代码编写的,这也让我有了些许信心去阅读,如果去看2.6的代码,简直不敢想象。。。
之前看过李述桐老师的《从零到一教你写嵌入式操作系统》的tinyOS,那个平台是stm32,当时在原子的开发板上面跟着视频编写并运行过,之后工作了每天都在接触linux,所以当看到《linux内核完全剖析》一书时,又激起了我的好奇心,也许我也可以?!!于是,便产生了这篇文章(一篇文章肯定不够,所以打算写一个系列,只要能坚持,代码还在写,记录就不会断),以此权当一个记录,因为我发现遇到的坑太多了,必须要记录一下。
二. 不罗嗦了,开始正题
从18年12月27日开始写的,平台是之前学驱动时,买的韦东山老师的jz2440开发板。
一开始,先从多任务开始。这里遇到的坑就开始很多了,《linux内核完全剖析》书中的0.11内核源码,当时Linus Torvalds是基于x86架构芯片写的,而现在的板子是arm架构,所以里面的涉及到汇编代码的内容基本不可以借鉴。。。于是我首先想到了之前的stm32下的tinyOS,里面的关于多任务qie'切换的代码可以借鉴,但是后来仔细阅读发现,他利用的是M3核的pendsvc异常来实现任务切换的,但是arm9的jz2440没有这个异常模式,依靠自己感觉太难了,基本没什么思路,所以又从网上开始找,幸运的是找到了——https://blog.csdn.net/jgw2008/article/category/6215030,姜广伟大神写于10年的几篇文章(再次深深佩服)。
一开始我有个疑问,就是任务切换之后一定要进入异常模式吗?答案是否定的。
我在姜大神的文章基础上进行了一些改动,下面叙述一下实现的过程:
如上图所示,首先需要明确几个变量:
1. (unsigned long *)TaskCur_STK_PTR
存放当前执行的任务的地址
2. (unsigned long *)TaskNext_STK_PTR
存放下一个执行的任务的地址
3. (unsigned long *)Task01_STK_PTR
存放第一个任务中的栈sp地址
4. (unsigned long *)Task02_STK_PTR
存放第二个任务中的栈sp地址
之后依次类推。。。
之所以要设置这几个变量,因为栈指针sp在入栈、出栈过程中是一直在变的,当前和下一个任务也是一直在变的,所以分别需要变量去保存。
下面是切换任务的汇编代码:
switch_to:
@ 将“当前任务”寄存器值压栈。
stmfd sp!,{lr} @ PC 入栈
stmfd sp!,{r0-r12,lr} @ r0-r12,lr入栈
mrs r4,cpsr
stmfd sp!,{r4} @ cpsr入栈
@ 保存“当前任务”的栈顶指针。
ldr r5,=TaskCur_STK_PTR @ 取出存放“当前任务”的堆栈指针的地址
ldr r5, [r5]
str sp,[r5] @ 保存“当前任务”的堆栈指针
@ 计算存放“当前任务”堆栈指针的地址。
ldr r0, =TaskCur_STK_PTR
ldr r1, =TaskNext_STK_PTR
ldr r1, [r1]
str r1, [r0]
@ 取出“下一个任务”的栈顶指针,并将寄存器依次出栈。
ldr r6, =TaskNext_STK_PTR @ 取出存放"下一个任务"的Stack Pointer的地址
ldr r6, [r6]
ldr sp, [r6] @ 取出"下一个任务"的堆顶指针,赋给SP
ldmfd sp!,{r4} @ cpsr出栈
msr CPSR_cxsf,r4
ldmfd sp!,{r0-r12,lr,pc} @ r0-r12,lr,pc出栈
之后将要运行的任务的起始地址赋给pc,就可以实现任务切换了。
本文地址:https://blog.csdn.net/CallMe_Xu/article/details/85940082
上一篇: 铁路12306候补订单兑现情况怎么查看?
下一篇: 解决BIOS、CMOS经常遇到的一些问题