跳到主要內容

關於Linux系統下Grub啟動流程的討論總結

關於Linux系統下Grub啟動流程的討論總結


 全世界linuxer都知道grub是什麼東西,但對於MBR引導到grub再引導到具體作業系統的這個流程可能有不少朋友就比較迷糊了。這不,cu上一位朋友就發出了這樣一個求助貼:

   假如現在一台電腦上裝了WIN2000系統,那麼我現在在裝上LINUX系統和GRUB,那麼假如把GRUB裝在主分區的話,GRUB直接引導 LINUX和WIN2000,我是可以理解的,因為MBR中是GRUB的STAGE1(對不對呢?),MBR通過檢查DPT分區資訊引導系統跳轉至DBR (活動分區),我這裏想問的活動分區是什麼時候設的呢?那麼裝GRUB到MBR裏,那原來MBR中的WIN的引導資訊是怎麼處理的呢?是不是我們假如說裝 GRUB到MBR的時候,GRUB就把GRUB所在那個區設置為了活動分區了呢?然後GRUB引導時候,MBR就找到那個活動分區找到所需要的檔,然後繼續呢?假如說把GRUB裝到其他分區(非主引導區)的話,那是怎麼樣實現GRUB先啟動的呢?不是先MBR嗎?因為裝到了其他分區,沒有改主引導區,因此主引導區還是WIN2000的引導資料啊,怎麼會GRUB先啟動了呢?這是為什麼呢?跟活動分區有關係沒有呢?我看資料上寫的是哪個系統啟動哪個系統就是活動分區,可是那樣的話,似乎就解釋不通了啊,就是最最開始這個地方一直不懂,理不清楚。




   下面就是cu各個玩家對這個問題分析討論的總結。

   首先讓我們看看傳統的啟動流程:載入並運行Master Boot Record(MBR)主引導區內容(如lilo等)。然後掃描分區表,定位活動分區,並將活動分區上的引導磁區內容載入到記憶體中執行。

   系統引導過程主要由以下幾個步驟組成(以硬碟啟動為例)
  1. 開機;
  2. BIOS加電自檢(POST——Power On Self Test),記憶體位址為0fff:0000;
  3. 將硬碟第一個磁區(0頭0道1磁區,也就是Boot Sector)讀入記憶體位址0000:7c00處;
  4. 檢查(WORD)0000:7dfe是否等於0xaa55.若不等於則轉去嘗試其他介質;如果沒有其他啟動介質,則顯示 “No ROM BASIC” ,然後死機;
  5. 跳轉到0000:7c00處執行MBR中的程式;
  6. MBR先將自己複製到0000:0600處,然後繼續執行;
  7. 在主分區表中搜索標誌為活動的分區。如果發現沒有活動分區或者不止一個活動分區,則停止;
  8. 將活動分區的第一個磁區讀入記憶體位址0000:7c00處;
  9. 檢查(WORD)0000:7dfe是否等於0xaa55,若不等於則顯示 “Missing Operating System”,然後停止,或嘗試軟碟啟動;
  10. 跳轉到0000:7c00處繼續執行特定系統的啟動程式;
  11. 啟動系統。


   裝grub到邏輯分區,那麼就一定把grub裝入的邏輯分區設為活動的。不過,這時候,grub接管了11步以後的動作:從stage 1.5讀出grub.conf。再由配置和用戶選擇決定下一步的引導行為。

   一般安裝grub都有兩種情況,對於安裝到MBR這種情況而言,GRUB直接覆蓋了原來的MBR引導程式。這也是為什麼要換回“原來的 windows的引導方式”,只要用dos引導fdisk /mbr一下就可以的原因。為什麼可以這樣做,請注意,1-11步中有兩個地方出現了0000:7c00。不管是dos boot sector還是nt loader它本身也是從0000:7c00運行的。其實ms當年開發分區管理的這個小程式相當於是在bios引導boot sector中插進去的。grub因為也是寫的從0000:7c00這個記憶體開始的副程式,那麼既可以被BIOS載入又可以被dos的MBR載入應該好理解了吧。

   開機自檢後,引導權交給了硬碟的MBR,此時grub就啟動了。由grub來引導windows /linux都可以。注意:linux不一定要安裝在活動分區,因為引導程式在MBR!但是windows一定要安裝在活動分區(可引導的 windows),第二個windows可以不安裝在活動分區,但它的引導檔一定在活動分區。

   大體順序是:

   grub—->windows–>查找引導檔—引導載入—啟動windows

   grub—->linux—>查找引導檔(/boot)–>引導載入—啟動linux

   那麼,如果把grub安裝到了其他的分區上,不是MBR呢?這是grub所裝在的那個主分區必須被設為活動分區。因為MBR(物理主引導分區)中其實並沒有 OS相關的引導程式的,通常MBR只是掃描並讀取隨後的分區表,找到相應的活動分區,讀取相應活動分區的第一個磁區的512位元組程式並運行,該程式負責進一步引導相應分區的相應系統。因此,大概的運行次序是

   BIOS—>MBR—->GRUB—->菜單。

   這樣,大體的真實流程就可以總結如下了:
  1. 開機;
  2. BIOS加電自檢(POST——Power On Self Test),記憶體位址為0fff:0000;
  3. 將硬碟第一個磁區(0頭0道1磁區,也就是Boot Sector)讀入記憶體位址0000:7c00處;
  4. 檢查(WORD)0000:7dfe是否等於0xaa55.若不等於則轉去嘗試其他介質;如果沒有其他啟動介質,則顯示 “No ROM BASIC” ,然後死機;
  5. 跳轉到0000:7c00處執行MBR中的程式;
  6. MBR先將自己複製到0000:0600處,然後繼續執行;假如先裝XP後裝LINUX,並且LINUX沒有裝在MBR,那這個MBR中的資料還是WIN 寫的資料,它的作用都是下步中所說的作用,就是搜索主分區表中標誌為活動的分區,那麼這個時候就必須把GRUB所在的主分區設置為活動的分區,這個時候才能正常的啟動GRUB,然後GRUB的STAGE1在調STAGE1.5和其他的,從而來引導整個系統。假如說先裝XP後裝LINUX,但是GRUB裝在了MBR,那樣STAGE1直接調入記憶體,STAGE1在調STAGE1.5和STAGE2等,從而來引導系統。那這個時候是不需要將GRUB其他檔所在的主分區設為活動分區的,它直接調STAGE1.5等,然後再調STAGE2等,來識別檔系統,從而實現可多啟動。
  7. 在主分區表中搜索標誌為活動的分區。如果發現沒有活動分區或者不止一個活動分區,則停止;
  8. 將活動分區的第一個磁區讀入記憶體位址0000:7c00處;
  9. 檢查(WORD)0000:7dfe是否等於0xaa55,若不等於則顯示 “Missing Operating System”,然後停止,或嘗試軟碟啟動;
  10. 跳轉到0000:7c00處繼續執行特定系統的啟動程式;
  11. 啟動系統。


   一點資料:

   能正常工作的grub應該包括一下檔:stage1、stage2、*stage1_5、menu.lst。

   其中stage1的大小一定是512位元組,它要被安裝(也就是寫入)某個硬碟的主引導記錄,或者某個活動分區(這個分區要用fdisk標記成可啟動的)的啟動磁區。stage1的主要的也是唯一的作用就是找到你存放在硬碟上某個地方的stage2檔,來完成後續的工作。

   stage2 檔可以存在在某個特定的檔系統中,比如你分了一個linux分區,在上面創建一個ext2檔系統,然後把這個檔拷貝到這個分區的某個目錄下。也可以把stage2直接存放在硬碟的某個位置,也就是未分區的某個地方。不過,好像沒有多少人會這麼做吧。

   因為stage1的容量有限(主引導記錄MBR和啟動磁區的大小只能夠是512位元組),所以它對檔系統是無法識別的,那如果你把stage2存放在 ext2或者fat格式的檔系統上,它如何來找到這個檔呢?這就要用到上面提到的那些stage1_5的檔了,它們負責解釋檔系統。你的 stage2放在什麼格式的檔系統上,就要調用對應的那個stage1_5檔。比如,你把stage2存放在ext2格式的檔系統上,就需要 e2fs_stage1_5;stage2存放在fat格式的檔系統上,就需要fat_stage1_5了。

