Linux bootloader 編寫方法

來源:互聯網
上載者:User

對於移植 linux 到其它開發板的人來說,編寫 boot loader 是一個不可避免的過程。對於學習linux的人來講,編寫 bootloader 也是一個很有挑戰性的工作。本文通過對 linux引導協議進行分析,詳細闡述了如何編寫一個可以在 i386 機器上引導 2.4.20核心的基本的bootloader。
1.概述

linux運行在保護模式下,但是當機器啟動複位的時候卻處於實模式下。所以寫bootloader做的工作也是在實模式之下的。

linux的核心有多種格式,老式的zImage和新型的bzImage。它們之間最大的差別是對於核心體積大小的限制。由於zImage核心需要放在實模式1MB的記憶體之內,所以其體積受到了限制。目前採用的核心格式大多為bzImage,這種格式沒有1MB記憶體限制。本文以下部分主要以bzImage為例進行分析。

2.bzImage格式核心的結構

bzImage核心從前向後分為3個部分,前512位元組被稱為bootsect,這就是磁碟片引導linux時用到的bootloader,如果不從磁碟片引導,這部分就沒有用,其中儲存了一些編譯時間產生的核心啟動選項的預設值。從512個位元組開始的512*n個位元組稱為setup部分,這是linux核心的實模式部分,這部分在實模式下運行,主要功能是為保護模式的linux核心啟動準備環境。這個部分最後會切換進入保護模式,跳轉到保護模式的核心執行。最後的部分就是保護模式的核心,也就是真正意義上的linux核心。其中n的大小可以從bootsect後半部得到,詳細地址可以參閱linux boot protocol。

3.引導過程概述

第一步,開啟冰箱門;第二步把大象放到冰箱裡……不要笑,過程就是這麼簡單。首先需要把linux核心的setup部分拷貝到9020H:0開始的地址,然後把保護模式核心拷貝到1MB開始的地址,然後根據Linux Boot Protocol 2.03的內容設定參數區的內容,基地址就是9000H:0,最後使用一條ljmp $0x9020,$0跳轉到setup段,剩下的事情就是linux自己的了^_^,果然簡單吧!

4.THE LINUX/I386 BOOT PROTOCOL

這個就是我們引導linux所使用的協議,它的位置在:Documetation/i386/boot.txt中。裡面詳細的寫了引導linux所需要知道的一切知識,對於其它體繫結構的CPU,也一定存在著類似的東東,仿照本文的方法就可以了。

5.細節一:基本引導參數

當然我們不指定任何參數linux核心也可以啟動,但是這樣有可能啟動進入一個我們不支援的framebuffer模式,導致沒有任何螢幕顯示;也可能mount了錯誤的根分區失敗,導致No Init Found的kernel panic。所以我們必須要指定一些東西。

如果你像我一樣是一個懶人,那麼可以直接把bootsect拷到9000H:0的位置,使用磁碟片引導時它會把自己複製到這個地方的,這裡面有些預設的設定,詳情請見boot.txt。

首先是root的位置,這裡bootsect_pos指向的是9000H:0的地址。

bootsect_pos[0x1fc] = root_minor;
bootsect_pos[0x1fd] = root_major;

 

其中root_minor和root_major分別是root的主裝置號和次裝置號。

當前顯示模式:

bootsect_pos[0x1fa] = 0xff;
bootsect_pos[0x1fb] = 0xff;

 

這兩個數值相當於引導參數vga=0xHHH的值,兩個0xff代表文字模式。

bootsect_pos[0x210] = 0xff;

 

這是在設定你的bootloader的類型,其實只要不是0就行,因為0代表的loader太舊無法引導新的核心,setup發現這個後就會停下來。按照規範你應該寫成0xff,這表示未知的boot loader,如果你的bootloader已經得到了一個官方分配的type id,那就寫上自己的數值。

6.細節二:如何載入核心

如果你現在的環境是一無所有,那麼必須使用bios中斷或者ATA指令去讀硬碟了,不過如果你手中如果有基本的DOS系統,那麼就可以使用DOS的程式了。為了能夠操作整個4GB的地址空間,我使用了WATCOM C寫了個小程式讀核心,不過你可以仿照bootsect裡面的做法,在實模式中讀一部分,然後進入到保護模式拷貝到1MB以上,然後再從實模式讀一部分……需要注意1:9000H:0也是DOS佔用的地址空間,所以讀完核心後就不要返回DOS了,否則會有問題;

注意2:一定保證是純DOS,不要載入HIMEM或者EMM386這樣的東西,它們會使上面的引導過程失敗。loadlin倒是可以來者通吃幾乎所有的DOS,不過它的作者也是這方面的大牛,對DOS下的記憶體管理非常的熟悉。我們現在研究這些古老的東西很難找資料了,況且我們是在寫bootloader,不是DOS killer^_^。

7.引導時的進階功能

1)initrd

initrd是啟動時的一個小虛擬盤,一般用它來實現模組化的核心。引導initrd的方法主要有兩個要點:
第一,把initrd讀入記憶體,我們可以仿照大多數boot loader的方法把它放在記憶體的最高端;
第二,設定initrd的起始位置和長度

bootsect_pos[0x218]開始的4個位元組放的是起始物理地址,bootsect_pos[0x21c]開始的4個位元組放的是initrd的長度。

2)command_line支援

用command_line你可以給核心傳一些參數,自己定製核心的行為。我是這樣做的,首先把command_line放在9900H:0的地址裡,然後把9900H:0的物理地址存放在bootsect_pos[0x228]開始的4個位元組裡面。注意一定是物理地址,所以你應該放99000H這個數,然後核心就會識別你的command_line了。

8.結束語

寫本文的目的主要是為了用最少的語言和最短的時間說明bootloader的原理,真正的權威資料還是要看linux核心源碼和boot.txt檔案。我曾經寫過一個例子loaderx,使用WATCOM C和TASM,WATCOM C是一個可以在DOS下產生能訪問4GB物理地址程式的C編譯器,裡面也有詳細的注釋和文檔說明。可以從下面的地址下載:loaderx.tar.gz

參考資料

THE LINUX/I386 BOOT PROTOCOL 2.03

--------------------

作者:範曉炬,聯想(北京)有限公司軟體設計中心嵌入式研發處開發工程師,研究興趣為 Linux 核心,網路安全,XWindow 系統,Linux 案頭應用,人工智慧系統。你可以通過xiaoju_f@263.net聯絡他。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.