天天看點

一個作業系統的實作(2)

接上文:

http://www.cnblogs.com/SuperXJ/archive/2010/12/02/1894639.html

                                                                                                                                     xiongjian

                                                                                                                           2010.12.22  msn:[email protected]

10 下面開始程序,首先引入幾個基本原則:

              1)程序表A用來儲存程序A的資訊和程序A切換時,儲存目前A運作時寄存器資訊。定義為: PROCESSproc_table[1024]; 表示系統最多可以有1024個程序,PROCESS裡面就儲存了本程序運作時的各個寄存器資訊(這樣可以在程序切換回來的時候傳回寄存器資訊),該程序對應的LDT描述符(一般指向代碼段和資料段),最後還有一個指向GDT中該程序位置的描述符。

實作一個最簡單的程序切換系統,需要下面3個子子產品: 

時鐘中斷處理程式/程序排程子產品/至少1個主程序和2個子程序

一個程序(ring1)的最小需要的元素為程序執行體,堆棧大小和位置。另外需要GDT中有一個選擇符指向一個該程序的LDT。在時鐘中斷發生時,時鐘中斷處理函數(ring0)将esp指向将要運作的程序在程序表中的位置。

       當做到這裡,系統應該可以定時觸發時間中斷處理函數,時間中斷處理函數會輪流的調用程序A和B了。(這也是個ring0到ring1直接互相切換的過程)

到此為止,作業系統的啟動可以高于段落。

其他需要注意的是:系統調用 

系統調用的簡單實作就是程序(ring1)将參數例如:num,儲存在寄存器中,然後自己産生一個中斷,例如int 100h.表示軟體發生100H号中斷(假設中斷處理函數為sys_call)。

I/O system(注意以下都是微核心形态) 

IO首先第一個想到的就是鍵盤,其實鍵盤驅動非常簡單,隻要注意以下幾個方面即可:

1 建立鍵盤中斷處理函數

2 打開8259a的鍵盤中斷

3 解析中斷發生時的資料以确定使用者按下的具體按鍵

4 鍵盤有一個緩沖區,用于儲存使用者按鍵資訊,驅動需要及時的吧這個緩沖區的資料讀取出來,如果不是一個完整資料,需要做臨時緩存。

系統有一個固定的顯存記憶體位置,顯示的最基本原理就是N個位元組裡面儲存字元和顔色資訊,最常見的是的565色。Linux的多終端機制的一般規則為多個終端對應一個螢幕,使用者在使用一個螢幕的時候,可以随時切換到其他螢幕而好像是切換了使用者一樣。實作這樣機制的一個程序叫做TTY程序,他作為第一個微核心以為的系統程序而存在,已差別于一般的使用者程序。下面就來看看他的大概實作思路:

       Tty_task()

       {

              Init_keyboard();

              For(循環3次) init_tty(i);

              While(1)

              {

                     //依次周遊每一個tty

                     For(I= 0; i<3 ; i++)

                     {

                            Tty_read(i);//如果目前活躍的tty是我,則從鍵盤驅動中讀取鍵盤緩存

                            In_process(i,key); //将讀出的緩存存放到目前tty的緩存中,另外處理alt+Fn的切換控制台指令(即Fn)

                            Tty_write(i);

                     }

              }

       }

微核心有MM和FS,分别為記憶體管理程序和檔案系統程序,下面看看一個微核心是如何實作程序建立的。

²       1 使用者調用fork函數

²       2 fork調用sys_call(MM, FORK);  //表示消息要發給MM程序,消息内容為FORK,内部通過send_recv實作,即先發送在接收消息

²       3 send_recv内部使用int觸發IDT中的一個中斷,假設中斷處理函數為s_call(ring0)

²       4 s_call内部會将消息從寄存器中取出,并向MM程序發送消息(msg_send() ).

²       5  msg_send(sender, dest, msg) //發送者/接收者/要發送的消息體   ××發送消息××

       {

                 檢查發送者和接收者不能相等

                     檢查是否會發生死鎖,例如A->B->A  即A和B在同時互相發送消息,AB程序都會堵死在發送程式處。

                     If(接收者是處理RECEIVE狀态)

                            線上性位址(實體位址)層面将要發送的消息複制到接收者的緩存中(虛拟位址-)線性位址)。因為發送者的消息是存放在實體位址裡面的,是以必須要找到消息的實體位置才能将消息複制到接收者程序。

                     }     

                     Else 發送者處于SEND狀态,并等待一直到接收者處于RECEIVE為止,通過調用程序排程程序實作。

         }

²       6 通過msg_send的調用,在實體位址層面,消息就被複制到了接收程序中(消息可以保持在接收程序的程序表項中)。下面看看接受程序:接收程序調用msg_recv來阻塞的接收消息

msg_recv(接收者,發送者,接收消息的指針m)

{

       If(接收者有來自硬體的消息)

       If(接收者隊列裡有消息) 将接收到的消息複制到m裡。

       Else (沒有消息) 阻塞

}

²       7 到目前為止,程序可以實作發送和接收消息了。實作的根本原理還是通過實體位址的消息複制。 現在的程序有了以下狀态:發送(消息)狀态,接收(消息)狀态,運作狀态,休眠狀态。 其中 發送/接收/休眠狀态都不會獲得CPU運作機會。

,同時MM程序會不停的查詢,如果有消息,則調用do_fork真正建立程序。

從這一系列流程可以看出,微核心僅僅給上層發送和接收消息2個接口,而不關心具體實作。具體的實作是他們通過參數傳給具體的ring1程序(例如FS,MM……)來實作。

以上就是微核心的思想,同時也是一個簡單同步IPC思想。

未完待續(檔案系統+記憶體管理)

繼續閱讀