留言

這個網誌中的熱門文章

用 C# 批次控制 Word 合併列印

前由 我有全區的電話資料,問題在於我要依不同里別來製作出電話簿。結果如下圖: 單純採用合併列印無法達成我的需求。解決方法係用「功能變數」儲存上一個里別,與現在里別進行比較:若不同,則換頁。不過,這樣功能變數還蠻長的。最後,我還是採用 C# 來解決。 解決方案 用 C# 控制 WORD 中合併列印的「資料來源 Data Source」,給予不同里別的「sqlstatement」。迴圈處理不同的里別即可。但可預見其處理過程會很慢,不過還好,我可以不用在意它,有跑出結果即可。 程式碼 IList<string> areas = new List<string>() { "後壁", "侯伯", "嘉苳", "土溝", "嘉田", "嘉民", "菁豊", "崁頂", "後廍", "墨林", "菁寮", "新嘉", "頂長", "平安", "仕安", "竹新", "新東", "長安", "頂安", "福安", "烏樹" }; string root = @"D:\"; // 根目錄 string data = root + @"\data.docm"; // 資料檔(即資料來源) string template = root + @"\template.docx"; // 已設定好格式與合併欄位的 Word 檔 string output = @"d:\Final"; // 輸出之資料夾 object oMissing = System.Reflection.Missing.Va...

