--- title: Bootstrap (開機載入) - 從零開始的開源地下城 tags: Linux, Linux讀書會, Kernel, 從零開始的開源地下城, COMBO-tw description: 介紹與Linux Kernel相關基本知識 lang: zh-Hant GA: G-2QY5YFX2BV --- # Bootstrap (開機載入) ###### tags: `Linux` ## 目錄 [TOC] ## 開機啟動介紹 ![](https://hackmd.io/_uploads/HyJUZsZI3.png) ### 完整的linux系統需要具備以下三個部分 ![](https://hackmd.io/_uploads/S1SUZiZL2.png) * Bootloader * Device tree blob * boot.img * Linux Kernel (Linux核心) * Root Filesystem (根目錄檔案系統) ### 常見的Bootloader * Grub * Uboot * ...之類的 #### Grub介紹 GNU GRUB(簡稱「GRUB」)是一個來自GNU專案的啟動載入程式。GRUB是多啟動規範的實現,它允許用戶可以在電腦內同時擁有多個作業系統,並在電腦啟動時選擇希望執行的作業系統。GRUB可用於選擇作業系統分割區上的不同核心,也可用於向這些核心傳遞啟動參數。 ![](https://hackmd.io/_uploads/r1PKboWUn.png) #### Uboot介紹 在一般的桌面電腦開機時,會有一個叫BIOS的程式先被執行,這一個程式會初始化電腦的一些週邊並從硬碟或其他儲存裝置將作業系統載入到記憶體執行。在Embedded系統下也是類似的機制,只是不叫做BIOS,而是叫做bootload,目前較為普遍使用的bootload是u-boot,在開機時u-boot協助將Linux的Image或zImage搬到記憶體,但Image與zImage在產生時沒有提供u-boot足夠的資訊執行搬移動作與啟動核心,因此u-boot提供了mkimage工具,來將Linux kernel的Image或zImage轉成u-boot可以識別的格式,產生的檔案稱之為uImage。 簡言之,就是在原本CPU去讀取Kernel Image的動作之前加上了一個類似BIOS的程式,可以先設定與檢查一些硬體參數,確保作業系統與周邊可以正常運作。 ### Linux開機啟動過程詳解(bootstrap) #### 最初始階段 當我們打開計算機^註1^電源,計算機會自動從主機板的BIOS(Basic Input/Output System)讀取其中所存儲的程式。這一類的程式通常知道一些直接連接在主板上的硬體(硬碟,網路接口,鍵盤,串列接口(USB),並列接口(VGA))。現在大部分的BIOS允許你從光碟或硬碟中選擇一個來啟動。 > ^註1^ 計算機泛指所以Computer,舉凡開發版、個人電腦、嵌入式裝置...等,利用數位電子技術,根據一系列指令指示並且自動執行任意算術或邏輯操作序列的裝置。通用電腦因有能遵循被稱為「程式」的一般操作集的能力而使得它們能夠執行極其廣泛的任務。 下一步,計算機將從你所選擇的存儲設備中讀取起始的512 bytes(比如光碟一開是的512 bytes,如果我們從光碟啟動的話)。這512 bytes叫做主引導記錄MBR (master boot record)。MBR會告訴電腦從該設備的某一個分區(partition)來裝載引導加載程序(boot loader)。Boot loader儲存有作業系統(OS)的相關信息,比如作業系統名稱,作業系統核心 (kernel)所在位置等。常用的boot loader有GRUB和LILO。 隨後,boot loader會幫助我們載入kernel。kernel實際上是一個用來操作計算機的程式,它是計算機作業系統的核心,主要的任務是管理計算機的硬體資源,充當軟體和硬體的接口。作業系統上的任何操作都要通過kernel傳達給硬體。Windows和Linux各自有自己kernel。狹義的作業系統就是指kernel,而廣義的作業系統包括kernel以及kernel之上的各種應用。 > Linus Torvalds與其說是Linux之父,不如說是Linux kernel之父。他依然負責Linux kernel的開發和維護。至於Ubuntu, Red Hat, 它們都是基於相同的kernel之上,囊括了不同的應用和介面構成的一個更加完整的作業系統版本。 實際上,我們可以在多個分割區安裝boot loader,每個boot loader對應不同的作業系統,在讀取MBR的時候選擇我們想要啟動的boot loader。這就是多作業系統的原理。 **小結:BIOS -> MBR -> boot loader -> kernel** #### Kernel(核心) 如果我們載入的是Linux kernel,Linux kernel開始工作。kernel會首先預留自己運行所需的儲存空間(這裡指的是記憶體(Ram)),然後通過驅動程序(driver)偵測計算機硬體。這樣,作業系統就可以知道自己有哪些硬體可用。隨後,kernel會啟動一個init處理程序。它是Linux系統中的1號處理程序(Process),在Linux系統沒有0號處理程序^註2^。到此,kernel就完成了在計算機啟動階段的工作,交接給init來管理。 > ^註2^ 在Linux kernel中,0號處理程序是`scheduler`,1號處理程序是`init/systemd`(所有user thread的祖先),2號處理程序是`kthreadd`(所有kernel thread的父處理程序)。因為0號處理程序是用於管理其他處理程序的,所以他是1號與2號的父處理程序,所以我們在Shell中並不會看到PID 0號的處理程序。 > ```bash > $ ps -eaf > UID PID PPID C STIME TTY TIME CMD > root 1 0 0 Jun24 ? 00:00:02 /sbin/init > root 2 0 0 Jun24 ? 00:00:00 [kthreadd] > ``` **小結: kernel -> init process** #### Init process(初始化程序) 根據給boot loader的選項(Option),Linux此時可以進入單用戶模式(single user mode)。在此模式下,初始化腳本還沒有開始執行,我們可以檢測並修復計算機可能存在的錯誤。 接下來,init會執行一系列的初始化腳本(startup scripts),這些腳本是Linux中常見的shell scripts。 這些腳本執行如下功能: * 設置計算機名稱 * 時區 * 偵測文件系統 * 掛載硬碟 * 清空臨時文件(/tmp) * 設置網路 * …等 當執行完這些初始化腳本,作業系統已經完全準備好了,只是,還沒有使用者可以登錄。init會給出登入(login)對話框,或者是圖形化的登錄介面。 輸入使用者名稱(比如說user)和密碼。 在這之後的過程中,你將以使用者(user)的身份操作此電腦。此外,根據你創建使用者時的設定,Linux還會將你歸類到某個群組(group)中,比如可以是stupid組,或者是user群組。 所以你將是用戶user, 同時是user群組的組員。(注意,群組user和用戶user只是同樣名稱而已,就好想你可以叫Dell, 同時還是Dell公司的老闆一樣。你完全也可以是用戶user,同時為stupid群組的組員) **總結 BIOS -> MBR -> boot loader -> kernel -> init process -> login** ### Linux Kernel 電腦真正在工作的東西其實是==硬體==, 例如數值運算要使用到 CPU、資料儲存要使用到硬碟、圖形顯示會用到顯示卡、 音樂發聲要有音效晶片、連接 Internet 可能需要網路卡等等。那麼如何控制這些硬體呢? 那就是核心的工作了!也就是說,你所希望電腦幫你達成的各項工作,都需要透過==核心==的幫助才行。 **總結 Linux Kernel 就是使用者與硬體溝通的橋梁** ### Root Filesystem Root filesystem的建置,即是在建立1個基本的Linux系統(base system),讓kernel在完成開機後,進入user mode執行使用者程式。Root filesystem的建置主要是以Busybox為主,並加入(移植)客製化的開放源始碼(open source)與自由軟體(free software)。 而嵌入式Linux的root filesystem是依照需求來加入套件的,與桌面環境的Linux distribution不同,因此都是用從頭打造的方式做起。在建立root filesystem時,程式庫相依 性(library dependencies) 的議題是相當重要的項目。當root filesystem缺少必要的library時,程式當然就無法執行囉,甚至連系統也可能會無法順利啟動呦。 **總結 Root Filesystem 就是放使用者所用的各個程式地方,例如:`bash`、`ls`、`gcc`之類的** ## Raspberry Pi啟動模式 * SD卡啟動 * USB啟動 包括以下兩種模式: * 設備啟動:作為大容量存儲設備啟動 * 主機啟動:使用以下方法之一啟動為USB主機: * 大容量存儲啟動:從大容量存儲設備啟動 * 網路啟動:通過乙太網路啟動 * GPIO啟動 ## 本章節練習與反思 * 請大家將自己的理解與本文的不足之處寫到自己的筆記當中吧 * 請大家試著說明[前一章節](/@combo-tw/S1EfJwQbB)是如何啟動樹梅派的吧 * 請介紹除 Grub 和 Uboot 以外的一種 bootloader 吧 * 一般計算機都是從 0 開始數,那為什麼文中提到的 init 的 pid 為 1 呢?那 pid 0 的行程又是什麼呢? pid 0 的行程又是在何時被啟動的呢? ## 參考資料 * [GNU Grub Wiki](https://zh.wikipedia.org/wiki/GNU_GRUB) * [u-boot啟動kernel之Legacy-uImage與FIT-uImage的區別](https://linux.incomeself.com/u-boot%e5%95%9f%e5%8b%95kernel%e4%b9%8blegacy-uimage%e8%88%87fit-uimage%e7%9a%84%e5%8d%80%e5%88%a5/#more-129) * [Linux開機啟動過程詳解(bootstrap)](https://read01.com/xDRGO.html) * [Raspberry Pi啟動模式](https://www.raspberrypi.org/documentation/hardware/raspberrypi/bootmodes/) * [Linux 核心編譯與管理](http://linux.vbird.org/linux_basic/0540kernel/0540kernel-fc4.php#intro_whatiskernel) * [Root Filesystem概念](https://blog.xuite.net/tzeng015/twblog/113272596-Root+Filesystem%E6%A6%82%E5%BF%B5+%28%E8%BD%89%E8%BC%89+digitimes+%29) * [buildRoot study - 建立自己的作業系統](http://fichugh.blogspot.com/2016/02/buildroot-study.html) * [在 raspberry pi 2 上使用 u-boot](https://descent-incoming.blogspot.com/2015/11/raspberry-pi-2-u-boot.html) * [電腦 Wiki](https://zh.wikipedia.org/wiki/%E7%94%B5%E5%AD%90%E8%AE%A1%E7%AE%97%E6%9C%BA) * [Linux kernel 笔记 (61)——PID是0,1,2的进程](https://nanxiao.me/linux-kernel-note-61-pid-0-1-2-process/)