MTX操作系统内核与启动流程分析
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
M TX操作系统内核与启动流程分析
任振强
(国家知识产权局专利局专利审查协作天津中心,天津300304)
摘要:通过研究系统从启动到用户程序运行的完整过程,分析了M TX操作系统内核的设计和实现,重点分析了进程的数据结
构及进程切换和系统调用的底层代码,总结了系统引导程序的设计要点和单一内存分段式编译模型的特性。
关键词!MTX;实模式;引导程序;内核;进程切换;系统调用
中图分类号:TP316 文献标识码:A D0I:10.19358/j.issn.2096-5133. 2019. 02. 013
引用格式:任振强.M TX操作系统内核与启动流程分析[J].信息技术与网络安全,2019,38(2):50-54.
M TX operating system kernel and startup procedure analysis
Ren Zhenqiang
(Patent Examination Cooperation Tianjin Center of the Patent O ffice,CNIPA,Tianjin 300304,China)
Abstract:Through a code-level observation of the startup procedure of the MTX operating system,the kernel is stiudied,the machine-level kernel code of process switching and system call is analyzed,and the princ ment memory model is summarized.
Key w ords :M TX; real m ode; booter; kernel; process switch ; system call
〇引言
M T X是美国华盛顿大学电子工程与计算机科学
授WANG K C于2015年发布的一款小型操作系 统[1],该系统基于Intel X6体 ,具有 标准
的类U m x内核,可在X6的实模式下实现内存管理,进程控制,进程调度,线程、进程 息、、中处理,输人输出设备驱动等典型的U N IX/L m u x内核[2]功能。
此外,M T X还支持对称多处理器结构(SMP),用了与L iu x ;容的EXT2文件统;其所有功能模块均能在编译时进行裁剪选择,编译后内核体积可以控制在几十甚至十几K B。
于M T X内核模块 合度极低,可以 调整进程调度功能
以满足实时性要求。
整体而言,M T X操作系统具有高度的灵活性和较低的学习门槛,非常适合于课堂教学和二次开发。
目前主流的类U N IX操作系统均不在实模式下运行[34],国发者虽然对U N IX/L iu x |核设计原理
较熟悉,但对M T X的实现方案并不了解。
因此本文选 择对M T X内核的实现代码进行研究,重点分析靠近底 件的进程 和系统调用代码,统引导程序设计要点进 ,整体通过进程 M T X操作系统进 步分析。
1内核编译
M T X操作系统内核在L i u x环境下使用BCC (Bruce’s C Compiler)Cross-Compiling Package 进行编 译和链接。
M T X使用B C C而不是G C C进行编译,因为 B C C不仅能编译生成8086兼容的16位汇编代码,还 可以基于单一■内存段(one-segment memory)模型对代码进 译。
工作于实模式的C P U以64 K B分段的形式访问物 理内存的最低1M B地址,C P U设置了 4个16位段寄 存器CS、DS、SS、ES,分别用于标记代码(C0de)段、数据 (Data)段、桟(Stack)段和附加(Extra)段。
B C C编译生 成的CS、D S Q S S全重合,于只有一个段,简化了内存 ,方便了程序的初始化。
由于只有一 ,程序可以被载人内存中任意一个可用段中运行,加载 和启动更为灵活。
2内核引导
核作为 MTX作 统的 0 进程,其加载和启 动方式有一定特殊性,同时又影响着其他进程的加载和运 。
2.1引导程序的加载
计算机硬件启动后首先将B IO S载人内存运行,B IOS 完成 寻找可启动设备进行启动。
具体 ,
B IO S首先将启动设备的起始512 B载人内存地址(0x0000,0x7C00),也就是物理地址0x07C00,随后跳 到该内存地址运行指令。
该起始512 B即为引导程 序。
完整的引导程序往往大小会超过512 B,因此当计 算机运行该512 B的代码时,需要完成以下步骤:将引 程序的 部分载人内存运行,寻找操作系统内核
并将其载人内存,最后运 作系统内核的起始代码。
统引导的过程中,弓丨程序会将其载人I 址为0S000的内存段中,随后引导程序会跳转到
0S000 作统内核代码。
以将内核载人
到0S000 ,一是为了 核足够的内存,二是为了方便进程 和系统调用。
M T X将第1个用户程序加载到内存0x2000 、第2个用程序加载到
0x3000 ,以此类推。
当用户程 统调用后,
C PU将返回0x1000段运行内核代码。
2.2引导程序分析
引导程序的前512 B已经被加载到内存中,该512 B程序运行时不能覆盖自身,通常将完整的引导
程序加载到另外的内存。
M T X的与早期
L in u x内核zlm age的引导程序相同[5],即内存的0x9000。
引导程序运行时没有任何库可用,只能使用BIOS 中断IN T13提供的读写功能。
当完整的引导程序加载 到0x9000 后,以下指令:
jmpi start,0x9000
start $
mov ax,cs
mov d s,ax
mov ss,ax
mov e s,ax
mov s p,8192
call _main
jm p i指令将代码段寄存器设置为0x9000后执行 Start处的代码。
由于B C C编译生成的CS、D S和SS段 重合,该代码使用4个m o v语句将所有段寄存器都设置为0x9000,后通过“mov S p,8192”将栈指针 设在偏移量为8K B的地址上,为后面的m a n函数提供 了足够的栈空间,随后调用内核的m a n函数。
可,于引 程 是 的 512 B代码将 载人存,因此也须自己为自己设置好所有的寄存器状态。
时操作系统尚未载人内存中,磁盘 1存的I/O工作依然要通过B IO S中断IN T13来完成。
m a n函数在EXT2文件系统中寻找到M T X内核文件,并将其载人内存的0x000 。
从m a n函数返回后,弓I 导程序执行“jm p 0,0x1000”,该指令将C P U的代码段 寄存器设置为内核加载 0x1000,运 一代码。
内核 启动。
3 M T X内核的进
M T X内核m a n函数的部分工作可简化为如下算法:
while ( 1 ) j
if ( readyQueue)
tsw itch();
5
上述代码只要readyQueue不为空则运行tsw itch进 行进程 。
readyQueue中保存 有可运行的进程,tsw itch从readyQueue中取出一个进程并将上下文(context)切换为该进程的上下文。
完成切换之后,CPU 将运行与m a n函全无关的另一个进程。
如果其 他进程运行tswltCh()后又 核进程,则
时C P U继续运行t s w i h之后的下一条语句。
要 进程切换,必须进程的进行了。
3.1进程控制块
操作系统使用一个进程代表一个程序的执行,内核通常使用一个进程控制块(Proccss Control B lock,PCB)代表一个进程[6]。
M T X的进程控制块具有如下$
typedef struct proc j
struct proc !next;
int !ksp ;
int kstack[ SSIZE ];
5PROC
内核使用全局变量PROC p r c[NPROC]保存系统 中有的进程,统最 可以 NPLOC进程。
m a n函数在运行w h ie(1)循环之前完成以下步骤:初始化p r c[]数组,设置好proc[0]并将其关联给内核自身,建立第一个程序的PR O C结构p r c[1],并 将proc[1]加人readyQueue中。
因此第一次运行while (1)循环时,判断readyQueue不为空后,系统切换到p r c[1]进程开始运 核以外的第一个程序。
P R O C中的n e x t指针指向下一个进程,进程因此可 以被放人进程队列中,如前文中所述的readyQueue。
k s p用于存放内核的桟指针;进程的内核桟kstack则位 于 PROC的最 。
P R O C中next、k s p和k sta ck三个变量的顺序至关重要:next是 struct proc 的第 1 项,ksp是第 2 项,kstack
是最后一项。
当run n in g保存当前进程PR0C结构的 内存地址时,running +2为该PR0C的k s p的地址,而 running+ sizeof(PR0C)正好是其ksta ck数组中最后一 项的内存地址,也就是空栈栈顶的位置。
3.2进程切换
进程 的过程非常简单:将当前进程的上下文存人当前进程的PR0C,从另一个PR0C中取出另一进 程的 ,最后用新进程的 设置CPU,从 [ C PU运行新进程。
M T X操作系统用全局变量PR0C!
指向当前运行的进程。
tS Q itC?的代码如下:_tsQitch $
SA V E:
push ax
push bx
push cx
push dx
push bp
push si
push di
pu sh>
mov b x,—running
mov 2 % b x],sp
FIND: call _scheduler
RESUME:
mov b x,—running
mov s p,2 % bx]
p o p>
pop di
pop si
pop bp
pop dx
pop cx
pop bx
pop ax
ret
S A V E过程保存上下文,p u sh和pushf语句将MTX 用到的C P U寄存器值压人ru n n in g的kstack桟中,再将 run n in g的值(进程的PR0C的 )赋给b x,由之前的讨论可知bx+2即为该PR0C中k s p变量 的地址,因此“mov2[b x],S p”语句将栈顶地址保存在 ksp变 中。
,进程的 保存 running 的 kstack栈 中。
与S A V E对应的RESUM E负责对进程上下文的恢 复,其全是S A V E的逆向过程。
保存和 的是进程调度函数scheduler。
scheduler将当前进程的PR0C 放人 readyQueue,从 readyQueue 中取出 一■个新PR0C,并将running指向该PR0C。
而R ES UM E函数通过弹栈设置C P U寄存器,从而设置好新进程的 。
由上述代码还可以 ,M T X的进程调度功能由scheduler完成,其不与系统其他部分耦合,可单独更换 以满足实时性要求。
3.3进程建立和系统调用
M T X内核的m a in函数在初始阶段建立第一个用户程序的PR0C结构proc[l],tS QltCh()之后系统运行 该程序。
M T X内核 新进程的过程被称为f o k,M T X内核中的函数原型为PR0C! kfork (char! filename),k fo rk可以通过filenam e参数指定程序的路径,并返该程序对应的PR0C的指针。
例如,内核可始阶段运行kf〇rk(“/bm/S hei r),将s h e ll程序作 为第一个程序,以允许用户通过s h e ll令。
与L in u x相同,M T X将内核所在的内核空间(Kernel space)与用户程序所在的用户空间 (User space)分 离。
M T X的内核加载至内存0x1000段,p r o c l程序加 载到0x2000段。
因此0x1000段为内核空间,0x2000 为用 。
作 统的核能 核程
成,当运行于User space的用户程序需要使用核 能时,其通过系统调用运 的内核函数。
系统调用
被称为System c a ll或syscall%7]。
当用户程序运行系统 调用之后,C P U跳转到0x1000段运行内核代码,该过 程通常 为 人 核( trap)。
核代码运
毕之后,C P U返回User space内存段继续运行用户程序 的代码。
3.3.1 进程的建立
M T X将内核加载到0x1000段,将用户程序Umage 加载到0x2000*0x3000等段。
内核的CS、DS、S S段寄 存器均为0x1000,而用程序的存器值为其
的内存段地址。
,fo k i进程的过程,就是将用户程序U m a g e加载到内存0x G + 1)000段并初 始化P<c[I]的程。
加载用户程序的原理与加载内核的原理相同,而初始化过程就是将p r c[i中的变量 赋值为该进程的值。
要了解f o k如何赋值PR0C中的变量,必须理解该变量在进程中代表的
含义。
以第1进程proc1为例:M T X内核通过k f o k语句 加载Uimage1并初始化proc[1],执行tswitch!)之后,核设 Uimage1 的 ,最 CPU 进人 存的0x2000段运行Uimage1。
ts w itc h函数最后的r e t语 句设置C P U的返 ,即C P U要执行的下一条指令的地址。
该返回地址存储在运行完“pop ax”之后的栈
中,也就是ksta ck数组的最后一项kstack%SSIZE-1]之 中。
执行<t之后C P U将执行kstack%SSIZE-1]保存地 址的语句,开始设置U im a g e l的上下文。
M T X内核中 设置Uim age上下文的过程为goUmode函数。
与tsw itch函数类似,goUmode函数使用p o p类指 令设置U im a g e l运行上下文的C P U寄存器。
Uimagel 被加载到内存0S000段,因此其CS、DS、ES为 0x2000。
这三个寄存器以及ax、b x等其他寄存器的值均保存在用户程序的栈中,以通过p o令进行 弹栈。
一个用户程序加载到哪个段无法由程序自身决定,因此用户程序的栈是在k f o k过程中建立的。
k fo k 将U im a g e l加载到0x2000段之后,手动在0x2000段结 的存中开辟出P<B的栈,将CS、D S等所有
存器的人栈中,再把栈顶的内存到PR0C,以便goUm ode过程能正确设置用户程序的栈。
因此,PR0C结构中应包含用户程序的桟信息,M T X在PR0C中设置了 u ss和u sp两项,以存储用户程 序桟的s s和s p寄存器信息。
添加u s s和u s p之后的 PR0C结构代码如下$
typedef struct proc |
struct proc !next;
int !ksp ;
int uss;
int usp ;
int kstack[ SSIZE ];
5PR0C
其中u ss在p ro c结构中的偏移量为4, u s p的偏移 量为 *,因此_ru n n in g+4 指向 PR0C 中的 uss,—running + 6指向usp。
因此goUmode的代码如下,其中USS = 4,U SP=6$
_goUmode $
mov b x,—running
mov a x,USS[ bx]
mov s s,ax
mov s p,USP[ bx]
pop ds
pop es
pop di
pop si
pop bp
pop dx
pop cx
pop bx
pop ax
iret
正如前文所述,上述代码通过PR0C结构中的u s 和u sp设好栈顶的位置,此后通过一系列p o p命令设
C P U的寄存器,从设置好用户程序的运。
当最后的i e t命令执行后,CPU始运行用户程。
3.3.2 系统调用
当运行于User space的用户程序需要内核功能时,例如运行于0x2000段中的p r o c l需要内核fo r k以建立 新进程时,其使用系统调用(s s a)调用内核中的函数。
由于用户程序与内核分别位于的内存段中,p ro c l无法通过普通的函数调用(function c a ll)来调用 核函数。
统调用需要做到:让0x1000 中的
k f o k函数获得0x2000段中p r o c l程序代码的调用参数,运 k f o k,再将结果返0x2000 中的程序代码。
其果好像p r o l运行了普通的函数调用一样,但和返 核 和用 进行传递。
核 和用 传 较为容易,其本 是在两个确定的内存进行复制,只者位于 的段中。
而C P U则需要在用 和核 的指令 运 ,CPU 进人 核,须用的 进行保存,以
核函 返 后,用 程 的 进 ,从
继续运行用户程序的代码。
用程的代码即是前述的goUmode,保存上下文的过程是goUmode 的逆过程。
而保存 后则应为C P U设 核栈,C P U开始运 核函数代码。
与L m u x操作系统一样,M T X以函数的形式进行系统调用,并在函数中触发0x80中断(INT80)。
接收 到INT80之后,C P U将当前标志位(flag)和CS、P C寄 存器压人用户程序栈保存(与 ,goUmode结尾的
i e t指令弹栈 三 ),然后将预存于指定■.的数据载人PC、CS,从 始运行与 全无关的指令。
该预存的(PC,CS)被称为中断向量(interrupt vector),中断向量保存在内存的0x0000段中。
因此可 以将内核函(0x1000)作为中断向量保存于0x0000 的指定位 。
INT80中断处理程序的部分关键代码如下$
mov b x,—running
mov s p,bx
add s p,_procSize
call _kcinth
_goUmode $
其中 procSize为 sizeof(PR0C)的值,也就是 PR0C 结构的 +代码将栈顶设 进程的PR0C的结尾,即kstaC k[]组的最后一项,然后 运行k c in th函数。
k c in th函数所做的工作即如:所 ,从用 取得系统调用的 ,根 调用内核函数,最后将函数的返回值复制回用。
由于用户程序以函数形式进 统调用,返 覆盖用户程序栈中的a s寄存器。
当k c n th返回后,CPU 执行goUmode函数以返回User space继续执行用户程。
4结论
M T X操作系统在实模式下构建了结构标准的类U N IX内核,其对硬件的要求极低,甚至可运行于8086 C P U上,为作系统微[8]和定制化提供了一个新的思路,并为嵌人式控制提供了一个新的方案。
参考文献
[1 ] K C WANG. Design and implementation of the MTX operating
system,2015 [ M ] . Switzerland: Springer International Publishing Switzerland,2015.
[2 &BACH M J. The design of the UNIX operating system,1986 [ M ].
Englewood Cliffs,NJ : Prentice -Hall,1986.
[3]TANENBAUM A S,W00DH ULL A S.操作系统设计与实
现[M].北京:电子工业出版社,2007.
[4]URESH V A H A LIA.深入理解U N IX系统内核[M].李雨,薛
磊,黄庆新,译.北京:机械工业出版社,2015.
[5]陈闳中.L in u s在嵌入式操作系统中的应用[J].同济大学学
报(自然科学版),2011,29(5):564-556.
[6]DOUGLASS B P.嵌入式实时系统开发[M].柳翔,译.北京:
机械工业出版社,2005.
[7]马毅,李霞峰,盛焕烨.基于U n i的实时操作系统设计[J].
计算机工程与应用,2001,39(4):109-110.
[8]尹凌,费斐,王晓东.一个嵌人式实时U N I X的技术研
究[J].计算机工程,2001,27(8):61-65.
(收稿日期:2018-12-21)
作者简介:
任振强(1983 -),男,硕士,研究实习员,主要研究方向:计算作系统等。