微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > 基于X86平台的简单多任务内核的分析与实现

基于X86平台的简单多任务内核的分析与实现

时间:10-08 来源:互联网 点击:

摘要:描述了一个简单多任务内核的设计和实现方法。分析了该简单内核的基本结构和加载运行的基本原理,然后描述了其被加载进机器RAM中以及两个任务进行切换的运行方法。

0 引言

当提到多任务时,人们便会联想到Mac OS、Linux、Windows等操作系统。通常情况下,若在操作系统下运行多任务,是由操作系统负责管理和调度各个任务的。本文通过分析一个简单的多任务内核,能够便于更容易地理解操作系统的任务管理机制,以及可以理解计算机系统是如何启动的。

1 多任务程序的结构

本文实现的简单多任务内核,主要由两个文件构成:一个是使用as86语言编制的引导启动程序,主要用于在计算机系统加电时,将内核代码从启动盘加载到内存中;另一个便是使用GNU as汇编语言编写的内核程序,其中实现两个运行在特权级2上的任务可在时钟中断控制下相互切换运行,并可通过系统调用在屏幕上实现字符显示。

2 多任务内核工作的启动程序原理

计算机系统加电启动后,会把启动程序从启动盘的第一个扇区加载到物理内存0x7c00位置开始处,之后把执行权交给0x7c00初开始运行启动程序。

启动程序的主要功能是将软盘或者镜像文件中的内核程序加载到内存的某个指定位置,实现这个目的的方法是利用ROS BIOS中断int 0x 13,把软盘或者镜像中的内核代码读入到内存,然后再把这段内核代码移动到内存0开始处。最后设置控制寄存器CR0中的开启保护运行模式标志,并跳转到内存0处开始执行内核代码。启动程序在内存中移动内核代码的示意图如图1所示。

将内核代码移动到物理内存0开始处的主要原因是这是GDT表时可以简单一点。但是,不能让启动程序把内核代码从软盘或映像文件中直接加载到内存0处,因为加载操作需要ROM BIOS提供中断过程,而BIOS使用的中断向量表正处于内存0开始处。若直接把内核代码加载到内存0处,那么,BIOS中断过程将不能正常运行。

3 内核程序

3.1 初始化任务

内核程序运行在32位保护模式下,初始化阶段主要包括重新设置GDT表,设置系统定时器芯片,重新设置IDT表并且设置时钟和系统调用中断门。内核示例中所有代码和数据段都对应到物理内存同一个区域上,即从物理内存0开始的区域。在虚拟地址空间中内核程序的内核代码和任务代码分配图如图2所示。

3.2 启动第一个任务

特权级0的代码不能直接把控制权转移到特权级2的代码中执行,但可以使用中断返回操作来实现,因此当初始化GDT、IDT和定时芯片结束后,就利用中断返回指令IRET来启动第一个任务。

具体的实现方法是在初始堆栈init stack中人工设置一个返回环境,即把任务0的TSS段选择符加载到任务寄存器TR中,LDT段选择符加载到LDTR中以后,把任务0的用户栈指针和代码指针以及标志寄存器值压入栈中,然后执行中断返回指令IRET。该指令会弹出堆栈上的堆栈指针作为任务0用户栈指针,恢复假设的任务0的标志寄存器内容,并且弹出栈中代码指针放入CS:EIP寄存器中,从而开始执行任务0的代码,以完成从特权级0到特权级3代码的控制转移。

3.3 两个任务的切换

内核程序将定时器芯片的通道0设置成每经过10 ms就向中断控制芯片发送一个时钟中断请求信号,这样,每个10 ms将会切换运行的任务。PC的ROM BIOS开机时已经在定时器芯片中把时钟中断请求信号设置成中断向量8,因此需要在中断8的处理过程中执行任务切换操作。

每个任务在执行时,会首先把一个字符的ASCII码放入寄存器AL中,然后调用系统中断int 0x80,而该系统调用处理过程会调用一个简单的字符写屏子程序。在显示过一个字符后,任务代码会使用循环语句延迟一段时间,然后又跳转到任务代码开始处继续循环执行,直到运行了10 ms而发生了定时中断,从而代码会切换到另一个任务去运行。

目前,该内核示例已经在Bochs模拟软件中运行测试过,测试结果如图3所示。

4 结语

本文分析了一个基于X86平台的简单多任务内核的基本结构和加载运行原理,描述了其被加载进机器RAM中的基本思路,同时给出了两个任务进行切换的运行方法。其主要目的是理解操作系统的启动加载过程。

附:本文的启动代码及内核代码如下:

基于X86平台的简单多任务内核的分析与实现

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top