?? jjj-start_kernel.txt
字號:
(系統(tǒng)初始化start_kernel函數(shù))
作者:大鷹mailto:e4gle@hackermail.com
至于x86的引導無非如下步驟:
1,cpu初始化自身,在固定位置執(zhí)行一條指令。
2,這條指令條轉到bios中。
3,bios找到啟動設備并獲取mbr,該mbr指向我們的lilo
4,bios裝載并把控制權交給lilo
5,壓縮內核自解壓,并把控制權轉交給解壓內核。
簡單點講,就是cpu成為內核引導程序的引導程序的引導程序的引導程序,西西。
這時內核將跳轉到start_kernel是/init/main.c的重點函數(shù),main.c函數(shù)很多定義都是為此函數(shù)服務的,這里
我簡要介紹一下這個函數(shù)的初始化流程。
初始化內核:
從start_kernel函數(shù)(/init/main.c)開始系統(tǒng)初始化工作,好,我們首先分析這個函數(shù):
函數(shù)開始首先:
#ifdef __SMP__
static int boot_cpu = 1;
/* "current" has been set up, we need to load it now *//*定義雙處理器用*/
if (!boot_cpu)
initialize_secondary();
boot_cpu = 0;
#endif
定義雙處理器。
printk(linux_banner); /*打印linux banner*/
打印內核標題信息。
開始初始化自身的部分組件(包括內存,硬件終端,調度等),我來逐個分析其中的函數(shù):
setup_arch(&command_line, &memory_start, &memory_end);/*初始化內存*/
返回內核參數(shù)和內核可用的物理地址范圍
函數(shù)原型如下:
setup_arch(char **, unsigned long *, unsigned long *);
返回內存起始地址:
memory_start = paging_init(memory_start,memory_end);
看看paging_init的定義,是初始化請求頁:
paging_init(unsigned long start_mem, unsigned long end_mem)(會在以后的內存管理子系統(tǒng)分析時詳細介
紹)
{
int i;
struct memclust_struct * cluster;
struct memdesc_struct * memdesc;
/* initialize mem_map[] */
start_mem = free_area_init(start_mem, end_mem);/*遍歷查找內存的空閑頁*/
/* find free clusters, update mem_map[] accordingly */
memdesc = (struct memdesc_struct *)
(hwrpb->mddt_offset + (unsigned long) hwrpb);
cluster = memdesc->cluster;
for (i = memdesc->numclusters ; i > 0; i--, cluster++) {
unsigned long pfn, nr;
/* Bit 0 is console/PALcode reserved. Bit 1 is
non-volatile memory -- we might want to mark
this for later */
if (cluster->usage & 3)
continue;
pfn = cluster->start_pfn;
if (pfn >= MAP_NR(end_mem)) /* if we overrode mem size */
continue;
nr = cluster->numpages;
if ((pfn + nr) > MAP_NR(end_mem)) /* if override in cluster */
nr = MAP_NR(end_mem) - pfn;
while (nr--)
clear_bit(PG_reserved, &mem_map[pfn++].flags);
}
memset((void *) ZERO_PAGE(0), 0, PAGE_SIZE);
return start_mem;
}
trap_init(); 初始化硬件中斷
/arch/i386/kernel/traps.c文件里定義此函數(shù)
sched_init() 初始化調度
/kernel/sched.c文件里有詳細的調度算法(這些會在以后進程管理和調度的結構分析中詳細介紹)
parse_options(command_line) 分析傳給內核的各種選項(隨后再詳細介紹)
memory_start = console_init(memory_start,memory_end) 初始化控制臺
memory_start = kmem_cache_init(memory_start, memory_end) 初始化內核內存cache(同樣,在以后的內存
管理分析中介紹此函數(shù))
sti();接受硬件中斷
kernel_thread(init, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
current->need_resched = 1; need_resched標志增加,調用schedule(調度里面會詳細說明)
cpu_idle(NULL) 進入idle循環(huán)以消耗空閑的cpu時間片
已經基本完成內核初始化工作,已經把需要完成的少量責任傳遞給了init,所身于地工作不過是進入idle循環(huán)
以消耗空閑的cpu時間片。所以在這里調用了cpu_idle(NULL),它從不返回,所以當有實際工作好處理時,該函
數(shù)就會被搶占。
parse_options函數(shù):
static void __init parse_options(char *line)/*參數(shù)收集在一條長命令行中,內核被賦給指向該命令行頭
部的指針*/
{
char *next;
char *quote;
int args, envs;
if (!*line)
return;
args = 0;
envs = 1; /* TERM is set to 'linux' by default */
next = line;
while ((line = next) != NULL) {
quote = strchr(line,'"');
next = strchr(line, ' ');
while (next != NULL && quote != NULL && quote < next) {
next = strchr(quote+1, '"');
if (next != NULL) {
quote = strchr(next+1, '"');
next = strchr(next+1, ' ');
}
}
if (next != NULL)
*next++ = 0;
/*
* check for kernel options first..
*/
if (!strcmp(line,"ro")) {
root_mountflags |= MS_RDONLY;
continue;
}
if (!strcmp(line,"rw")) {
root_mountflags &= ~MS_RDONLY;
continue;
}
if (!strcmp(line,"debug")) {
console_loglevel = 10;
continue;
}
if (!strcmp(line,"quiet")) {
console_loglevel = 4;
continue;
}
if (!strncmp(line,"init=",5)) {
line += 5;
execute_command = line;
args = 0;
continue;
}
if (checksetup(line))
continue;
if (strchr(line,'=')) {
if (envs >= MAX_INIT_ENVS)
break;
envp_init[++envs] = line;
} else {
if (args >= MAX_INIT_ARGS)
break;
argv_init[++args] = line;
}
}
argv_init[args+1] = NULL;
envp_init[envs+1] = NULL;
}
原作者:大鷹
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -