Cosmos里程碑1--C#開源操做系統學習系列四

使用的代碼包爲cosmos14395.zip,如下把COSMOS里程碑1簡稱爲COSMOS MS1或 MS1 COSMOS

申請:因爲本篇內容涉及的技術的東西太多,小弟水平有限,若有思想認識上的錯誤,歡迎你們指正。

對於IBM-PC兼容機的硬件啓動流程我目前理解是這樣的:通電->BIOS初始化與自檢->CPU初始化->加載硬盤的0磁道0柱面1扇區的內容進內存並開始執行這一部分的內容。到此,硬件的過程—注意是硬件--就走完了,剩下的就都交給0磁道0柱面1扇區的程序來執行,這裏面的東西就是咱們程序員要作的東西了。

這裏若是沒有操做系統的話,那麼從0磁道0柱面1扇區開始執行的程序就是咱們本身寫的程序,但這樣一次只能執行一個,很浪費硬件資源,若是要換別的程序的話還得從新啓動一次硬件,因此咱們但願這個首先執行的程序能夠一直運行,而後再向這個程序發出命令,讓這個程序來執行咱們想要執行的程序,這樣就能夠不用重啓硬件就能運行多個程序了,慢慢地這個咱們對其發出命令讓其運行別的程序的程序就變成了咱們所謂的操做系統了。

隨着操做系統的發展,現代操做系統的通常都須要作如下工做:

1. 進程管理
2. 內存管理
3. IO管理
4. 文件系統管理
(以上爲參考《操做系統的設計與實現》一書)

對於咱們此次要分析的COSMOS MS1,那麼他實現了以上哪些功能呢,嚴格來講都沒實現(第一個里程碑版本嘛,能運行就能夠了),要說的話能夠說實現了一些IO管理上的功能,如向顯示器上輸出字符和相應鍵盤輸入。下面經過一副圖來講一下COSMOS
MS1操做系統(即PC機軟件部分)的啓動過程:linux

再說明一下,本版本使用VS2010編譯以後彷佛沒法正常運行,這裏是我我的的理解:里程碑1的程序仍是VS2008的項目,若是使用VS2010的朋友在打開項目以後會提示升級,升級完後編譯會出現部分沒法編譯經過的狀況,是由於升級以後部分項目升級成使用.net 4.0的框架,而部分項目仍是用的.net 2.03.5framework,當使用.net 2.0.net 3.5的項目引用了.net 4.0項目的程序集時,是沒法經過編譯的,這時儘管把這些項目該爲使用.net 4.0framework後能夠正常啓動進到編譯界面,可是編譯操做系統的過程當中會出現「未將引用設置到對象」錯誤,緣由不明………..

好了,瞭解了流程就直接上代碼,跟着代碼逐行進行說明,找到Program文件,定位到如下代碼git

/// <summary>
/// 爲何這個是程序的開始函數,請看小弟的上一篇拙文 :)
/// </summary>
publicstaticvoidInit()
{
// 初始化硬件
Kernel.Boot.Default();
// 加載一些在硬件設置完畢以後,程序啓動以前須要運行的一些東西,COSMOS中每個須要在這裏運行的東西叫作一個Stage(不知道操做系統理論中是否是有這麼一個概念?),好比說一些歡迎詞和版權聲明之類的。這加載進來的是一個歡迎語的Stage
Kernel.Staging.DefaultStageQueue stages = newCosmos.Kernel.Staging.DefaultStageQueue();
// 運行上一步加載的Stage
stages.Run();
// 剩下的你們應該都能看得懂了
Randommt = newRandom();
intnum
= mt.Next();

System.Console.WriteLine(
" I am thinking of a number between 0 and 100. What is it? " );
System.Console.ForegroundColor
= ConsoleColor.Blue;
System.Console.Write(
" Take a guess: " );
System.Console.ForegroundColor
= ConsoleColor.White;
short guess = short .Parse(System.Console.ReadLine());

while (guess != num)
{
System.Console.ForegroundColor
= ConsoleColor.Red;
if (guess > num)
System.Console.WriteLine(
" Too high. " );
else
System.Console.WriteLine(
" Too low. " );

System.Console.ForegroundColor
= ConsoleColor.Blue;
System.Console.Write(
" Take another guess: " );
System.Console.ForegroundColor
= ConsoleColor.White;
guess
= short .Parse(System.Console.ReadLine());
}

System.Console.WriteLine(
" You got it!!!! " );

stages.Teardown();
}


主要分析一下Kernel.Boot.Default()這個函數幹了什麼事,前面一大堆理論中關於CPU,內存,IO初始化這些的操做都是在這裏面完成的程序員

public static void Default() {
// Init Heap first - Hardware loads devices and they need heap
// 竟然是先在內存中初始化堆(就是開闢堆空間) 還覺得是先對CPU進行設置呢……
// 初始化堆的過程其實就是一個在系統中創建各類不一樣的對象的過程,用這些對象來對內存進行管理
Heap.CheckInit();

// 如今該是設置CPU和初始化IO了,稍後對該函數進行分析
Cosmos.Hardware.PC.Global.Init();

// Now init kernel devices and rest of kernel
// 對設備進行初始化,看名字這應該是個鍵盤 
Keyboard.Initialize();
}

再看一下Cosmos.Hardware.PC.Global.Init()裏面作了什麼編程

View Code
public static void Init() {
// 終於到CPU了 
// 這裏先是new 了一個處理器,可是從函數的帶來看這個處理器什麼都沒作,那玄機就是在Processor這個類的構造函數裏面了。跟進去能夠看到,能夠看到構造函數裏面建立了GDT(簡單的說就是對於x86的CPU,若是要使用保護模式的話就須要建立一個GDT,並對它進行設置來開啓CPU的保護模式功能),可是,因爲是MS1(里程碑1),實現程度還很小,建立GDT只是一個空操做,實際什麼也沒作,估計會在後續版本中添加進來。
mProcessor = new Processor();
// 對中斷控制器
Bus.CPU.PIC.Init();

// All old.. need to port ----------------
// 對串口進行初始化
HW.Serial.InitSerial( 0 );
// 對調試工具進行初始化(這個應該是在初期才使用的吧,商業操做系統上在這裏應該沒有調試相關的代碼)
HW.DebugUtil.Initialize();
HW.DebugUtil.SendMessage(
" Logging " , " Initialized! " );
// 初始化時鐘?不知道有啥用
HW.PIT.Initialize(Tick);

// Partially new
// 初始化中斷處理程序,此處是掛在不一樣的處理程序到對應的中斷向量號上
Interrupts.Init();
// end partially new

// 初始化ATA存儲設備,一般指的是硬盤,此處傳入的參數是一個委託,委託內容爲一個死循環,也就是沒有作任何實現,估計之後會補上
HW.Storage.ATA.Initialize(Sleep);

// 建立IDT,若是要使用CPU的分頁功能就必須建立一個IDT,並對其進行設置。這裏這個函數也是沒有作任何實現,由於仍是MS1,COSMOS能作的事情還不多,不必使用到CPU的分頁功能。
HW.CPU.CreateIDT();
// end old -----------------

// 把鍵盤添加到系統設備中
HW.Device.Add( new Bus.CPU.Keyboard());
}


這樣就算是基本完成了,固然,對於不一樣的操做系統,初始化的流程可能會不同,這得根據實際的硬件狀況來決定。app

以上的初始化函數中大量調用了這個操做:void Write8(UInt16 aPort, byte aData)框架

這個是直接往端口中寫入數據,根據IBM-PC兼容機的端口說明,對不一樣的端口進行初始化其實就是往相應的端口中寫入不一樣的數據(但一般都是寫入數據0dom

這裏完了以後咱們再跳回到上一層函數,看看Keyboard.Initialize()裏面作了什麼ide

View Code
//這是一個鍵盤設備的初始化函數,對於一個設備,COSMOS中使用相應的類和對象來實現設備的功能,之後支持的設備多了的話,這些初始化函數也可能會增多。
public static void Initialize() {
mBuffer
= new Queue<uint>
(BufferSize);

// Old

Hardware.Keyboard.Initialize(HandleScancode);
// New


mKeys
= new List<KeyMapping>(128
);
//如下都是添加字符的映射關係進映射關係表

#region Letters
AddKey(
0x10, 'q' );
AddKey(
0x100000, 'Q'
);
AddKey(
0x11, 'w'
);
AddKey(
0x110000, 'W'
);
AddKey(
0x12, 'e'
);
AddKey(
0x120000, 'E'
);
AddKey(
0x13, 'r'
);
AddKey(
0x130000, 'r'
);
AddKey(
0x14, 't'
);
AddKey(
0x140000, 'T'
);
AddKey(
0x15, 'y'
);
AddKey(
0x150000, 'Y'
);
AddKey(
0x16, 'u'
);
AddKey(
0x160000, 'U'
);
AddKey(
0x17, 'i'
);
AddKey(
0x170000, 'I'
);
AddKey(
0x18, 'o'
);
AddKey(
0x180000, 'O'
);
AddKey(
0x19, 'p'
);
AddKey(
0x190000, 'P'
);

AddKey(
0x1E, 'a'
);
AddKey(
0x1E0000, 'A'
);
AddKey(
0x1F, 's'
);
AddKey(
0x1F0000, 'S'
);
AddKey(
0x20, 'd'
);
AddKey(
0x200000, 'D'
);
AddKey(
0x21, 'f'
);
AddKey(
0x210000, 'F'
);
AddKey(
0x22, 'g'
);
AddKey(
0x220000, 'G'
);
AddKey(
0x23, 'h'
);
AddKey(
0x230000, 'H'
);
AddKey(
0x24, 'j'
);
AddKey(
0x240000, 'J'
);
AddKey(
0x25, 'k'
);
AddKey(
0x250000, 'K'
);
AddKey(
0x26, 'l'
);
AddKey(
0x260000, 'L'
);

AddKey(
0x2C, 'z'
);
AddKey(
0x2C0000, 'Z'
);
AddKey(
0x2D, 'x'
);
AddKey(
0x2D0000, 'X'
);
AddKey(
0x2E, 'c'
);
AddKey(
0x2E0000, 'C'
);
AddKey(
0x2F, 'v'
);
AddKey(
0x2F0000, 'V'
);
AddKey(
0x30, 'b'
);
AddKey(
0x300000, 'B'
);
AddKey(
0x31, 'n'
);
AddKey(
0x310000, 'N'
);
AddKey(
0x32, 'm'
);
AddKey(
0x320000, 'M'
);
#endregion


#region digits
AddKey(
0x1, '`' );
AddKey(
0x10000, '~'
);
AddKey(
0x2, '1'
);
AddKey(
0x20000, '!'
);
AddKey(
0x3, '2'
);
AddKey(
0x30000, '@'
);
AddKey(
0x4, '3'
);
AddKey(
0x40000, '#'
);
AddKey(
0x5, '4'
);
AddKey(
0x50000, '$'
);
AddKey(
0x6, '5'
);
AddKey(
0x60000, '%'
);
AddKey(
0x7, '6'
);
AddKey(
0x70000, '^'
);
AddKey(
0x8, '7'
);
AddKey(
0x80000, '&'
);
AddKey(
0x9, '8'
);
AddKey(
0x90000, '*'
);
AddKey(
0xA, '9'
);
AddKey(
0xA0000, '('
);
AddKey(
0xB, '0'
);
AddKey(
0xB0000, ')'
);

#endregion


#region Special
AddKey(
0x1C, '\n' );
AddKey(
0x1C0000, '\n'
);
AddKey(
0x39, ' '
);
AddKey(
0x390000, ' '
);
AddKey(
0x0E, '\u0968'
);
AddKey(
0x0E0000, '\u0968'
);
#endregion


#region Punctuation
AddKey(
0x34, '.' );
AddKey(
0x340000, '>'
);
#endregion

}


好了,硬件的設置(初始化)總算完了,讓咱們回到最上層的函數看看接下來的是什麼。函數

在這以後操做系統的任務就算是基本完成了,剩下的就應該是程序的調度運行的工做了,從源代碼中能夠看到COSMOS是直接運行了一個猜數的程序,咱們看一下運行截圖:工具

好了,COSMOS MS1的啓動流程和運行到這裏就算是結束了。可是還有幾個問題沒有解開,好比:System.Console.WriteLinestring)這個函數。對於在.net framework環境下編程的朋友可能尚未意識到,問題在什麼地方。

首先System.Console.WriteLine是向顯示器上顯示字符,可是在咱們剛纔的代碼中沒有看到與顯示器設備初始化相關的代碼,在.net 環境下之因此可以向顯示器上輸出字符是由於.net framework在程序啓動以前已經進行了這部份相關代碼的加載,當程序中遇到System.Console.WriteLine相似的函數調用時,實際上是調用的.net framework中的代碼來實現的,這就是爲何咱們在編寫.net 程序的時候須要引入相應的dll,這些加載代碼就在這些dll裏面。

可是COSMOS是獨立於.net framework來運行的,也就是說COSMOS在運行時是沒加載過任何.net framework中的dll,這部分功能的實現COSMOS是經過編寫本身的程序庫(Plugs)來完成的,這個部分上一篇文章介紹IL2CPU編譯器時小小地涉及了一下,更多的內容將在下一遍文章中說明,呵呵(誒呀!誰扔過來的雞蛋!)

歡迎你們實踐學習交流,任何意見和錯誤都歡迎指出,一塊兒學習,共同進步 J

廣告時間:歡迎光臨小弟的淘寶話費充值小店捧場,呵呵

參考資料:

《程序員的自我修養鏈接、裝載與庫》

《操做系統的設計與實現》--上冊

《深度探索C++對象模型》

鳥哥的LINUX私房菜

Intel Vol 3A System Programming Guide Part 1

《編譯原理》「龍書」第二版

相關文章
相關標籤/搜索