2009年11月10日

Linux kernel linux-2.6.15.5.tar.bz2 啟動流程(i386)

kernel:linux-2.6.15.5.tar.bz2

配合Linux裝置驅動程式之開發詳解一書3.4章節閱讀

必備工具知識:vim,ctags使用,vim中可使用"/"來搜尋字串,並用"n"來搜尋下一個字串

i386中
1.bzImage被呼叫時,從/arch/i386/boot/setup.S的start:開始執行,並進行一些基本硬體設定
start:
jmp     trampoline

# This is the setup header, 
and it must start at %cs:2 (old 0x9020:2)

.ascii  "HdrS"          # header signature

2.接著呼叫/arch/i386/boot/compressed/head.S
# jump to startup_32 in arch/i386/boot/compressed/head.S
3./arch/i386/boot/compressed/head.S之中有個startup_32常式,其主要功能為設定基本的執行環境,如堆疊,之後清除BSS段,並呼叫/arch/i386/boot/compressed/misc.c的decompress_kernel()解壓縮核心到記憶體,再跳到新的kernel

(/arch/i386/boot/compressed/head.S)
.globl startup_32

startup_32:
cld
cli
movl $(__BOOT_DS),%eax
movl %eax,%ds

/*
* Clear BSS
*/
xorl %eax,%eax
movl $_edata,%edi
movl $_end,%ecx
subl %edi,%ecx
cld
rep
stosb
......
/*
* Do the decompression, and jump to the new kernel..
*/
......
call decompress_kernel


(/arch/i386/boot/compressed/misc.c)

asmlinkage int decompress_kernel(struct moveparams *mv, void *rmode)
{
real_mode = rmode;

if (RM_SCREEN_INFO.orig_video_mode == 7) {
vidmem = (char *) 0xb0000;
vidport = 0x3b4;
} else {
vidmem = (char *) 0xb8000;
vidport = 0x3d4;
}

lines = RM_SCREEN_INFO.orig_video_lines;
cols = RM_SCREEN_INFO.orig_video_cols;

if (free_mem_ptr < 0x100000) setup_normal_output_buffer();
else setup_output_buffer_if_we_run_high(mv);

makecrc();
putstr("Uncompressing Linux... ");
gunzip();
putstr("Ok, booting the kernel.\n");
if (high_loaded) close_output_buffer_if_we_run_high(mv);
return high_loaded;
}
4.核心被解壓縮到記憶體後,會再呼叫/arch/i386/kernel/head.S的startup_32常式,會初始化page table,並啟用記憶體分頁機制
ENTRY(startup_32)
5.而上述做完之後,/init/main.c的start_kernel()被呼叫,進入和平台架構無關的linux核心部份,此時呼叫一堆初始化函式來設定中斷,和進一步的記憶體設定
/*
*      Activate the first processor.
*/

asmlinkage void __init start_kernel(void)
{
6.而/arch/i386/kernel/process.c中kernel_thread()啟動第一個核心thread,此執行緒執行init(),再來呼叫cpu_idle()等待排程 ?????? 7./init/main.c此時為核心執行緒,完成週邊設備和其driver的載入和初始化,和掛載根目錄,他會搜索檔案系統裡面的init程式,並使用execve()系統呼叫來執行init程式,順序為如下:
run_init_process("/sbin/init");
run_init_process("/etc/init");
run_init_process("/bin/init");
run_init_process("/bin/sh");
ps.多數情況下,嵌入式系統可以給核心傳入一個簡單的shell命令搞(script)來啟動必須的嵌入式應用程式 到目前為止,慢長得LInux核心初始化和啟動過程就結束了,而init()對應的,和由start_kernel()創見的第一個執行緒也進入使用者模式

沒有留言:

張貼留言

NO-CARRIER 網卡無法啟動

 工作時,由於想要啟動linux OS的網卡, 發現某張新設定的網卡一直無法啟動,就算下指令UP了,但是也沒有順利啟動 所以爬文後,想要確認該網卡的status, 發現某行為: eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu...