999精品在线视频,手机成人午夜在线视频,久久不卡国产精品无码,中日无码在线观看,成人av手机在线观看,日韩精品亚洲一区中文字幕,亚洲av无码人妻,四虎国产在线观看 ?

MTX操作系統內核與啟動流程分析

2019-12-27 21:05:44任振強
網絡安全與數據管理 2019年2期
關鍵詞:進程程序設置

任振強

(國家知識產權局專利局專利審查協作天津中心,天津 300304)

0 引言

MTX是美國華盛頓大學電子工程與計算機科學系教授WANG K C于2015年發布的一款小型操作系統[1],該系統基于Intel x86體系結構,具有結構標準的類Unix內核,可在x86的實模式下實現內存管理,進程控制,進程調度,線程、進程間消息、管道、中斷處理,輸入輸出設備驅動等典型的UNIX/Linux內核[2]功能。此外,MTX還支持對稱多處理器結構(SMP),并使用了與Linux兼容的EXT2文件系統;其所有功能模塊均能在編譯時進行裁剪選擇,編譯后內核體積可以控制在幾十甚至十幾KB。而且由于MTX內核模塊間耦合度極低,因此可以自由調整進程調度功能以滿足實時性要求。整體而言,MTX操作系統具有高度的靈活性和較低的學習門檻,非常適合于課堂教學和二次開發。

目前主流的類UNIX操作系統均不在實模式下運行[3-4],國內開發者雖然對UNIX/Linux內核設計原理較熟悉,但對MTX的實現方案并不了解。因此本文選擇對MTX內核的實現代碼進行研究,重點分析靠近底層硬件的進程切換和系統調用代碼,并且對系統引導程序設計要點進行總結,整體通過進程視角對MTX操作系統進行初步分析。

1 內核編譯

MTX操作系統內核在Linux環境下使用BCC(Bruce’s C Compiler)Cross-Compiling Package進行編譯和鏈接。MTX使用BCC而不是GCC進行編譯,因為BCC不僅能編譯生成8086兼容的16位匯編代碼,還可以基于單一內存段(one-segment memory)模型對代碼進行編譯。

工作于實模式的CPU以64 KB分段的形式訪問物理內存的最低1 MB地址,CPU設置了4個16位段寄存器CS、DS、SS、ES,分別用于標記代碼(Code)段、數據(Data)段、棧(Stack)段和附加(Extra)段。BCC編譯生成的CS、DS和SS完全重合,相當于只有一個段,簡化了內存模型,方便了程序的初始化。由于只有一個段,程序可以被載入內存中任意一個可用段中運行,加載和啟動更為靈活。

2 內核引導

內核作為MTX操作系統的第0進程,其加載和啟動方式有一定特殊性,同時又影響著其他進程的加載和運行。

2.1 引導程序的加載

計算機硬件啟動后首先將BIOS載入內存運行,BIOS完成自檢并尋找可啟動設備進行啟動。具體而言,BIOS首先將啟動設備的起始512 B載入內存地址(0x0000,0x7C00),也就是物理地址0x07C00,隨后跳轉到該內存地址運行指令。該起始512 B即為引導程序。完整的引導程序往往大小會超過512 B,因此當計算機運行該512 B的代碼時,需要完成以下步驟:將引導程序的剩余部分載入內存運行,尋找操作系統內核并將其載入內存,最后運行操作系統內核的起始代碼。

在系統引導的過程中,引導程序會將其載入段地址為0x1000的內存段中,隨后引導程序會跳轉到0x1000段執行操作系統內核代碼。之所以將內核載入到0x1000段,一是為了給內核足夠的內存空間,二是為了方便進程管理和系統調用。MTX將第 1個用戶程序加載到內存0x2000段、第 2個用戶程序加載到0x3000段,并以此類推。當用戶程序執行系統調用后,CPU將返回0x1000段運行內核代碼。

