现在要来看看怎样让系统实现简单多任务。看一下Linux 0.00版本(已经丢失了,重新的),它就是当时李纳斯在Minix论坛上发布的Linux的最初版本。由于李纳斯的源码是AT&T格式的,语法较烦,正有打算改下Nams,巧在网上看到一个已经改写成nasm格式的,下面我来解读一下。
一个正在任务运行的任务要被调出的时候,要保存“上下文”信息,这些零散的“上下文”信息被保存在一个叫TSS的结构体中,相应的有TSS描述符被加载到GDT中。另外一个任务需要一个LDT,相应的有LDT描述符被加载到GDT。我们现在建立两个任务,我们需要的结构体有:
1、GDT(代码段描述符、数据段描述符、显示的描述符、TSS0描述符、LDT0描述符、TSS1描述符、LDT1描述符)
2、LDT0(数据段描述符,代码段描述符)
3、LDT1(数据段描述符,代码段描述符)
4、TSS0
5、TSS1
除此之外,还需要堆栈支持,基于此,内存的分布如下
IDT+GDT+0的用户栈+(LDT0+TSS0+0的核心堆栈)+(LDT1+TSS1+1的核心堆栈)+TASK0+TASK1+0的用户栈
由于是时间片的调度,所以需要时钟发生器这个中断源来给系统计时,当中断到来时去执行定义好的处理,这里需要一个结构体IDT,它将每个异常或中断向量分别与它们的处理过程联系起来。和GDT、IDT类似。同以前一样,需要IDT描述符,它将被加载到IDTR中。
我们用中断返回操作来实现,因此当初始化GDT、IDT和定时器芯片结束后,我们就利用中断返回指令IRET来启动运行第一个任务。具体如下,初始堆栈中人工设置一个返回环境,即把任务0的TSS段选择符加载到任务寄存器LTR中、LDT加载到LDTR中,把任务0的用户栈指针和代码指针以及标志寄存器压入栈中,然后执行中断IRET。本条指令会弹出堆栈上的堆栈指针作为任务0的用户栈指针,恢复恢复假设的任务0的标志寄存器内容,并且弹出代码寄存器放入CS:EIP寄存器中,从而开始执行任务0的代码。当任务切换时,任务1的TSS选择符作为操作数执行远跳指令,从而切换到任务1执行。
代码请空间下载!