成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

對Linux系統(tǒng)啟動過程分析

系統(tǒng) Linux 系統(tǒng)運維
關(guān)于開源軟件最古老的笑話是:“代碼是自具文檔化的”。經(jīng)驗表明,閱讀源代碼就像聽天氣預(yù)報一樣:明智的人依然出門會看看室外的天氣。本文講述了如何運用調(diào)試工具來觀察和分析 Linux 系統(tǒng)的啟動。分析一個功能正常的系統(tǒng)啟動過程,有助于用戶和開發(fā)人員應(yīng)對不可避免的故障。

[[222309]]

理解運轉(zhuǎn)良好的系統(tǒng)對于處理不可避免的故障是***的準(zhǔn)備。

關(guān)于開源軟件最古老的笑話是:“代碼是自具文檔化的self-documenting”。經(jīng)驗表明,閱讀源代碼就像聽天氣預(yù)報一樣:明智的人依然出門會看看室外的天氣。本文講述了如何運用調(diào)試工具來觀察和分析 Linux 系統(tǒng)的啟動。分析一個功能正常的系統(tǒng)啟動過程,有助于用戶和開發(fā)人員應(yīng)對不可避免的故障。

從某些方面看,啟動過程非常簡單。內(nèi)核在單核上以單線程和同步狀態(tài)啟動,似乎可以理解。但內(nèi)核本身是如何啟動的呢?initrd(initial ramdisk)引導(dǎo)程序bootloader具有哪些功能?還有,為什么以太網(wǎng)端口上的 LED 燈是常亮的呢?

請繼續(xù)閱讀尋找答案。在 GitHub 上也提供了 介紹演示和練習(xí)的代碼。 

啟動的開始:OFF 狀態(tài) 

局域網(wǎng)喚醒Wake-on-LAN

OFF 狀態(tài)表示系統(tǒng)沒有上電,沒錯吧?表面簡單,其實不然。例如,如果系統(tǒng)啟用了局域網(wǎng)喚醒機制(WOL),以太網(wǎng)指示燈將亮起。通過以下命令來檢查是否是這種情況:

  1. # sudo ethtool <interface name>

其中 <interface name> 是網(wǎng)絡(luò)接口的名字,比如 eth0。(ethtool 可以在同名的 Linux 軟件包中找到。)如果輸出中的 Wake-on 顯示 g,則遠(yuǎn)程主機可以通過發(fā)送 魔法數(shù)據(jù)包MagicPacket 來啟動系統(tǒng)。如果您無意遠(yuǎn)程喚醒系統(tǒng),也不希望其他人這樣做,請在系統(tǒng) BIOS 菜單中將 WOL 關(guān)閉,或者用以下方式:

  1. # sudo ethtool -s <interface name> wol d

響應(yīng)魔法數(shù)據(jù)包的處理器可能是網(wǎng)絡(luò)接口的一部分,也可能是 底板管理控制器Baseboard Management Controller(BMC)。 

英特爾管理引擎、平臺控制器單元和 Minix

BMC 不是唯一的在系統(tǒng)關(guān)閉時仍在監(jiān)聽的微控制器(MCU)。x86_64 系統(tǒng)還包含了用于遠(yuǎn)程管理系統(tǒng)的英特爾管理引擎(IME)軟件套件。從服務(wù)器到筆記本電腦,各種各樣的設(shè)備都包含了這項技術(shù),它開啟了如 KVM 遠(yuǎn)程控制和英特爾功能許可服務(wù)等 功能。根據(jù) Intel 自己的檢測工具IME 存在尚未修補的漏洞。壞消息是,要禁用 IME 很難。Trammell Hudson 發(fā)起了一個 me_cleaner 項目,它可以清除一些相對惡劣的 IME 組件,比如嵌入式 Web 服務(wù)器,但也可能會影響運行它的系統(tǒng)。

IME 固件和系統(tǒng)管理模式System Management Mode(SMM)軟件是 基于 Minix 操作系統(tǒng) 的,并運行在單獨的平臺控制器單元Platform Controller Hub上(LCTT 譯注:即南橋芯片),而不是主 CPU 上。然后,SMM 啟動位于主處理器上的通用可擴(kuò)展固件接口Universal Extensible Firmware Interface(UEFI)軟件,相關(guān)內(nèi)容 已被提及多次。Google 的 Coreboot 小組已經(jīng)啟動了一個雄心勃勃的 非擴(kuò)展性縮減版固件Non-Extensible Reduced Firmware(NERF)項目,其目的不僅是要取代 UEFI,還要取代早期的 Linux 用戶空間組件,如 systemd。在我們等待這些新成果的同時,Linux 用戶現(xiàn)在就可以從 Purism、System76 或 Dell 等處購買 禁用了 IME 的筆記本電腦,另外 帶有 ARM 64 位處理器筆記本電腦 還是值得期待的。 

引導(dǎo)程序

除了啟動那些問題不斷的間諜軟件外,早期引導(dǎo)固件還有什么功能呢?引導(dǎo)程序的作用是為新上電的處理器提供通用操作系統(tǒng)(如 Linux)所需的資源。在開機時,不但沒有虛擬內(nèi)存,在控制器啟動之前連 DRAM 也沒有。然后,引導(dǎo)程序打開電源,并掃描總線和接口,以定位內(nèi)核鏡像和根文件系統(tǒng)的位置。U-Boot 和 GRUB 等常見的引導(dǎo)程序支持 USB、PCI 和 NFS 等接口,以及更多的嵌入式專用設(shè)備,如 NOR 閃存和 NAND 閃存。引導(dǎo)程序還與 可信平臺模塊Trusted Platform Module(TPM)等硬件安全設(shè)備進(jìn)行交互,在啟動最開始建立信任鏈。

在構(gòu)建主機上的沙盒中運行 U-boot 引導(dǎo)程序。

在構(gòu)建主機上的沙盒中運行 U-boot 引導(dǎo)程序。

包括樹莓派、任天堂設(shè)備、汽車主板和 Chromebook 在內(nèi)的系統(tǒng)都支持廣泛使用的開源引導(dǎo)程序 U-Boot。它沒有系統(tǒng)日志,當(dāng)發(fā)生問題時,甚至沒有任何控制臺輸出。為了便于調(diào)試,U-Boot 團(tuán)隊提供了一個沙盒,可以在構(gòu)建主機甚至是夜間的持續(xù)集成(CI)系統(tǒng)上測試補丁程序。如果系統(tǒng)上安裝了 Git 和 GNU Compiler Collection(GCC)等通用的開發(fā)工具,使用 U-Boot 沙盒會相對簡單:

  1. # git clone git://git.denx.de/u-boot; cd u-boot
  2. # make ARCH=sandbox defconfig
  3. # make; ./u-boot
  4. => printenv
  5. => help

在 x86_64 上運行 U-Boot,可以測試一些棘手的功能,如 模擬存儲設(shè)備 的重新分區(qū)、基于 TPM 的密鑰操作以及 USB 設(shè)備熱插拔等。U-Boot 沙盒甚至可以在 GDB 調(diào)試器下單步執(zhí)行。使用沙盒進(jìn)行開發(fā)的速度比將引導(dǎo)程序刷新到電路板上的測試快 10 倍,并且可以使用 Ctrl + C 恢復(fù)一個“變磚”的沙盒。 

啟動內(nèi)核 

配置引導(dǎo)內(nèi)核

引導(dǎo)程序完成任務(wù)后將跳轉(zhuǎn)到已加載到主內(nèi)存中的內(nèi)核代碼,并開始執(zhí)行,傳遞用戶指定的任何命令行選項。內(nèi)核是什么樣的程序呢?用命令 file /boot/vmlinuz 可以看到它是一個 “bzImage”,意思是一個大的壓縮的鏡像。Linux 源代碼樹包含了一個可以解壓縮這個文件的工具—— extract-vmlinux

  1. # scripts/extract-vmlinux /boot/vmlinuz-$(uname -r) > vmlinux
  2. # file vmlinux
  3. vmlinux: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically
  4. linked, stripped

內(nèi)核是一個 可執(zhí)行與可鏈接格式 Executable and Linking Format(ELF)的二進(jìn)制文件,就像 Linux 的用戶空間程序一樣。這意味著我們可以使用 binutils 包中的命令,如 readelf 來檢查它。比較一下輸出,例如:

  1. # readelf -S /bin/date
  2. # readelf -S vmlinux

這兩個二進(jìn)制文件中的段內(nèi)容大致相同。

所以內(nèi)核必須像其他的 Linux ELF 文件一樣啟動,但用戶空間程序是如何啟動的呢?在 main() 函數(shù)中?并不確切。

main() 函數(shù)運行之前,程序需要一個執(zhí)行上下文,包括堆棧內(nèi)存以及 stdiostdoutstderr 的文件描述符。用戶空間程序從標(biāo)準(zhǔn)庫(多數(shù) Linux 系統(tǒng)在用 “glibc”)中獲取這些資源。參照以下輸出:

  1. # file /bin/date
  2. /bin/date: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically
  3. linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32,
  4. BuildID[sha1]=14e8563676febeb06d701dbee35d225c5a8e565a,
  5. stripped

ELF 二進(jìn)制文件有一個解釋器,就像 Bash 和 Python 腳本一樣,但是解釋器不需要像腳本那樣用 #! 指定,因為 ELF 是 Linux 的原生格式。ELF 解釋器通過調(diào)用 _start() 函數(shù)來用所需資源 配置一個二進(jìn)制文件,這個函數(shù)可以從 glibc 源代碼包中找到,可以 用 GDB 查看。內(nèi)核顯然沒有解釋器,必須自我配置,這是怎么做到的呢?

用 GDB 檢查內(nèi)核的啟動給出了答案。首先安裝內(nèi)核的調(diào)試軟件包,內(nèi)核中包含一個未剝離的unstripped vmlinux,例如 apt-get install linux-image-amd64-dbg,或者從源代碼編譯和安裝你自己的內(nèi)核,可以參照 Debian Kernel Handbook 中的指令。gdb vmlinux 后加 info files 可顯示 ELF 段 init.text。在 init.text 中用 l *(address) 列出程序執(zhí)行的開頭,其中 addressinit.text 的十六進(jìn)制開頭。用 GDB 可以看到 x86_64 內(nèi)核從內(nèi)核文件 arch/x86/kernel/head_64.S 開始啟動,在這個文件中我們找到了匯編函數(shù) start_cpu0(),以及一段明確的代碼顯示在調(diào)用 x86_64 start_kernel() 函數(shù)之前創(chuàng)建了堆棧并解壓了 zImage。ARM 32 位內(nèi)核也有類似的文件 arch/arm/kernel/head.Sstart_kernel() 不針對特定的體系結(jié)構(gòu),所以這個函數(shù)駐留在內(nèi)核的 init/main.c 中。start_kernel() 可以說是 Linux 真正的 main() 函數(shù)。 

從 start_kernel() 到 PID 1 

內(nèi)核的硬件清單:設(shè)備樹和 ACPI 表

在引導(dǎo)時,內(nèi)核需要硬件信息,不僅僅是已編譯過的處理器類型。代碼中的指令通過單獨存儲的配置數(shù)據(jù)進(jìn)行擴(kuò)充。有兩種主要的數(shù)據(jù)存儲方法:設(shè)備樹device-tree高級配置和電源接口(ACPI)表。內(nèi)核通過讀取這些文件了解每次啟動時需要運行的硬件。

對于嵌入式設(shè)備,設(shè)備樹是已安裝硬件的清單。設(shè)備樹只是一個與內(nèi)核源代碼同時編譯的文件,通常與 vmlinux 一樣位于 /boot 目錄中。要查看 ARM 設(shè)備上的設(shè)備樹的內(nèi)容,只需對名稱與 /boot/*.dtb 匹配的文件執(zhí)行 binutils 包中的 strings 命令即可,這里 dtb 是指設(shè)備樹二進(jìn)制文件device-tree binary。顯然,只需編輯構(gòu)成它的類 JSON 的文件并重新運行隨內(nèi)核源代碼提供的特殊 dtc 編譯器即可修改設(shè)備樹。雖然設(shè)備樹是一個靜態(tài)文件,其文件路徑通常由命令行引導(dǎo)程序傳遞給內(nèi)核,但近年來增加了一個 設(shè)備樹覆蓋 的功能,內(nèi)核在啟動后可以動態(tài)加載熱插拔的附加設(shè)備。

x86 系列和許多企業(yè)級的 ARM64 設(shè)備使用 ACPI 機制。與設(shè)備樹不同的是,ACPI 信息存儲在內(nèi)核在啟動時通過訪問板載 ROM 而創(chuàng)建的 /sys/firmware/acpi/tables 虛擬文件系統(tǒng)中。讀取 ACPI 表的簡單方法是使用 acpica-tools 包中的 acpidump 命令。例如:

聯(lián)想筆記本電腦的 ACPI 表都是為 Windows 2001 設(shè)置的。

聯(lián)想筆記本電腦的 ACPI 表都是為 Windows 2001 設(shè)置的。

是的,你的 Linux 系統(tǒng)已經(jīng)準(zhǔn)備好用于 Windows 2001 了,你要考慮安裝嗎?與設(shè)備樹不同,ACPI 具有方法和數(shù)據(jù),而設(shè)備樹更多地是一種硬件描述語言。ACPI 方法在啟動后仍處于活動狀態(tài)。例如,運行 acpi_listen 命令(在 apcid 包中),然后打開和關(guān)閉筆記本機蓋會發(fā)現(xiàn) ACPI 功能一直在運行。暫時地和動態(tài)地 覆蓋 ACPI 表 是可能的,而***地改變它需要在引導(dǎo)時與 BIOS 菜單交互或刷新 ROM。如果你遇到那么多麻煩,也許你應(yīng)該 安裝 coreboot,這是開源固件的替代品。 

從 start_kernel() 到用戶空間

init/main.c 中的代碼竟然是可讀的,而且有趣的是,它仍然在使用 1991 - 1992 年的 Linus Torvalds 的原始版權(quán)。在一個剛啟動的系統(tǒng)上運行 dmesg | head,其輸出主要來源于此文件。***個 CPU 注冊到系統(tǒng)中,全局?jǐn)?shù)據(jù)結(jié)構(gòu)被初始化,并且調(diào)度程序、中斷處理程序(IRQ)、定時器和控制臺按照嚴(yán)格的順序逐一啟動。在 timekeeping_init() 函數(shù)運行之前,所有的時間戳都是零。內(nèi)核初始化的這部分是同步的,也就是說執(zhí)行只發(fā)生在一個線程中,在***一個完成并返回之前,沒有任何函數(shù)會被執(zhí)行。因此,即使在兩個系統(tǒng)之間,dmesg 的輸出也是完全可重復(fù)的,只要它們具有相同的設(shè)備樹或 ACPI 表。Linux 的行為就像在 MCU 上運行的 RTOS(實時操作系統(tǒng))一樣,如 QNX 或 VxWorks。這種情況持續(xù)存在于函數(shù) rest_init() 中,該函數(shù)在終止時由 start_kernel() 調(diào)用。

早期的內(nèi)核啟動流程。

早期的內(nèi)核啟動流程。

函數(shù) rest_init() 產(chǎn)生了一個新進(jìn)程以運行 kernel_init(),并調(diào)用了 do_initcalls()。用戶可以通過將 initcall_debug 附加到內(nèi)核命令行來監(jiān)控 initcalls,這樣每運行一次 initcall 函數(shù)就會產(chǎn)生 一個 dmesg 條目。initcalls 會歷經(jīng)七個連續(xù)的級別:early、core、postcore、arch、subsys、fs、device 和 late。initcalls 最為用戶可見的部分是所有處理器外圍設(shè)備的探測和設(shè)置:總線、網(wǎng)絡(luò)、存儲和顯示器等等,同時加載其內(nèi)核模塊。rest_init() 也會在引導(dǎo)處理器上產(chǎn)生第二個線程,它首先運行 cpu_idle(),然后等待調(diào)度器分配工作。

kernel_init() 也可以 設(shè)置對稱多處理(SMP)結(jié)構(gòu)。在較新的內(nèi)核中,如果 dmesg 的輸出中出現(xiàn) “Bringing up secondary CPUs...” 等字樣,系統(tǒng)便使用了 SMP。SMP 通過“熱插拔” CPU 來進(jìn)行,這意味著它用狀態(tài)機來管理其生命周期,這種狀態(tài)機在概念上類似于熱插拔的 U 盤一樣。內(nèi)核的電源管理系統(tǒng)經(jīng)常會使某個core離線,然后根據(jù)需要將其喚醒,以便在不忙的機器上反復(fù)調(diào)用同一段的 CPU 熱插拔代碼。觀察電源管理系統(tǒng)調(diào)用 CPU 熱插拔代碼的 BCC 工具 稱為 offcputime.py

請注意,init/main.c 中的代碼在 smp_init() 運行時幾乎已執(zhí)行完畢:引導(dǎo)處理器已經(jīng)完成了大部分一次性初始化操作,其它核無需重復(fù)。盡管如此,跨 CPU 的線程仍然要在每個核上生成,以管理每個核的中斷(IRQ)、工作隊列、定時器和電源事件。例如,通過 ps -o psr 命令可以查看服務(wù)每個 CPU 上的線程的 softirqs 和 workqueues。

  1. # ps -o pid,psr,comm $(pgrep ksoftirqd)
  2. PID PSR COMMAND
  3. 7 0 ksoftirqd/0
  4. 16 1 ksoftirqd/1
  5. 22 2 ksoftirqd/2
  6. 28 3 ksoftirqd/3
  7.  
  8. # ps -o pid,psr,comm $(pgrep kworker)
  9. PID PSR COMMAND
  10. 4 0 kworker/0:0H
  11. 18 1 kworker/1:0H
  12. 24 2 kworker/2:0H
  13. 30 3 kworker/3:0H
  14. [ . . . ]

其中,PSR 字段代表“處理器processor”。每個核還必須擁有自己的定時器和 cpuhp 熱插拔處理程序。

那么用戶空間是如何啟動的呢?在***,kernel_init() 尋找可以代表它執(zhí)行 init 進(jìn)程的 initrd。如果沒有找到,內(nèi)核直接執(zhí)行 init 本身。那么為什么需要 initrd 呢? 

早期的用戶空間:誰規(guī)定要用 initrd?

除了設(shè)備樹之外,在啟動時可以提供給內(nèi)核的另一個文件路徑是 initrd 的路徑。initrd 通常位于 /boot 目錄中,與 x86 系統(tǒng)中的 bzImage 文件 vmlinuz 一樣,或是與 ARM 系統(tǒng)中的 uImage 和設(shè)備樹相同。用 initramfs-tools-core 軟件包中的 lsinitramfs 工具可以列出 initrd 的內(nèi)容。發(fā)行版的 initrd 方案包含了最小化的 /bin/sbin/etc 目錄以及內(nèi)核模塊,還有 /scripts 中的一些文件。所有這些看起來都很熟悉,因為 initrd 大致上是一個簡單的最小化 Linux 根文件系統(tǒng)。看似相似,其實不然,因為位于虛擬內(nèi)存盤中的 /bin/sbin 目錄下的所有可執(zhí)行文件幾乎都是指向 BusyBox 二進(jìn)制文件 的符號鏈接,由此導(dǎo)致 /bin/sbin 目錄比 glibc 的小 10 倍。

如果要做的只是加載一些模塊,然后在普通的根文件系統(tǒng)上啟動 init,為什么還要創(chuàng)建一個 initrd 呢?想想一個加密的根文件系統(tǒng),解密可能依賴于加載一個位于根文件系統(tǒng) /lib/modules 的內(nèi)核模塊,當(dāng)然還有 initrd 中的。加密模塊可能被靜態(tài)地編譯到內(nèi)核中,而不是從文件加載,但有多種原因不希望這樣做。例如,用模塊靜態(tài)編譯內(nèi)核可能會使其太大而不能適應(yīng)存儲空間,或者靜態(tài)編譯可能會違反軟件許可條款。不出所料,存儲、網(wǎng)絡(luò)和人類輸入設(shè)備(HID)驅(qū)動程序也可能存在于 initrd 中。initrd 基本上包含了任何掛載根文件系統(tǒng)所必需的非內(nèi)核代碼。initrd 也是用戶存放 自定義ACPI 表代碼的地方。

救援模式的 shell 和自定義的 initrd 還是很有意思的。

救援模式的 shell 和自定義的 initrd 還是很有意思的。

initrd 對測試文件系統(tǒng)和數(shù)據(jù)存儲設(shè)備也很有用。將這些測試工具存放在 initrd 中,并從內(nèi)存中運行測試,而不是從被測對象中運行。

***,當(dāng) init 開始運行時,系統(tǒng)就啟動啦!由于第二個處理器現(xiàn)在在運行,機器已經(jīng)成為我們所熟知和喜愛的異步、可搶占、不可預(yù)測和高性能的生物。的確,ps -o pid,psr,comm -p 1 很容易顯示用戶空間的 init 進(jìn)程已不在引導(dǎo)處理器上運行了。 

總結(jié)

Linux 引導(dǎo)過程聽起來或許令人生畏,即使是簡單嵌入式設(shè)備上的軟件數(shù)量也是如此。但換個角度來看,啟動過程相當(dāng)簡單,因為啟動中沒有搶占、RCU 和競爭條件等撲朔迷離的復(fù)雜功能。只關(guān)注內(nèi)核和 PID 1 會忽略了引導(dǎo)程序和輔助處理器為運行內(nèi)核執(zhí)行的大量準(zhǔn)備工作。雖然內(nèi)核在 Linux 程序中是***的,但通過一些檢查 ELF 文件的工具也可以了解其結(jié)構(gòu)。學(xué)習(xí)一個正常的啟動過程,可以幫助運維人員處理啟動的故障。 

責(zé)任編輯:龐桂玉 來源: Linux中國
相關(guān)推薦

2009-12-03 10:00:46

Linux系統(tǒng)啟動

2018-10-18 14:06:15

Linux系統(tǒng)過程

2025-06-18 09:01:27

Linux系統(tǒng)啟動系統(tǒng)

2010-05-06 14:05:15

Unix系統(tǒng)

2009-08-11 09:03:45

Windows 7系統(tǒng)啟動

2011-06-28 13:27:13

ARM Linux

2023-09-02 21:39:47

2012-02-20 14:47:08

JavaPlay

2012-08-16 09:07:57

Erlang

2024-09-11 09:25:03

Tomcat組件PREP

2011-08-22 08:53:17

Android啟動過程李洋

2010-03-02 16:13:50

Linux系統(tǒng)啟動過程

2021-02-09 08:23:02

Linux操作系統(tǒng)

2010-03-02 15:45:57

Linux系統(tǒng)啟動過程

2021-08-03 07:59:37

Linux系統(tǒng)地址

2011-07-28 10:34:38

Cocoa 程序 啟動

2014-06-23 10:31:09

Android啟動過程

2011-09-05 17:35:18

MTK啟動過程RTOS

2018-12-06 09:00:06

LinuxWindows雙系統(tǒng)

2010-01-12 13:47:18

Linux grub
點贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 欧美日韩免费一区二区三区 | 国产午夜精品一区二区三区嫩草 | 日韩三片 | 久久久亚洲一区 | 久久久久久网站 | 免费一二区 | 2019天天操| 欧美精品影院 | 色免费在线视频 | 一区二区成人 | 手机av免费在线 | 国产精品久久久乱弄 | 久久久噜噜噜久久中文字幕色伊伊 | 美女久久久久 | 伊人伊成久久人综合网站 | 欧美一级三级 | 免费在线观看一区二区 | 久久久久久免费看 | 综合亚洲视频 | 最新日韩精品 | 久久精品日产第一区二区三区 | 亚洲精品美女在线观看 | 日一区二区 | 天堂在线www| 国产粉嫩尤物极品99综合精品 | 亚洲精品成人 | 欧美成视频 | 国产乱码精品一区二区三区五月婷 | 久久久精品综合 | 午夜精品影院 | 亚洲精品视频三区 | 久久久.com | 午夜精品在线 | 欧美日韩不卡 | 欧美一级欧美三级在线观看 | www.久久.com | 卡通动漫第一页 | 欧美男人天堂 | 高清免费在线 | 久久青草av | 中文字幕在线一区 |