跟我一起寫作業系統(二)——史上最簡單的核心
轉載註明出處:http://www.cnblogs.com/lucasysfeng/p/4847662.html
上一講地址:http://www.cnblogs.com/lucasysfeng/p/4846119.html
專案地址:https://github.com/lucasysfeng/lucasOS
上一講我們介紹了計算機的啟動流程,並給出了一份簡單的主引導記錄程式碼,此份程式碼僅僅是顯示幾個字元,並沒有做它本應該做的事--啟動核心。本講我們首先看下核心是如何被啟動的,然後寫一個簡單的核心,用已經實現的主引導記錄配合GRUB啟動它。
如何啟動核心
前一講我們說到,計算機讀取"主引導記錄"前面446位元組的機器碼之後,會執行事先安裝的“啟動管理器”bootloader,由使用者選擇啟動哪個核心,之後就會載入核心,將控制權交給核心。GNU GRUB(GRand Unified Bootloader)就是一種bootloader,滿足多重引導規範(The Multiboot Specification),GRUB可選擇作業系統分割槽上的不同核心,下圖就是GRUB的圖形介面:
圖 GRUB介面
能夠被GRUB啟動的核心需要滿足兩個的條件:
(1) 核心的前8K位元組內必須要包含多重引導規範的頭資訊(Multiboot Header);
(2) 核心要載入在記憶體地址的1MB以上。
那麼Multiboot Header是什麼樣子的呢?它必須包含4位元組對齊的3個域(還有其他非必須域,我們不討論),如下:
魔數域(magic):標誌頭的魔數,必須等於 0x1BADB002。。
標誌域(flag):是否需要載入程式支援某些特性,我們不關心這些特性,這個標誌置為0。
校驗域(checksum):校驗等式是否成立(magic + flags + checksum = 0)
本文不討論GRUB的實現,我們會用前人已經寫好的GRUB(筆者會給出),我們要做的是完成符合GRUB啟動規範的核心。為了完成這個核心,我們需要寫少量的彙編用來在核心中加入Multiboot Header,然後用C語言寫核心入口,最後將彙編目的碼和C語言目的碼連結起來生成真正的核心。下面就讓我們一步步地完成這些吧!
第一步 彙編入口
1. 彙編程式碼如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
; 檔名 boot.asm
; Copyright: www.cnblogs.com/lucasysfeng
MBOOT_MAGIC equ 0x1BADB002 ; multiboot magic域,必須為此值
MBOOT_FLAGS equ 0x00 ; multiboot flag域, GRUB啟動時是否要做一些特殊操作
MBOOT_CHECKSUM equ -(MBOOT_MAGIC + MBOOT_FLAGS) ; multiboot checksum域,校驗上面兩個域是否正確
[BITS 32] ; 以32位編譯
section .text
dd MBOOT_MAGIC
dd MBOOT_FLAGS
dd MBOOT_CHECKSUM
dd start
[GLOBAL start]
[EXTERN kernel_main] ; 核心入口函式, EXTERN表明此符號在外部定義
start:
cli ; 禁用中斷
call kernel_main ; 呼叫核心入口函式
jmp $ ; 無限迴圈
|
在上面彙編中,我們定義了GRUB啟動需要的域MBOOT_MAGIC、MBOOT_FLAGS和MBOOT_CHECKSUM,並呼叫了核心入口函式kernel_main, kernel_main下一節實現。
2. 編譯生成目標檔案boot.o
# nasm -f elf boot.asm -o boot.o
執行上面命令後會生成目標檔案boot.o,-f elf的意思是生成ELF格式的目的碼。
第二步 核心入口
1. 核心程式碼如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
/****************************************************
# Copyright(c) www.cnblogs.com/lucasysfeng, all rights reserved
# File : kernel.c
# Author : lucasysfeng
# Description : 核心入口函式
****************************************************/
int
kernel_main()
{
// 視訊記憶體開始地址
char
*display_buf = (
char
*)0xb8000;
// 清屏
unsigned
int
i = 0;
const
unsigned
int
total = 80 * 25 * 2;
// 一屏25行,每行80個字元,每個字元2個位元組
while
(i < total)
{
display_buf[i++] =
' '
;
display_buf[i++] = 0x04;
// 顏色
}
// 顯示字元
const
char
*str =
"Hello World, welcome to kernel!"
;
for
(i = 0;
'\0'
!= *str;)
{
display_buf[i++] = *(str++);
display_buf[i++] = 0x04;
}
return
0;
}
|
0xb8000h是視訊記憶體開始的地址,讀者可以看第一講(http://www.cnblogs.com/lucasysfeng/p/4846119.html)“真實模式記憶體地址空間分佈”那張圖,找到0xb8000h這個地址。從0xb8000h這個地址開始,每2個位元組表示一個字元,前一個位元組是字元的ASCII碼,後一個位元組是這個字元的顏色和屬性,顏色和屬性此處先不用關心。這段C程式碼的其餘部分相信讀者都能看得懂,我就不過多解釋了。
2. 編譯生成目標檔案kernel.o
# gcc -m32 -c -o kernel.o kernel.c
執行上面命令後,目標檔案kernel.o就生成了。
第三步 生成核心
上面講到了能被GRUB啟動的核心需要滿足的條件:
(1) 核心的前8K位元組內必須要包含多重引導規範的頭資訊(Multiboot Header);
(2) 核心要載入在記憶體地址的1MB以上。
我們將頭資訊放在了彙編生成的目標檔案boot.o中,因此我們需要將boot.o和kernel.o連結到一起生成真正的kernel,並且這個真正的核心要載入到1MB記憶體上,為此,我們需要下面的連結指令碼和命令(關於連結指令碼的使用自行google):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
相關推薦跟我一起寫作業系統(二)——史上最簡單的核心轉載註明出處:http://www.cnblogs.com/lucasysfeng/p/4847662.html 上一講地址:http://www.cnblogs.com/lucasysfeng/p/4846119.html 專案地址:https://github.com/lucasys 跟我一起寫作業系統(一)——10分鐘寫個作業系統轉載註明出處: http://www.cnblogs.com/lucasysfeng/p/4846119.html 專案地址:https://github.com/lucasysfeng/lucasOS 想動手,但不知從何入手,是學習一門新知識普遍會遇到的尷尬點。筆 跟我一起寫 Makefile(二)三、make是如何工作的 在預設的方式下,也就是我們只輸入make命令。那麼, 1、make會在當前目錄下找名字叫“Makefile”或“makefile”的檔案。 2、如果找到,它會找檔案中的第一個目標檔案(target),在上面 跟我一起寫 Makefile(十二)隱含規則———— 在我們使用Makefile時,有一些我們會經常使用,而且使用頻率非常高的東西,比如,我們編譯C/C++的源程式為中間目標檔案(Unix下是[.o]檔案,Windows下是[.obj]檔案)。本章講述的就是一些在Makefile中的“隱含的”,早先約定了的,不需要我們再寫出來的規則。 “隱 跟我一起寫Makefile(七)awk 註意事項 ack ref 個人 c語言 分開 數據庫 特性 make 的運行——————一般來說,最簡單的就是直接在命令行下輸入make命令,make命令會找當前目錄的makefile來執行,一切都是自動的。但也有時你也許只想讓make重編譯某些文件,而不是整個工程 跟我一起寫Makefile(四)比較 命令解釋 例子 exec 上層 tab鍵 file 順序 變量傳遞 書寫命令————每條規則中的命令和操作系統Shell的命令行是一致的。make會一按順序一條一條的執行命令,每條命令的開頭必須以[Tab]鍵開頭,除非,命令是緊跟在依賴規則後面的分號後的。在命令行之間 跟我一起寫Makefile(三)image 函數名 headers 波浪 用法 日期 最好 頭文件 哪些 書寫規則————規則包含兩個部分,一個是依賴關系,一個是生成目標的方法。在Makefile中,規則的順序是很重要的,因為,Makefile中只應該有一個最終目標,其它的目標都是被這個目標所連帶出來的, 跟我一起寫Makefile:使用函數ref pos weibo blank log vdi make linu wiki 跟我一起寫Makefile:使用函數 兩個排版不一樣 書籍下載 書籍下載跟我一起寫Makefile:使用函數 【轉】跟我一起寫 Makefile軟件 linux下 是我 main c++ class 情況 如果 反斜杠 概述—— 什麽是makefile?或許很多Winodws的程序員都不知道這個東西,因為那些Windows的IDE都為你做了這個工作,但我覺得要作一個好的和professional的程序員,makef 跟我一起寫 Makefile - 6. 使用條件判斷跟我一起寫 Makefile - 6. 使用條件判斷 http://wiki.ubuntu.org.cn 6. 使用條件判斷 使用條件判斷,可以讓 make 根據執行時的不同情況選擇不同的執行分支。條件表示式可以是比較變數的值,或是比較變數和常量的值。 6.1 示例 下面 跟我一起寫 Makefile - 4. 書寫命令跟我一起寫 Makefile - 4. 書寫命令 http://wiki.ubuntu.org.cn 4. 書寫命令 每條規則中的命令和作業系統 shell 的命令列是一致的。make 會按順序一條一條的執行命令,每條命令的開頭必須以 Tab 鍵開頭,除非命令是緊跟在依賴規則後面 跟我一起寫 Makefile - 2. Makefile 介紹跟我一起寫 Makefile - 2. Makefile 介紹 http://wiki.ubuntu.org.cn 2. Makefile 介紹 make 命令執行時,需要一個 Makefile 檔案,以告訴 make 命令如何去編譯和連結程式。 以下示例來源於 GNU 的 跟我一起寫 Makefile - 1. 概述跟我一起寫 Makefile - 1. 概述 http://wiki.ubuntu.org.cn 1. 概述 什麼是 Makefile?Windows 的整合開發環境 (integrated development environment, IDE) 完成了 Makefile 的 跟我一起寫Makefile:MakeFile介紹makefile 介紹 make命令執行時,需要一個 makefile 檔案,以告訴make命令如何去編譯和連結程式。 首先,我們用一個示例來說明makefile的書寫規則。以便給大家一個感性認識。這個示例來源於gnu的make使用手冊,在這個示例中,我們的工程有8個 跟我一起寫Makefile:書寫命令轉載: 書寫命令 每條規則中的命令和作業系統Shell的命令列是一致的。make會按順序一條一條的執行命令,每條命令的開頭必須以[Tab]鍵開頭,除非,命令是緊跟在依賴規則後面的分號後的。在命令列之間中的空格或是空行會被忽略,但是如果該空格或空行是以Tab鍵開頭的,那 跟我一起寫Makefile:使用變數轉載: 使用變數 在Makefile中的定義的變數,就像是C/C++語言中的巨集一樣,他代表了一個文字字串,在Makefile中執行的時候其會自動原模原樣地展開在所使用的地方。其與C/C++所不同的是,你可以在Makefile中改變其值。在Makefile中,變數可以 跟我一起寫Makefile:使用條件判斷轉載: 使用條件判斷 使用條件判斷,可以讓make根據執行時的不同情況選擇不同的執行分支。條件表示式可以是比較變數的值,或是比較變數和常量的值。 示例 下面的例子,判斷$(CC)變數是否“gcc”,如果是的話,則使用GNU函式編譯目標。 libs_for_gcc 跟我一起寫Makefile:隱含規則轉載: 隱含規則 在我們使用Makefile時,有一些我們會經常使用,而且使用頻率非常高的東西,比如,我們編譯C/C++的源程式為中間目標檔案(Unix下是[.o]檔案,Windows下是[.obj]檔案)。本章講述的就是一些在Makefile中的“隱含的”,早先約定 跟我一起寫Makefile:使用make更新函式庫檔案轉載: 使用make更新函式庫檔案 函式庫檔案也就是對Object檔案(程式編譯的中間檔案)的打包檔案。在Unix下,一般是由命令"ar"來完成打包工作。 函式庫檔案的成員 一個函式庫檔案由多個檔案組成。你可以以如下格式指定函式庫檔案及其組成: archi 跟我一起寫 Makefile-陳浩makefile:是告訴編譯器(交叉工具鏈)如何去編譯、連結一個工程的規則。 一、概述 什 麼是makefile?或許很多Winodws的程式設計師都不知道這個東西,因為那些Windows的IDE都為你做了這個工作,但我覺得要作一個好的和 professi |