VLC c# 順利編譯

原文網址: http://www.cnblogs.com/haibindev/archive/2011/12/21/2296173.html 原文作者: haibindev 原文標題:c#万能视频播放器 本文的重點在於修正 class VlcPlayer,使其能順利在 VC# Express 2010 .Net Framework 4 下順利編譯。 修正重點在於 CallingConvention = CallingConvention. StdCall 改成 CallingConvention = CallingConvention. Cdecl using System; using System.Runtime.InteropServices; using System.Security; using System.Text; namespace VlcDotNet { class VlcPlayer { private IntPtr libvlc_instance_; private IntPtr libvlc_media_player_; private double duration_; public VlcPlayer(string pluginPath) { string plugin_arg = "--plugin-path=" + pluginPath; string[] arguments = { "-I", "dummy", "--ignore-config", "--no-video-title", plugin_arg }; libvlc_instance_ = LibVlcAPI.libvlc_new(arguments); libvlc_media_player_ = LibVlcAPI.libvlc_media_player_new(libvlc_instance_); } public ...

[Symfony+Doctrine] 透過非 Id 來使用 Pessimistic Lock

根據 文件 ,Doctrine 有 Pessimistic Lock,又分為兩種: LockMode::PESSIMISTIC_WRITE:對應至 MySQL 的 Select FOR UPDATE LockMode::PESSIMISTIC_READ:對應至 MySQL 的 Select LOCK IN SHARE MODE 差別在於 LOCK IN SHARE MODE 會將在 row 的資料鎖定(row-level lock),在非同一交易(Transaction)下,不給寫入,其他交易可以讀取, 且可以繼續 Select LOCK IN SHARE MODE 。而 FOR UPDATE 不僅鎖定該資料,在非同一交易下,不給寫入,其它交易可以讀取, 但不能 Select LOCK IN SHARE MODE 。MySQL 文件有更詳細的比較與情境使用的說明,參考 網址 。 現在問題是,我們要完全採用 ORM 來處理資料。Doctrine 的文件提到 EntityManager::find 可以採用 Pessimistic Lock, 但 find 是透過 id 來處理 。而其他 find 系列函數(包括:findAll, findBy, findOneBy)皆不支援 LockMode。 因此,勢必要有方法來「透過非 id 來使用 Pessimistic Lock」。透過查看原始碼,簡單的方法是有的,解法之範例如下: 19 public function depositAction() 20 { 21 22 $em = $this->getDoctrine()->getManager(); 23 24 $em->transactional(function ($em) { 25 $entityName = 'AcmeTrainingBundle:Account'; 26 $lockMode = LockMode::PESSIMISTIC_READ; 27 $orderBy = null; 28 $...