Linux是如何啟動的?

来源:https://www.cnblogs.com/alongdidi/archive/2019/08/27/how_linux_start.html
-Advertisement-
Play Games

參考資料: An introduction to the Linux boot and startup processes 這篇隨筆,可以理解為是對這篇英文文章的翻譯與個人理解、筆記的整合。 擴展閱讀: GNU GRUB - Wikipedia systemd - Wikipedia BIOS in ...


參考資料:

An introduction to the Linux boot and startup processes

這篇隨筆,可以理解為是對這篇英文文章的翻譯與個人理解、筆記的整合。

擴展閱讀:

GNU GRUB - Wikipedia

systemd - Wikipedia

BIOS interrupt call - Wikipedia

Multiboot specification - Wikipedia

Chain loading - Wikipedia

Master boot record - Wikipedia

Best Couple of 2016: Display manager and window manager

淺析 Linux 初始化 init 系統,第 1 部分:SysV init

淺析 Linux 初始化 init 系統,第 2 部分:Upstart

淺析 Linux 初始化 init 系統,第 3 部分:Systemd

 

前言

理解Linux是如何啟動的對於配置和針對Linux啟動失敗的排錯是至關重要的。

本篇文章大體上把Linux啟動過程分成了兩部分:引導(boot)和啟動(startup)。

引導:從電腦開機至內核初始化完畢啟動systemd程式的這個階段。

啟動:從systemd程式啟動至系統完全啟動完畢的這個階段。

引導階段主要涉及了引導裝載程式(boot loader),對於我所學習的CentOS系列的系統來說,主要涉及的均是GRUB這個引導裝載程式。

  • 0.x系列的版本,是老的版本,也叫做GRUB 1/Legacy,主要用於以前的Linux發行版,例如CentOS 5/6。
  • 2.x系列的版本,是新的版本,也叫做GRUB 2,現在主流的例如CentOS 7上會使用它。雖然是新版的GRUB,版本號差別也不是很大,但是GRUB 2幾乎是完全重寫的GRUB!

啟動階段主要涉及了系統初始化進程的方式(init 進程/系統)。

  • CentOS 5:System V init,可簡稱System V或者SysV。
  • CentOS 6:Upstart。
  • CentOS 7:Systemd。

這3種進程初始化方式,配置文件的寫法有較大的不同。

本篇隨筆,所涉及的引導和啟動的版本是當前的主流版本,即GRUB 2和Systemd。下文如果沒特別說明或者GRUB單獨出現的話,那麼GRUB就表示GRUB 2了。

將引導和啟動的過程,更細緻的劃分的話,如下所示。

  1. Boot
    1. BIOS POST
    2. Boot loader(GRUB 2)
      1. Stage 1
      2. Stage 1.5
      3. Stage 2
    3. Kernel initialization
  2. Startup
    1. Systemd

 

引導過程(boot)

想要啟動引導過程的話,主要有兩種方式。一種是電腦處於關機狀態,用戶物理性開機;另一種是電腦處於開機狀態,用戶通過GUI或者CLI程式性重啟(當然如果有物理重啟按鈕,也可以物理性重啟)。

譯者註:我也不曉得為何作者要說這句簡單的話。

BIOS POST

引導的第一步和Linux系統是無關的,所有的OS都會有這個步驟。這步是BIOS中提供的POST(Power On Self Test,開機自檢)功能,主要用於檢測硬體是否可正常工作。

如果POST檢測失敗的話,則引導終止,後續的步驟也不會再有了,系統啟動失敗。

POST檢測成功,確保硬體可正常工作後,BIOS會釋出BIOS中斷(BIOS interrupt,詳見擴展閱讀)INT 13H,它用於在所有已連接的可引導設備上定位引導扇區(boot sector)。第一個找到的包含有效引導記錄(boot record)引導扇區會被載入入記憶體當中,並且將控制權傳遞給從引導扇區中載入的代碼。

引導扇區是引導裝載程式的第一個階段(stage)。現代大多數的Linux發行版中採用三種引導裝載程式,分別是LILO、GRUB 1和GRUB 2,GRUB 2是當前階段最新也是最常用的引導裝載程式。

GRUB 2

GRUB 2的全稱是“GRand Unified Bootloader, version 2”,它使得電腦可以找到OS的內核文件並將其載入記憶體中。

GRUB被設計用於相容多引導規範(multiboot specification,詳見擴展閱讀),這個規範使得它可以引導許多的Linux和自由OS;它還可以鏈式載入(chain load,詳見擴展閱讀)專有(proprietary)OS的引導記錄。

GRUB還可以允許用戶從某個Linux發行版中選擇不同的內核來引導。這樣在某個內核更新發生了錯誤,或者更新使得某些重要的軟體使用出現異常的時候,就可以引導之前版本的內核來正常工作。

GRUB 1的配置文件是/boot/grub/grub.conf,GRUB 2的配置文件是/boot/grub2/grub.cfg。紅帽系的Linux,從Fedora 15和CentOS/RHEL 7開始將GRUB升級到了GRUB 2版本。GRUB 2和GRUB 1在功能上是相同的,但是經過了幾乎完全的重寫,所以是要優於GRUB 1的。

GRUB 1和2都是有三個階段(stage),本文會大致闡述這三個階段。不過,關於GRUB具體是如何配置的,不在本文的範圍中。

GRUB 2在官方中並不是使用這3個階段,即stage 1/1.5/2,這個應該是GRUB 1所使用的,不過使用這3個階段來闡述GRUB 2,也是可以的。

譯者註:在擴展閱讀中,GRUB 2應該是4個階段。

Stage 1

當BIOS POST的自檢階段通過後,BIOS從已連接的設備上尋找可用的引導記錄,引導記錄一般位於磁碟的MBR上。stage 1的引導記錄叫做boot.img。

MBR位於磁碟的第一個扇區sector 0,大小為512B,扣除64B的分區信息和2個位元組的boot signature,僅剩下446B的空間。這個空間非常小,所以boot.img的代碼量也必須很小,它不會包含文件系統的驅動(即沒有識別文件系統相關的代碼),boot.img的唯一作用就是找到並載入stage 1.5。為了完成stage 1的任務,stage 1.5的位置必須位於stage 1自身和第一個分區之間。如圖所示。

By Shmuel Csaba Otto Traian, CC BY-SA 3.0, https://commons.wikimedia.org/w/index.php?curid=28427221

將stage 1.5載入入記憶體後,stage 1就將控制權轉交給了stage 1.5了。

譯者註:在我的CentOS 7系統上,該文件位於/boot/grub2/i386-pc/boot.img,大小為512B,理論上是應該小於446B才對。

Stage 1.5

如上所述,stage 1.5位於stage 1和第一個分區之間,即sector 1~62,總容量為512*62=31,744。

譯者註:上面的圖片stage 1.5的容量為32,256B,比31,744多了一個512B,不懂為什麼。

這個階段的文件是core.img,作者的該文件大小是25,389B,我的是26,664(/boot/grub2/i386-pc/core.img)。可見該階段還可以有許多的剩餘容量。

這個階段主要是包含了各種各樣的文件系統驅動程式,例如EXT家族、XFS、NTFS等。只有具備了文件系統驅動,才可以基於文件的路徑和名稱(例如/boot/vmlinuz-3.10.0-862.el7.x86_64)來查找/載入某個文件。

剩餘的容量,應該是讓開發人員自己擴展、增加想要載入的文件系統驅動程式的。

這個階段所載入的文件系統驅動,就是用於識別stage 2的文件所在的文件系統的。

GRUB 2的stage 1.5中的core.img要比GRUB 1版本中的更加複雜和強大,因此GRUB 2中的stage 2可以位於標準的EXT系列文件系統,但不能是在LVM分區上。