2.2 引導程序分析

引導程序的前512 B已經被加載到內存中,該512 B程序運行時不能覆蓋自身,因此通常將完整的引導程序加載到另外的內存地址。MTX的選擇與早期Linux內核zImage的引導程序相同[5],即內存的0x9000段。

引導程序運行時沒有任何庫可用,只能使用BIOS中斷INT13提供的讀寫功能。當完整的引導程序加載到0x9000段之后,執行以下指令:

jmpi start,0x9000

start:

mov ax,cs

mov ds,ax

mov ss,ax

mov es,ax

mov sp,8192

call _main

jmpi指令將代碼段寄存器設置為0x9000后執行start處的代碼。由于BCC編譯生成的CS、DS和SS段重合,因此該段代碼使用4個mov語句將所有段寄存器都設置為0x9000,之后通過“mov sp,8192”將棧指針設在偏移量為8KB的地址上,為后面的main函數提供了足夠的棧空間,隨后調用內核的main函數。可見,由于引導程序是由自己的前512 B代碼將自身載入內存,因此也必須自己為自己設置好所有的寄存器狀態。

此時操作系統尚未載入內存中,因此讀磁盤寫內存的I/O工作依然要通過BIOS中斷INT13來完成。main函數在EXT2文件系統中尋找到MTX內核文件,并將其載入內存的0x1000段。從main函數返回后,引導程序執行“jmpi 0,0x1000”,該指令將CPU的代碼段寄存器設置為內核加載地址0x1000,并運行段內第一條代碼。內核正式啟動。

3 MTX內核的進程實現

MTX內核main函數的部分工作可簡化為如下算法:

while (1) {

if (readyQueue)

tswitch();

}

上述代碼只要readyQueue不為空則運行tswitch進行進程切換。readyQueue中保存著所有可運行的進程,tswitch從readyQueue中取出一個進程并將上下文(context)切換為該進程的上下文。完成切換之后,CPU將運行與main函數完全無關的另一個進程。如果其他進程運行tswitch()后又切換回上述內核進程,則此時CPU繼續運行tswitch之后的下一條語句。

要理解進程切換,必須對進程的數據結構進行了解。

3.1 進程控制塊

操作系統使用一個進程代表一個程序的執行,內核通常使用一個進程控制塊(Process Control Block,PCB)代表一個進程[6]。MTX的進程控制塊具有如下結構:

typedef struct proc {

struct proc *next;

int *ksp;

int kstack[SSIZE];

} PROC

內核使用全局變量PROC proc[NPROC]保存系統中所有的進程,因此系統最多可以建立NPROC個進程。main函數在運行while(1)循環之前完成以下步驟:初始化proc[]數組,設置好proc[0]并將其關聯給內核自身,建立第一個程序的PROC結構proc[1],并將proc[1]加入readyQueue中。因此第一次運行while(1)循環時,判斷readyQueue不為空后,系統切換到proc[1]進程開始運行內核以外的第一個程序。

PROC中的next指針指向下一個進程,進程因此可以被放入進程隊列中,如前文中所述的readyQueue。ksp用于存放內核的棧指針;進程的內核棧kstack則位于PROC結構的最尾端。

PROC中next、ksp和kstack三個變量的順序至關重要:next是struct proc的第1項,ksp是第2項,kstack是最后一項。當running保存當前進程PROC結構的內存地址時,running+2為該PROC的ksp的地址,而running+sizeof(PROC)正好是其kstack數組中最后一項的內存地址,也就是空棧棧頂的位置。

3.2 進程切換

進程切換的過程非常簡單:將當前進程的上下文存入當前進程的PROC,從另一個PROC中取出另一進程的上下文,最后用新進程的上下文設置CPU,從而使CPU運行新進程。MTX操作系統用全局變量PROC *running指向當前運行的進程。tswitch的代碼如下:

_tswitch:

SAVE:

push ax

push bx

push cx

