計算機啟動過程


前言

這篇文章是在看了很多前輩寫的博客下完成的,一些表述和圖來自參考資料,非原創 ,該篇先從ROM RAM 這些硬件介紹,然后從啟動的過程最主要的主角:BIOS 開始,介紹整個過程。

前期知識

ROM 和 RAM 是什么, 有什么區別

    參考: [什么是ROM 什么是RAM【詳細介紹】](https://zhuanlan.zhihu.com/p/71383426) 和  https://baijiahao.baidu.com/s?id=1669115625475225711&wfr=spider&for=pc

ROM

ROM (Read-Only Memory) , 如下圖 , 他的作用
把固件(系統軟件)燒錄進Flash,然后就不能修改了。不管用戶怎么重新啟動,怎么運用,都不會影響到固件。也就是說, 固件是不可被寫入的 ,因此叫做“只讀儲存器”。
1297993-20211029152853878-1068744821.jpg

RAM

RAM (Random-Access Memory) , 隨機儲存器 ,就是電腦的內存條。用於存放動態數據。(也叫運行內存)系統運行的時候,需要把操作系統從ROM中讀取出來,放在RAM中運行。

1297993-20211029155436359-1794960879.jpg

1297993-20211110105527327-895182707.jpg

可以看出 ROM 和 RAM 同屬於硬件, 不同的是 ROM 經常被嵌入到元器件當中 ,而RAM 是我們熟悉的內存 ,通常可拔插 .

BIOS

"基本輸出輸入系統"(Basic Input/Output System),簡稱為BIOS。它是一組固化到計算機內主板上一個ROM芯片上的程序,它保存着計算機最重要的基本輸入輸出的程序、開機后自檢程序和系統自啟動程序,它可從CMOS中讀寫系統設置的具體信息。 其主要功能是為計算機提供最底層的、最直接的硬件設置和控制。

加載 BIOS

    原文鏈接:https://blog.csdn.net/weixin_46350177/article/details/116796559

計算機剛開機的時候只有1M的內存可以使用。 此時內存會被各種外設瓜分,映射在內存的相應區域。同理,BIOS里的信息會被映射到內存的一段連續的區域中(0xC00000xFFFFF),其中最為關鍵的系統BIOS被映射到了0xF00000xFFFFF位置,CPU開機就是執行了系統BIOS這塊內存區域中的代碼,注意BIOS中的程序還會占用內存開頭的一些區域,如把中斷向量表寫在了內存開始的位置。

在開機的一瞬間,CPU中的PC寄存器被強制初始化為0xFFFF0。BIOS程序的入口地址就是0xFFFF0,然后CPU就開始跑起來,執行BIOS中的程序。

BIOS 做了什么

	這里摘自來自 https://www.jeanleo.com/2018/08/28/linux%E6%9C%BA%E5%99%A8%E5%90%AF%E5%8A%A8%E8%BF%87%E7%A8%8B/ 的描述, 非原創 

機器啟動到linux初始化是一個比較復雜並且細節性較強的過程,大部分的實現都是由於歷史遺留問題以及各種協議約定而來的,銜接性比較強,而且比較難跟蹤,畢竟不是C語言那么簡單,一個函數調用一個函數,整個脈絡比較清晰明了。

這里主要是以linux-3.2.55版本內核為基礎,將整個系統的初始化流程梳理了一下。

進入正文:

A、 自摁下電源開關后,是由主板自動初始化處理器信息的,將CS、DS、ES、SS置為0xffff,而PC置為0x0000(物理地址),由於初始化時,處理器處於實模式,那么也就是計算機執行的第一條指令在0xffff0(物理地址)這個位置。計算機執行的第一條指令是來自BIOS的,存儲在ROM里面,通過ROM芯片譯碼以讀取出來執行,該指令通常都是一條跳轉指令,這是由於0xffff0距離可訪問的內存結尾已經不遠了,該指令可以用來跳轉到具體的BIOS操作代碼中;

B、 BIOS開始執行后,做了不少事情,比如Power On Self Test(POST,開機自檢),檢查CPU寄存器、周邊芯片的狀態,以及針對動態內存、主板芯片組、顯卡以及相關外圍的寄存器做初始化設置,並檢查能夠正常工作,同時記錄系統的設置值,最重要的就是將常駐程序庫(可以理解為BIOS的庫)放置在某段內存中,提供給操作系統或者應用程序調用,比如int 0x13等

C、 BIOS畢竟不是系統,完成了分內工作后,執行int 0x19(前面提到的BIOS的常駐程序庫)將存儲在磁盤0頭0道0扇區的MBR讀入到內存0x7c00中,然后BIOS通過跳轉指令去到0x7c00去執行引導程序代碼;

D、 MBR的引導程序對不同的linux版本而言各有不同,最初0.11版本中,linux的/boot/bootsect.s自己實現了這個MBR引導程序,而如今3.2.55的linux內核版本自身已經不再實現MBR引導程序了,都是由GRUB的/stage1/stage1.S實現的,具體的引導程序歷史可以參考linux內核中的/Documentation/x86/boot.txt;

E、 Linux 0.11的引導過程就不談了,關於這塊的資料數不勝數,那么GRUB實現的引導,主要是給用戶提供了系統引導選擇和引導編輯等功能,核心的是它通過調用BIOS的常駐程序庫去將linux內核映像加載到內存當中

F、 GRUB加載完了內核映像,將會跳轉到內核的/ arch/x86/boot/header.S里面的_start開始執行,其實_start也沒什么好執行的,就跳轉到start_of_setup去設置准備給實模式下main函數運行的環境;

G、 開始進入main函數執行,該函數的實現在/arch/x86/boot/main.c文件里面,具體可以進入去分析里面的代碼,其主要的莫過於一些參數的准備、堆的初始化、CPU的檢測、BIOS的設置以及內存檢測等工作,然后開始轉入保護模式 (到這個地方才進入了保護模式);

H、 進入保護模式后,將會跳轉去執行arch/x86/boot/compressed/head_32.S里面的startup_32,其主要設置一個基本的環境,如堆棧等;

I、 再往下就是調用/arch/x86/boot/compressed/misc.c里面的decompress_kernel,用來解壓內核,當內核被解壓到內存中之后,就可以調用它了;

J、 解壓完內核,還要調用一個startup_32,這個不同於前面的那個,這個是位於/arch/x86/kernel/head_32.S里面的,主要工作是對頁表進行初始化,並啟動內存分頁功能,初始化0號進程;

K、 startup_32 執行完了之后,最后進入內核的主題函數start_kernel,該函數位於/init/main.c,自此完成linux的最后初始化。

以上就是機器啟動linux的整個過程,主要是梳理了初始化實現的一個線索,暫時不深入分析。

我們總結一下, 大概的流程就是 :

  1. BIOS 運行自己的開機程序
  2. 硬件自檢
  3. 加載內核鏡像 , (交給操作系統了)
  4. 進入實模式ing...
  5. 保護模式 (頁表還沒初始化)
  6. 解壓內核到內存當中(開始操作系統的運行啦)
  7. 頁表初始化
  8. 初始化 0 號進程
  9. main 函數

其中加載MBR的過程如下 :

    所謂的加載: 就是把某設備(如硬盤)中的程序復制到內存中的過程。
    加載啟動區就是: BIOS程序把啟動區的內容復制到了內存的某區域

    什么是啟動區?
    啟動區是符合某種特征的一塊區域,人們把它叫做啟動區。

    BIOS的查找啟動盤的順序是可以設置的,如U盤啟動,硬盤啟動,軟盤啟動,光盤啟動等。

    所謂的符合某種特征指的是: BIOS會按照設置的啟動盤順序,輪流去讀取這些啟動盤中位於0盤0道1扇區的內容。這0盤0道1扇區一共有512字節,如果末尾的兩個字節分別是0x55和0xaa,那么BIOS就會認為它是個啟動區。如果不是,就下一個啟動盤接着尋找,都找不到的話會報出無啟動區的錯誤。

    BIOS把啟動區的512字節復制到內存的0x7c00位置,並用一條跳轉指令把pc寄存器的值指向0x7c00。

可以看這篇文章,可以知道在0盤0道1扇區有個MBR的區域。

圖例 :

1297993-20211111215340619-399966103.png

GRUB

上面我們講的第D個步驟 , 這個 GRUB 是什么東西呢 ? GRUB 是個引導操作系統的程序 ,下面來自 GRUB 官網的介紹
1.1 Overview
Briefly, a boot loader is the first software program that runs when a computer starts. It is responsible for loading and transferring control to an operating system kernel software (such as Linux or GNU Mach). The kernel, in turn, initializes the rest of the operating system (e.g. a GNU system).

	GNU GRUB is a very powerful boot loader, which can load a wide variety of free operating systems, as well as proprietary operating systems with chain-loading1. GRUB is designed to address the complexity of booting a personal computer; both the program and this manual are tightly bound to that computer platform, although porting to other platforms may be addressed in the future.

	One of the important features in GRUB is flexibility; GRUB understands filesystems and kernel executable formats, so you can load an arbitrary operating system the way you like, without recording the physical position of your kernel on the disk. Thus you can load the kernel just by specifying its file name and the drive and partition where the kernel resides.

	簡而言之,引導加載程序是計算機啟動時運行的第一個軟件程序。它負責加載和傳輸控制到操作系統內核軟件(如 Linux 或 GNU Mach)。內核反過來初始化操作系統的其余部分(例如 GNU 系統)。

	GNU GRUB 是一個非常強大的引導加載程序,它可以加載各種各樣的免費操作系統,以及具有鏈加載1 的專有操作系統。GRUB 旨在解決啟動個人計算機的復雜性;該程序和本手冊都與該計算機平台緊密相關,盡管將來可能會移植到其他平台。

	GRUB 的重要特性之一是靈活性;GRUB 了解文件系統和內核可執行格式,因此您可以按照自己喜歡的方式加載任意操作系統,而無需記錄內核在磁盤上的物理位置。因此,您只需指定內核的文件名以及內核所在的驅動器和分區即可加載內核。

下面是來自:

	Windows也有類似的工具NTLOADER;比如我們在機器中安裝了Windows 98后,我們再安裝一個Windows XP,在機器啟動的會有一個菜單讓我們選擇進入是進入Windows 98還是進入WindowsXP。NTLOADER就是一個多系統啟動引導管理器,NTLOADER同樣也能引導Linux,只是極為麻煩罷了;

	在Powerpc架構的機器中,如果安裝了Linux的Powerpc版本,大多是用yaboot多重引導管理器,比如Apple機目前用的是IBM Powerpc處理器,所以在如果想在Apple機上,安裝Macos和LinuxPowerpc版本,大多是用yaboot來引導多個操作系統;

	因為目前X86架構的機器仍是主流,所以目前GRUB和LILO仍然是我們最常用的多重操作系統引導管理器;

語摘

	lvzongting 說:

	對於這個話題很感興趣,根據自己了解的補充幾點內存地址的東西:
	1.計算機開機時,CPU默認執行0ffffh:0000h處的指令(8086是這樣,386應該類似),而此內存地址應該存放的就是bios rom
	2.bios執行玩post等后,將引導設備的mbr復制到內存地址07c00h處,跳轉執行此處指令,這個地址應該是規定的
	3.現在一般引導設備中的mbr是grub或lilo這樣的引導程序,這樣的程序首先將自己復制到06c00h處執行,在主分區表中搜索活動分區,將用戶選擇的活動分區的第一個扇區讀入到07c00h處,調轉到07c00h處執行
	注:以上均在實模式中執行,還未進入保護模式
	4.為加載內核做准備,並將控制權交給kernel,系統啟動成功
	注:這一步進入保護模式
	當然這是現在一般的啟動流程,當然如果自己寫os,可以直接在引導設備的mbr中寫直接加載內核的代碼,將編譯的代碼dd入引導設備的mbr中即可。





	成仔不說話 說:

	bios不一定存在,bios只是提供了一個固定的方式,去訪問其他輸入輸出設備,存在的目的是可以將硬件的變化簡化,這樣內核就可以通過和固定的bios通信來獲取基本的硬件地址信息,然后再獲得更充分的硬件地址信息。沒有bios的計算機,就沒有這么一個固定的方式,隨着硬件的改變,就要靜態的改變內核內部設備的入口地址,然后重新編譯。可以這么說bios是使得現在操作系統變得通用的一個利器。比如現在不同的arm手機的內核不能隨便換着用,而有bios的計算機內核即使硬件不那么一樣,卻可以用同樣的內核。還比如現在很多時候都會將硬件地址的map獨立於內核寫到一個單獨的文件中,內核載入的時候會從這些文件中讀取硬件的入口地址.  
	
	從上電開始,處理器的指令計數器會被初始化成一個值(這個值不一定是0x0000H,因為一般還會在前面放中斷向量表),然后從這個地址開始執行程序。這些程序有可能放到片內的flash,有可能放到片外的flash,或是RAM里面。由於RAM是掉電易失的,所以可能需要先從其他存儲設備中載入內存然后再從內存中調入片內進行運算。

參考資料


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM