文章目錄
- BIOS完成下面的功能:
- Bootloader的工作
- Setup()的工作
- start_kernel()的工作
原文地址:
http://www.manio.org/cn/startup-of-linux-view-of-society.html
其實這才應該是這一系列文章的第一節,因為這篇文章講的是Apsara Distributed File System開天地的事。話說Mr. Process是一個現代人,但是,只要是人,總該有個祖先。人們總想知道自己從哪來,然後才可以估摸算一下自己將去向何方。所以咱也要瞭解一下Linux的世界裡人類的起源。
圖1:從上電到BIOS
按下電源開關的那個真實的人就是Linux世界裡的上帝,他創造了Linux世界的一切。當他按下機箱上的電源開關時,主板開始供電,CPU上的Reset Pin被拉高,這會引起CPU的一系列動作,這些動作是晶片設計時就決定的。CPU中的一些寄存器被置為固定的值,因為這些寄存器可能在啟動的過程中要使用,比如CS(程式碼片段寄存器)和EIP(指標指令寄存器)。這一步完成之後,CPU就可開執行地址為0xfffffff0裡的ROM中的程式。這段程式就是BIOS(Basic Input Output System)。
BIOS完成下面的功能:
1.POST(Power-On Self Test):顧名思名,就是查查有什麼裝置,這些裝置是不是正常。要是CPU有Advanced Configuration and Power Interface(ACPI )的支援,也在這個時候進行。ACPI是用來對電源進行管理的,用來節電之類的。
2.初始化裝置:確保沒有IRQ和IO衝突。
3.尋找OS/Bootloader。這一步後面點再細說
我們在BIOS的設定菜單裡能夠設定從何處啟動,比如磁碟片,硬碟,光碟機…BIOS會按我們設定的順序搜尋OS。
4.把Bootloader複製到RAM裡(地址為0x00007c00),然後那個地址開始執行。
什麼是Bootloader?
現在,我們只要關心的是:bootloader會找到OS,把OS核心COPY到RAM中。
圖2:boot loader的載入
如所示,在硬碟的第一個sector,有一個分區表(記錄了哪些分區上有作業系統)和一個小版的Bootloader。當這個BIOS被設定為從這裡啟動時,這個小版的bootloader被複製到RAM的0x00007c00。然後它會把自己又移動到0x00096a00。在這之後,它再把另一段Bootloader從硬碟上複製到0x00096c00,然後從那裡開始執行。分作兩段的原因是因為現在的bootloader太大了,在MBR上存不完那麼多。
Bootloader會把OS的核心映像複製到RAM中。
Bootloader的工作
1. 調用BIOS以顯示“Loading Image”的訊息。
2. 調用BIOS,把核心映像的前512位元組複製到0×00090000,setup()函數在0×00090200。
3. 調用BIOS,把剩下的核心映像載入到0×00010000(小核心zImage)或0×00100000(大核心bzImage)
4. 跳到setup()開始執行。
Setup()的工作
setup()用來初始化裝置。雖然BIOS已經做了一些初始化的工作,但是Linux關不依賴於他。setup()會初始化鍵盤,FPU等裝置,並設定一些寄存器。在Setup()的最後,會調用startup_32()。
startup_32()
Linux裡有兩個startup_32()。
首先會執行的是arch/i386/boot/compressed/head.S裡的那個。這個startup_32()的作用主要是解壓核心。
第二個startup_32()是在arch/i386/kernel/head.S的。這個startup_32()的工作就是為Linux的第一個進程(就是Mr. Process的祖先)設定生存環境。最後跳到start_kernel()中去。
在Understanding the Linux Kernel 3rd 中的描述如下
- Initializes the segmentation registers with their final values.
- Fills the bss segment of the kernel (see the section “Program Segments and Process Memory Regions” in Chapter 20) with zeros.
- Initializes the provisional kernel Page Tables contained in swapper_pg_dir and pg0 to identically map the linear addresses to the same physical addresses, as explained in the section “Kernel Page Tables” in Chapter 2.
- Stores the address of the Page Global Directory in the cr3 register, and enables paging by setting the PG bit in the cr0 register.
- Sets up the Kernel Mode stack for process 0 (see the section “Kernel Threads” in Chapter 3).
- Once again, the function clears all bits in the eflags register.
- Invokes setup_idt( ) to fill the IDT with null interrupt handlers (see the section “Preliminary Initialization of the IDT” in Chapter 4).
- Puts the system parameters obtained from the BIOS and the parameters passed to the operating system into the first page frame (see the section “Physical Memory Layout” in Chapter 2).
- Identifies the model of the processor.
10. Loads the gdtr and idtr registers with the addresses of the GDT and IDT tables.
11. Jumps to the start_kernel( ) function.
start_kernel()的工作
完成所有組件的初始化工作。
Understanding the Linux Kernel對這一段工作的描述如下:
¨ The scheduler is initialized by invoking the sched_init( ) function (see Chapter 7).
¨ The memory zones are initialized by invoking the build_all_zonelists( ) function (see the section “Memory Zones” in Chapter 8).
¨ The Buddy system allocators are initialized by invoking the page_alloc_init( ) and mem_init( ) functions (see the section “The Buddy System Algorithm” in Chapter 8).
¨ The final initialization of the IDT is performed by invoking trap_init( ) (see the section “Exception Handling” in Chapter 4) and init_IRQ( ) (see the section “IRQ data structures” in Chapter 4).
¨ The TASKLET_SOFTIRQ and HI_SOFTIRQ are initialized by invoking the softirq_init( ) function (see the section “Softirqs” in Chapter 4).
¨ The system date and time are initialized by the time_init( ) function (see the section “The Linux Timekeeping Architecture” in Chapter 6).
¨ The slab allocator is initialized by the kmem_cache_init( ) function (see the section “General and Specific Caches” in Chapter 8).
¨ The speed of the CPU clock is determined by invoking the calibrate_delay( ) function (see the section “Delay Functions” in Chapter 6).
¨ The kernel thread for process 1 is created by invoking the kernel_thread( ) function. In turn, this kernel thread creates the other kernel threads and executes the /sbin/init program, as described in the section “Kernel Threads” in Chapter 3.
以上幾個函數的執行過程如:
圖3:啟動函數的執行過程
第二個startup_32()和start_kernel()揭示了Linux一生的真諦。從這裡面咱看到了Mr. Process(一個普通的進程)所擁有的一切是怎麼得到的。弄清楚了這些,也就弄清楚了Linux。Really清楚。
BTW,我做的圖怎麼那麼好看~美感天生在那裡,你擋都擋不住,怎麼搞怎麼好看加專業!