push dx

push bp

push si

push di

pushf

mov bx,_running

mov 2[bx],sp

FIND: call _scheduler

RESUME:

mov bx,_running

mov sp,2[bx]

popf

pop di

pop si

pop bp

pop dx

pop cx

pop bx

pop ax

ret

SAVE過程保存上下文,push和pushf語句將MTX用到的CPU寄存器值壓入running的kstack棧中,再將running的值(即當前進程的PROC結構的地址)賦給bx,由之前的討論可知bx+2即為該PROC中ksp變量的地址,因此“mov 2[bx],sp”語句將棧頂地址保存在ksp變量中。至此,當前進程的上下文被保存至running的kstack棧當中。

與SAVE對應的RESUME負責對進程上下文的恢復,其完全是SAVE的逆向過程。保存和恢復之間的是進程調度函數scheduler。scheduler將當前進程的PROC放入readyQueue,從readyQueue中取出一個新PROC,并將running指向該PROC。而RESUME函數通過彈棧設置CPU寄存器,從而設置好新進程的上下文。

由上述代碼還可以看出,MTX的進程調度功能由scheduler完成,其不與系統其他部分耦合,可單獨更換以滿足實時性要求。

3.3 進程建立和系統調用

MTX內核的main函數在初始階段建立第一個用戶程序的PROC結構proc[1],tswitch()之后系統運行該程序。MTX內核建立新進程的過程被稱為fork,MTX內核中的函數原型為PROC *kfork(char *filename),kfork可以通過filename參數指定程序的路徑,并返回該程序對應的PROC的指針。例如,內核可在初始階段運行kfork(“/bin/shell”),將shell程序作為第一個程序,以允許用戶通過shell執行命令。

與Linux相同,MTX將內核所在的內核空間(Kernel space)與用戶程序所在的用戶空間(User space)分離。MTX的內核加載至內存0x1000段,proc1程序加載到0x2000段。因此0x1000段為內核空間,0x2000段為用戶空間。操作系統的核心功能由內核程序完成,當運行于User space的用戶程序需要使用核心功能時,其通過系統調用運行相應的內核函數。系統調用被稱為System call或syscall[7]。當用戶程序運行系統調用之后,CPU跳轉到0x1000段運行內核代碼,該過程通常被稱為陷入內核(trap)。而當內核代碼運行完畢之后,CPU返回User space內存段繼續運行用戶程序的代碼。

3.3.1進程的建立

MTX將內核加載到0x1000段,將用戶程序Uimage加載到0x2000、0x3000等段。內核的CS、DS、SS段寄存器均為0x1000,而用戶程序的段寄存器值為其所在的內存段地址。因此,fork建立第i進程的過程,就是將用戶程序Uimagei加載到內存0x(i+1)000段并初始化proc[i]的過程。加載用戶程序的原理與加載內核的原理相同,而初始化過程就是將proc[i]中的變量賦值為該進程對應的值。因此要了解fork如何賦值PROC結構中的變量,必須理解該變量在進程中代表的含義。

以第1進程proc1為例:MTX內核通過kfork語句加載Uimage1并初始化proc[1],執行tswitch()之后,內核設置Uimage1的上下文,并最終使CPU進入內存的0x2000段運行Uimage1。tswitch函數最后的ret語句設置CPU的返回地址,即CPU要執行的下一條指令的地址。該返回地址存儲在運行完“pop ax”之后的棧中,也就是kstack數組的最后一項kstack[SSIZE-1]之中。執行ret之后CPU將執行kstack[SSIZE-1]保存地址的語句,開始設置Uimage1的上下文。MTX內核中設置Uimage上下文的過程為goUmode函數。

與tswitch函數類似,goUmode函數使用pop類指令設置Uimage1運行上下文的CPU寄存器。Uimage1被加載到內存0x2000段,因此其CS、DS、ES均應為0x2000。這三個寄存器以及ax、bx等其他寄存器的值均保存在用戶程序的棧中,以便通過pop類命令進行彈棧。