標準的stage 2的文件的位置是在/boot文件系統上,準確地說,是/boot/grub2。

Stage 2

該階段的文件位於/boot/grub2目錄中。該階段不算前2個階段有鏡像文件(image file:boot.img和core.img),它主要由許多運行時按需載入的內核模塊文件構成(位於/boot/grub2/i386-pc目錄)。

該階段的主要功能是定位並載入內核文件,而後將控制權轉交給內核。內核文件的名稱均以vmlinuz開頭,可在/boot目錄下找到當前系統已安裝的內核。

[root@C7 ~]# ls -l /boot/vmlinuz-*
-rwxr-xr-x. 1 root root 6224704 Sep 27  2018 /boot/vmlinuz-0-rescue-341d78e441db4d8b985b51fc31f40be9
-rwxr-xr-x. 1 root root 6224704 Apr 21  2018 /boot/vmlinuz-3.10.0-862.el7.x86_64
[root@C7 ~]# file /boot/vmlinuz-*
/boot/vmlinuz-0-rescue-341d78e441db4d8b985b51fc31f40be9: Linux kernel x86 boot executable bzImage, version 3.10.0-862.el7.x86_64 ([email protected]) #1 SMP , RO-rootFS, swap_dev 0x5, Normal VGA
/boot/vmlinuz-3.10.0-862.el7.x86_64:                     Linux kernel x86 boot executable bzImage, version 3.10.0-862.el7.x86_64 ([email protected]) #1 SMP , RO-rootFS, swap_dev 0x5, Normal VGA

GRUB有一個預引導菜單,可以讓用戶選擇想要引導的內核,包含了救援(rescue)模式,配置得當的話還包含恢復(recovery)模式。

Kernel

內核是一種可自我展開的壓縮格式的文件,它們和RAM disk鏡像文件、硬碟的設備映射都位於/boot目錄下。

/boot/initramfs-0-rescue-341d78e441db4d8b985b51fc31f40be9.img
/boot/initramfs-3.10.0-862.el7.x86_64.img
/boot/System.map-3.10.0-862.el7.x86_64

當內核被載入記憶體執行,自我展開完畢後,它會啟動systemd進程。此時引導過程就結束了,正式進入啟動過程。

註:引導過程的結束時,Linux仍然無法執行任何生產任務。因為生產任務是需要具體的進程來完成的,而systemd進程只是所有生產任務進程的最上級父進程(系統的第一個進程)。

 

啟動過程(startup)

Systemd

systemd是Linux系統中的第一個進程,即最頂級的父進程。它的任務是啟動系統中的其他進程使得Linux可以進入生產環境得狀態。包含掛載文件系統、啟動和管理服務。和啟動順序無關的systemd任務不在本文的討論範圍之內。

首先,systemd根據/etc/fstab掛載文件系統,包含swap文件和分區。此時systemd就可以訪問位於/etc目錄下的配置文件了,包含自己的配置文件。它使用自己的配置文件(/etc/systemd/system/default.target)來決定要將系統啟動為哪種狀態(state)或者target。default.target僅僅是一個到真實target文件的字元鏈接文件。對於桌面工作站來說,是鏈接到graphical.target(相當於System V init中的運行級別5)。對於伺服器來說,一般是鏈接到multi-user.target(相當於System V init中的運行級別3)。emergency.target則相當於單用戶模式。

註意:target和服務是systemd的單元(unit)。

Table 1是systemd的target和System V init的運行級別的對照表格。systemd提供了target別名(alias)用於向後相容。target別名允許腳本和管理員使用SysV的命令(例如init 3)來切換運行級別,當然,這些命令會傳遞給systemd解析與執行。

Table 1: Comparison of SystemV runlevels with systemd targets and some target aliases.

SystemV Runlevel

systemd target

systemd target aliases

Description

  halt.target  

Halts the system without powering it down.

0 poweroff.target runlevel0.target

Halts the system and turns the power off.

S emergency.target  

Single user mode. No services are running; filesystems are not mounted. This is the most basic level of operation with only an emergency shell running on the main console for the user to interact with the system.

1 rescue.target runlevel1.target

A base system including mounting the filesystems with only the most basic services running and a rescue shell on the main console.

2   runlevel2.target

Multiuser, without NFS but all other non-GUI services running.

3 multi-user.target runlevel3.target

All services running but command line interface (CLI) only.

4   runlevel4.target

Unused.

5 graphical.target runlevel5.target

multi-user with a GUI.

6 reboot.target runlevel6.target

Reboot.

  default.target  

This target is always aliased with a symbolic link to either multi-user.target or graphical.target. systemd always uses the default.target to start the system. The default.target should never be aliased to halt.target, poweroff.target, or reboot.target.

每個target在其配置文件中會說明依賴關係,有依賴就有啟動的先後順序之分,被依賴方啟動失敗,那麼依賴方也會啟動失敗(依賴方依賴於被依賴方)。這些依賴一般是系統要運行於某個功能級別下(例如web伺服器、DB伺服器、緩存伺服器等)所需要的服務。當target配置文件中所有的依賴都正常啟動完畢後,系統會運行於那個target級別下。

Systemd也會去查找SysV配置目錄下是否含有啟動腳本,如果有的話,也會載入的。基本上在CentOS 7上,服務已經都使用systemd風格的配置文件來管理了,不過在SysV配置目錄下還有一個網路相關的配置文件,可能只是用作一個學習案例吧,或者網路服務在CentOS 7上依然使用SysV管理(概率較低)。

[root@C7 ~]# ls -l /etc/rc.d/init.d/
total 40
-rw-r--r--. 1 root root 18104 Jan  3  2018 functions
-rwxr-xr-x. 1 root root  4334 Jan  3  2018 netconsole
-rwxr-xr-x. 1 root root  7293 Jan  3  2018 network
-rw-r--r--. 1 root root  1160 Apr 11  2018 README

接下來我們來看一張文本圖,Figure 1。這張圖來源於bootup(7)。展示了systemd的啟動流程。

           local-fs-pre.target
                    |
                    v
           (various mounts and   (various swap   (various cryptsetup
            fsck services...)     devices...)        devices...)       (various low-level   (various low-level
                    |                  |                  |             services: udevd,     API VFS mounts:
                    v                  v                  v             tmpfiles, random     mqueue, configfs,
             local-fs.target      swap.target     cryptsetup.target    seed, sysctl, ...)      debugfs, ...)
                    |                  |                  |                    |                    |
                    \__________________|_________________ | ___________________|____________________/
                                                         \|/
                                                          v
                                                   sysinit.target
                                                          |
                     ____________________________________/|\________________________________________
                    /                  |                  |                    |                    \
                    |                  |                  |                    |                    |
                    v                  v                  |                    v                    v
                (various           (various               |                (various          rescue.service
               timers...)          paths...)              |               sockets...)               |
                    |                  |                  |                    |                    v
                    v                  v                  |                    v              rescue.target
              timers.target      paths.target             |             sockets.target
                    |                  |                  |                    |
                    v                  \_________________ | ___________________/
                                                         \|/
                                                          v
                                                    basic.target
                                                          |
                     ____________________________________/|                                 emergency.service
                    /                  |                  |                                         |
                    |                  |                  |                                         v
                    v                  v                  v                                 emergency.target
                display-        (various system    (various system
            manager.service         services           services)
                    |             required for            |
                    |            graphical UIs)           v
                    |                  |           multi-user.target
|                  |                  |
                    \_________________ | _________________/
                                      \|/
                                       v
                             graphical.target

sysinit.target和basic.target可以看作是一個檢測點(checkpoint)。儘管systemd的設計目標之一是並行啟動系統服務,但是依然存在某些特定的服務和target是需要在其他服務和target啟動之前啟動的。直到所有被該檢測點依賴的服務和target被滿足後,那麼該檢測點才可以通過。

因此直到所有被依賴的單元完成後,才可以到達sysinit.target。所有的那些單元,掛載文件系統、配置swap文件、啟動udev、建立隨機生成器種子(random genorator seed)、初始化低級設備、如果有文件系統需要加密的話則配置加密服務。不過在sysinit.target內部,上述的這些單元是可以並行執行的。也就是說systemd支持單元在某個target內部的並行執行。

sysinit.target完成了一些底層的功能,即較接近硬體層,慢慢地會往高層發展,接近用戶層,即basic.target。這個階段涉及的unit,如圖所示。

最後就可以啟動multi-user.target和graphical.target這兩個我們熟悉的用戶級別的target了。註意:multi-user.target必須啟動成功,才可以啟動graphical.target。

Figure 1中,加粗帶下劃線的target,是常用的啟動target,到達這些target,就表示系統已經啟動完畢了。multi-user.target啟動完畢後展示了文本模式的登錄界面,而graphical.target則展示了圖形化的登陸界面,想瞭解關於圖形化登陸界面的話,可查閱擴展閱讀中的Best Couple of 2016: Display manager and window manager。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 主鍵就是一個表中每個數據行的唯一標識。不會有重覆值的列才能當主鍵。一個表可以沒有主鍵,但是會非常難以處理,因此沒有特殊理由表都要設定主鍵 主鍵有兩種選用策略:業務主鍵和邏輯主鍵。業務主鍵是使用有業務意義的欄位做主鍵,比如身份證號、銀行賬號等;邏輯主鍵是使用沒有任何業務意義的欄位做主鍵,完全給程式看的 ...
  • 目 錄 1. 概述... 2 2. 使命及目標... 3 3. 系統框架... 4 4. 設備容器(iNeuKernel)... 4 5. 第三方數據導入介面... 9 6. 視圖建模(iNeuView)... 10 7. 機器學習(iNeuAI)... 11 8. 徵集需求... 13 1. 概述 ...
  • 本文將通過實際的例子來演示如何在ASP.NET Core中應用JWT進行用戶認證以及Token的刷新方案(ASP.NET Core 系列目錄) 一、什麼是JWT? JWT(json web token)基於開放標準(RFC 7519),是一種無狀態的分散式的身份驗證方式,主要用於在網路應用環境間安全 ...
  • 實際的生產環境中,總會做一些定期的任務,比如數據備份,我們不可能總等到那個時間去手動執行,這時計劃任務就派上用場了。 ...
  • Windows 有任務管理器來管理進程,Linux 也有相應的命令來管理進程。 ...
  • Linux伺服器線上打包遇到的問題 轉載請標明出處: "https://dujinyang.blog.csdn.net/article/details/80110942" 本文出自:【奧特曼超人的博客】 線上打包的流程 遇到奇怪的BUG(Linux apktool 包體變大) 1. 線上打包的流程 ...
  • 如何控制服務的運行狀態?如何切換不同的運行級別? 服務控制 ntsysv 仿圖形交互界面,集中配置各種服務啟動狀態 :同時對指定運行級別中的服務進行管理,不加僅管理當前運行級別中的服務。 systemctl systemctl {選項} name.servive :啟動 :停止 :重啟,先停止,再啟 ...
  • 一、awk介紹 全稱:由Aho Weinberger Kernaighan三個人的首字母組合而成 1970年第一次出現在Unix機器上,後來在開源領域使用它 awk是一種單獨的編程語言解釋器 awk報告生成器:通過模式匹配以及自己本身的語言格式,來獲取並輸出客戶所需要的內容 示例:獲取系統上面用戶i ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...