一個用戶程序加載到哪個段無法由程序自身決定,因此用戶程序的棧是在kfork過程中建立的。kfork將Uimage1加載到0x2000段之后,手動在0x2000段結尾的空內存中開辟出proc1的棧,將CS、DS等所有寄存器的值寫入棧中,再把棧頂的內存地址寫回到PROC,以便goUmode過程能正確設置用戶程序的棧頂。

因此,PROC結構中應包含用戶程序的棧信息,MTX在PROC中設置了uss和usp兩項,以存儲用戶程序棧的ss和sp寄存器信息。添加uss和usp之后的PROC結構代碼如下:

typedef struct proc {

struct proc *next;

int *ksp;

int uss;

int usp;

int kstack[SSIZE];

} PROC

其中uss在proc結構中的偏移量為4,usp的偏移量為6,因此_running+4指向PROC中的uss,_running+6指向usp。因此goUmode的代碼如下,其中USS=4,USP=6:

_goUmode:

mov bx,_running

mov ax,USS[bx]

mov ss,ax

mov sp,USP[bx]

pop ds

pop es

pop di

pop si

pop bp

pop dx

pop cx

pop bx

pop ax

iret

正如前文所述,上述代碼通過PROC結構中的uss和usp設置好棧頂的位置,此后通過一系列pop命令設置CPU的寄存器,從而設置好用戶程序的運行上下文。當最后的iret命令執行后,CPU正式開始運行用戶程序。

3.3.2系統調用

當運行于User space的用戶程序需要內核功能時,例如運行于0x2000段中的proc1需要內核fork以建立新進程時,其使用系統調用(syscall)調用內核中的函數。由于用戶程序與內核分別位于不同的內存段中,proc1無法通過普通的函數調用(function call)來調用內核函數。因此系統調用需要做到:讓0x1000段中的kfork函數獲得0x2000段中proc1程序代碼的調用參數,運行kfork,再將結果返回給0x2000段中的程序代碼。其效果好像proc1運行了普通的函數調用一樣,但參數和返回值跨越內核空間和用戶空間進行傳遞。

跨越內核空間和用戶空間傳遞參數較為容易,其本質上是在兩個確定的內存地址之間進行復制,只不過二者位于不同的段中。而CPU則需要在用戶空間和內核空間的指令之間切換運行,因此在CPU進入內核空間前,必須對用戶空間的上下文進行保存,以便當內核函數返回之后,對用戶程序的上下文進行恢復,從而繼續運行用戶程序的代碼。恢復用戶程序上下文的代碼即是前述的goUmode,保存上下文的過程是goUmode的逆過程。而保存上下文之后則應為CPU設置內核棧,并使CPU開始運行內核函數代碼。

與Linux操作系統一樣,MTX以函數的形式進行系統調用,并在函數中觸發0x80中斷(INT80)。接收到INT80之后,CPU將當前標志位(flag)和CS、PC寄存器壓入用戶程序棧保存(與此對應,goUmode結尾的iret指令彈棧恢復這三個值),然后將預存于指定地址的數據載入PC、CS,從而開始運行與當前完全無關的指令。該預存的(PC,CS)被稱為中斷向量(interrupt vector),中斷向量保存在內存的0x0000段中。因此可以將內核函數地址(0x1000)作為中斷向量保存于0x0000段的指定位置。

INT80中斷處理程序的部分關鍵代碼如下:

mov bx,_running

mov sp,bx

add sp,_procSize

call _kcinth

_goUmode:

其中procSize為sizeof(PROC)的值,也就是PROC結構的大小。因此上述代碼將棧頂設置在當前進程的PROC結構的結尾,即kstack[]數組的最后一項,然后運行kcinth函數。kcinth函數所做的工作即如前文所述,從用戶空間取得系統調用的參數,根據參數調用內核函數,最后將函數的返回值復制回用戶空間。由于用戶程序以函數形式進行系統調用,因此返回值應覆蓋用戶程序棧中的ax寄存器。當kcinth返回后,CPU執行goUmode函數以返回User space繼續執行用戶程序。

4 結論

MTX操作系統在實模式下構建了結構標準的類UNIX內核,其對硬件的要求極低,甚至可運行于8086 CPU上,為操作系統微型化[8]和定制化提供了一個新的思路,并為嵌入式控制提供了一個新的方案。

猜你喜歡
進程程序設置
中隊崗位該如何設置
少先隊活動(2021年4期)2021-07-23 01:46:22
債券市場對外開放的進程與展望
中國外匯(2019年20期)2019-11-25 09:54:58
試論我國未決羈押程序的立法完善
人大建設(2019年12期)2019-05-21 02:55:44
“程序猿”的生活什么樣
英國與歐盟正式啟動“離婚”程序程序
環球時報(2017-03-30)2017-03-30 06:44:45
本刊欄目設置說明
中俄臨床醫學專業課程設置的比較與思考
創衛暗訪程序有待改進
中國衛生(2015年3期)2015-11-19 02:53:32
社會進程中的新聞學探尋
民主與科學(2014年3期)2014-02-28 11:23:03
地鐵出入段線轉換軌設置
主站蜘蛛池模板: 日韩成人免费网站| 丝袜美女被出水视频一区| 99免费在线观看视频| 91久草视频| 在线观看欧美国产| 国产欧美专区在线观看| 成人福利在线观看| 色婷婷电影网| 欧美在线导航| 乱色熟女综合一区二区| 午夜a视频| 亚洲第一在线播放| 成人国内精品久久久久影院| 亚洲激情区| 国产精品久久久久久搜索| 亚洲乱码在线视频| 视频二区中文无码| 日韩无码黄色网站| 欧美激情第一区| 久久国产亚洲偷自| 日韩欧美国产成人| 思思热在线视频精品| 性色在线视频精品| 亚洲伊人电影| 首页亚洲国产丝袜长腿综合| 亚洲国产理论片在线播放| 亚洲精品色AV无码看| 无码啪啪精品天堂浪潮av| 国产精彩视频在线观看| 成人午夜视频免费看欧美| 久久这里只有精品2| 国产精品永久在线| 日韩欧美国产中文| 青草精品视频| 亚洲欧美日韩中文字幕一区二区三区| 欧美一区国产| 中文字幕永久在线看| 亚洲人成在线精品| 福利一区在线| 四虎成人在线视频| 色综合成人| 日韩国产高清无码| 成人无码一区二区三区视频在线观看| 激情综合五月网| 久久国产毛片| 9966国产精品视频| 国产精品福利导航| 中文字幕无码中文字幕有码在线| 亚洲国产系列| 伊人查蕉在线观看国产精品| 亚洲无码久久久久| 免费jizz在线播放| 伊人91在线| 成人国产精品视频频| 欧美一级99在线观看国产| 在线日本国产成人免费的| 国产成人av一区二区三区| 伊人精品视频免费在线| 亚洲精品天堂在线观看| 国产亚洲精久久久久久久91| 久久精品国产精品国产一区| 一本久道久久综合多人| 久久99热66这里只有精品一| 欧美在线网| aaa国产一级毛片| 五月激情婷婷综合| 国产欧美日韩视频怡春院| 国产美女一级毛片| a毛片在线免费观看| 国产网站免费| 天堂av综合网| 国产乱视频网站| 91高清在线视频| 一本大道视频精品人妻 | 欧美一区二区福利视频| 好吊妞欧美视频免费| 亚洲视频无码| 亚洲国模精品一区| 免费国产高清精品一区在线| 人妻精品久久久无码区色视| 亚洲国产系列| 91国内视频在线观看|