Linux init main.c源代碼分析_第1頁
Linux init main.c源代碼分析_第2頁
已閱讀5頁,還剩15頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、linux init main.c源代碼分析 1 /*2 * linux/init/main.c3 *4 * (c) 1991 linus torvalds5 */67 #define _library_ / 定義該變量是為了包括定義在unistd.h 中的內(nèi)嵌匯編代碼等信息。8 #include unistd.h / *.h 頭文件所在的默認(rèn)名目是include/,則在代碼中就不用明確指明位置。/ 假如不是unix 的標(biāo)準(zhǔn)頭文件,則需要指明所在的名目,并用雙引號(hào)括住。/ 標(biāo)準(zhǔn)符號(hào)常數(shù)與類型文件。定義了各種符號(hào)常數(shù)和類型,并申明白各種函數(shù)。/ 假如定義了_library_,則還含系統(tǒng)調(diào)用號(hào)和內(nèi)

2、嵌匯編代碼syscall0()等。9 #include time.h / 時(shí)間類型頭文件。其中最主要定義了tm 結(jié)構(gòu)和一些有關(guān)時(shí)間的函數(shù)原形。1011 /*12 * we need this inline - forking from kernel space will result13 * in no copy on write (!), until an execve is executed. this14 * is no problem, but for the stack. this is handled by not letting15 * main() use the stack

3、at all after fork(). thus, no function16 * calls - which means inline code for fork too, as otherwise we17 * would use the stack upon exit from 'fork()'.18 *19 * actually only pause and fork are needed inline, so that there20 * won't be any messing with the stack from main(), but we defi

4、ne21 * some others too.22 */* 我們需要下面這些內(nèi)嵌語句 - 從內(nèi)核空間創(chuàng)建進(jìn)程(forking)將導(dǎo)致沒有寫時(shí)復(fù)制(copy onwrite)!* 直到執(zhí)行一個(gè)execve 調(diào)用。這對(duì)堆??赡軒韱栴}。處理的方法是在fork()調(diào)用之后不讓main()使用* 任何堆棧。因此就不能有函數(shù)調(diào)用 - 這意味著fork 也要使用內(nèi)嵌的代碼,否則我們?cè)趶膄ork()退出* 時(shí)就要使用堆棧了。* 實(shí)際上只有pause 和fork 需要使用內(nèi)嵌方式,以保證從main()中不會(huì)弄亂堆棧,但是我們同時(shí)還* 定義了其它一些函數(shù)。*/ 本程序?qū)?huì)在移動(dòng)到用戶模式(切換到任務(wù)0)后才執(zhí)行

5、fork(),因此避開了在內(nèi)核空間寫時(shí)復(fù)制問題。/ 在執(zhí)行了moveto_user_mode()之后,本程序就以任務(wù)0 的身份在運(yùn)行了。而任務(wù)0 是全部將創(chuàng)建的子/ 進(jìn)程的父進(jìn)程。當(dāng)創(chuàng)建第一個(gè)子進(jìn)程時(shí),任務(wù)0 的堆棧也會(huì)被復(fù)制。因此盼望在main.c 運(yùn)行在任務(wù)0/ 的環(huán)境下時(shí)不要有對(duì)堆棧的任何操作,以免弄亂堆棧,從而也不會(huì)弄亂全部子進(jìn)程的堆棧。23 static inline _syscall0(int,fork)/ 這是unistd.h 中的內(nèi)嵌宏代碼。以嵌入?yún)R編的形式調(diào)用linux 的系統(tǒng)調(diào)用中斷0x80。該中斷是全部/ 系統(tǒng)調(diào)用的入口。該條語句實(shí)際上是int fork()創(chuàng)建進(jìn)程系統(tǒng)調(diào)

6、用。/ syscall0 名稱中最終的0 表示無參數(shù),1 表示1 個(gè)參數(shù)。參見include/unistd.h,133 行。24 static inline _syscall0(int,pause) / int pause()系統(tǒng)調(diào)用:暫停進(jìn)程的執(zhí)行,直到/ 收到一個(gè)信號(hào)。25 static inline _syscall1(int,setup,void *,bios) / int setup(void * bios)系統(tǒng)調(diào)用,僅用于 / linux 初始化(僅在這個(gè)程序中被調(diào)用)。 26 static inline _syscall0(int,sync) / int sync()系統(tǒng)調(diào)用:更

7、新文件系統(tǒng)。2728 #include linux/tty.h / tty 頭文件,定義了有關(guān)tty_io,串行通信方面的參數(shù)、常數(shù)。29 #include linux/sched.h / 調(diào)度程序頭文件,定義了任務(wù)結(jié)構(gòu)task_struct、第1 個(gè)初始任務(wù)/ 的數(shù)據(jù)。還有一些以宏的形式定義的有關(guān)描述符參數(shù)設(shè)置和獵取的/ 嵌入式匯編函數(shù)程序。30 #include linux/head.h / head 頭文件,定義了段描述符的簡(jiǎn)潔結(jié)構(gòu),和幾個(gè)選擇符常量。31 #include asm/system.h / 系統(tǒng)頭文件。以宏的形式定義了很多有關(guān)設(shè)置或修改/ 描述符/中斷門等的嵌入式匯編子程序

8、。32 #include asm/io.h / io 頭文件。以宏的嵌入?yún)R編程序形式定義對(duì)io 端口操作的函數(shù)。3334 #include stddef.h / 標(biāo)準(zhǔn)定義頭文件。定義了null, offsetof(type, member)。35 #include stdarg.h / 標(biāo)準(zhǔn)參數(shù)頭文件。以宏的形式定義變量參數(shù)列表。主要說明白-個(gè)/ 類型(va_list)和三個(gè)宏(va_start, va_arg 和va_end),vsprintf、/ vprintf、vfprintf。36 #include unistd.h37 #include fcntl.h / 文件掌握頭文件。用于文件及

9、其描述符的操作掌握常數(shù)符號(hào)的定義。38 #include sys/types.h / 類型頭文件。定義了基本的系統(tǒng)數(shù)據(jù)類型。3940 #include linux/fs.h / 文件系統(tǒng)頭文件。定義文件表結(jié)構(gòu)(file,buffer_head,m_inode 等)。4142 static char printbuf1024; / 靜態(tài)字符串?dāng)?shù)組,用作內(nèi)核顯示信息的緩存。4344 extern int vsprintf(); / 送格式化輸出到一字符串中(在kernel/vsprintf.c,92 行)。45 extern void init(void); / 函數(shù)原形,初始化(在168 行)。

10、46 extern void blk_dev_init(void); / 塊設(shè)備初始化子程序(kernel/blk_drv/ll_rw_blk.c,157 行)47 extern void chr_dev_init(void); / 字符設(shè)備初始化(kernel/chr_drv/tty_io.c, 347 行)48 extern void hd_init(void); / 硬盤初始化程序(kernel/blk_drv/hd.c, 343 行)49 extern void floppy_init(void); / 軟驅(qū)初始化程序(kernel/blk_drv/floppy.c, 457 行)50

11、 extern void mem_init(long start, long end); / 內(nèi)存管理初始化(mm/memory.c, 399 行)51 extern long rd_init(long mem_start, int length); / 虛擬盤初始化(kernel/blk_drv/ramdisk.c,52)52 extern long kernel_mktime(struct tm * tm); / 計(jì)算系統(tǒng)開機(jī)啟動(dòng)時(shí)間(秒)。53 extern long startup_time; / 內(nèi)核啟動(dòng)時(shí)間(開機(jī)時(shí)間)(秒)。5455 /*56 * this is set up b

12、y the setup-routine at boot-time57 */* 以下這些數(shù)據(jù)是由setup.s 程序在引導(dǎo)時(shí)間設(shè)置的(參見第3 章中表3.2)。*/58 #define ext_mem_k (*(unsigned short *)0x90002) / 1m 以后的擴(kuò)展內(nèi)存大?。╧b)。59 #define drive_info (*(struct drive_info *)0x90080) / 硬盤參數(shù)表基址。60 #define orig_root_dev (*(unsigned short *)0 x901fc) / 根文件系統(tǒng)所在設(shè)備號(hào)。 6162 /*63 * yeah,

13、 yeah, it's ugly, but i cannot find how to do this correctly64 * and this seems to work. i anybody has more info on the real-time65 * clock i'd be interested. most of this was trial and error, and some66 * bios-listing reading. urghh.67 */* 是啊,是啊,下面這段程序很差勁,但我不知道如何正確地實(shí)現(xiàn),而且好象它還能運(yùn)行。假如有* 關(guān)于實(shí)時(shí)時(shí)鐘更

14、多的資料,那我很感愛好。這些都是摸索出來的,以及看了一些bios 程序,呵!*/6869 #define cmos_read(addr) ( / 這段宏讀取cmos 實(shí)時(shí)時(shí)鐘信息。70 outb_p(0x80|addr,0x70); / 0x70 是寫端口號(hào),0x80|addr 是要讀取的cmos 內(nèi)存地址。71 inb_p(0x71); / 0x71 是讀端口號(hào)。72 )73/ 定義宏。將bcd 碼轉(zhuǎn)換成二進(jìn)制數(shù)值。74 #define bcd_to_bin(val) (val)=(val)15) + (val)4)*10)75/ 該子程序取cmos 時(shí)鐘,并設(shè)置開機(jī)時(shí)間.startup_t

15、ime(秒)。參見后面cmos 內(nèi)存列表。76 static void time_init(void)77 78 struct tm time; / 時(shí)間結(jié)構(gòu)tm 定義在include/time.h 中。79/ cmos 的訪問速度很慢。為了減小時(shí)間誤差,在讀取了下面循環(huán)中全部數(shù)值后,若此時(shí)cmos 中秒值/ 發(fā)生了變化,那么就重新讀取全部值。這樣內(nèi)核就能把與cmos 的時(shí)間誤差掌握在1 秒之內(nèi)。80 do 81 time.tm_sec = cmos_read(0); / 當(dāng)前時(shí)間秒值(均是bcd 碼值)。82 time.tm_min = cmos_read(2); / 當(dāng)前分鐘值。83 ti

16、me.tm_hour = cmos_read(4); / 當(dāng)前小時(shí)值。84 time.tm_mday = cmos_read(7); / 一月中的當(dāng)天日期。85 time.tm_mon = cmos_read(8); / 當(dāng)前月份(112)。86 time.tm_year = cmos_read(9); / 當(dāng)前年份。87 while (time.tm_sec != cmos_read(0);88 bcd_to_bin(time.tm_sec); / 轉(zhuǎn)換成二進(jìn)制數(shù)值。89 bcd_to_bin(time.tm_min);90 bcd_to_bin(time.tm_hour);91 bcd_t

17、o_bin(time.tm_mday);92 bcd_to_bin(time.tm_mon);93 bcd_to_bin(time.tm_year);94 time.tm_mon-; / tm_mon 中月份范圍是011。/ 調(diào)用kernel/mktime.c 中函數(shù),計(jì)算從1970 年1 月1 日0 時(shí)起到開機(jī)當(dāng)日經(jīng)過的秒數(shù),作為開機(jī)/ 時(shí)間。95 startup_time = kernel_mktime(time);96 9798 static long memory_end = 0; / 機(jī)器具有的物理內(nèi)存容量(字節(jié)數(shù))。99 static long buffer_memory_end

18、= 0; / 高速緩沖區(qū)末端地址。100 static long main_memory_start = 0; / 主內(nèi)存(將用于分頁)開頭的位置。101102 struct drive_info char dummy32; drive_info; / 用于存放硬盤參數(shù)表信息。103104 void main(void) /* this really is void, no error here. */105 /* the startup routine assumes (well, .) this */* 這里的確是void,并沒錯(cuò)。在startup 程序(head.s)中就是這樣假設(shè)的*/

19、 參見head.s 程序第136 行開頭的幾行代碼。106 /*107 * interrupts are still disabled. do necessary setups, then108 * enable them 109 */* 此時(shí)中斷仍被禁止著,做完必要的設(shè)置后就將其開啟。*/ 下面這段代碼用于保存:/ 根設(shè)備號(hào) .root_dev; 高速緩存末端地址.buffer_memory_end;/ 機(jī)器內(nèi)存數(shù).memory_end;主內(nèi)存開頭地址 .main_memory_start;110 root_dev = orig_root_dev; / root_dev 定義在fs/supe

20、r.c,29 行。111 drive_info = drive_info; / 復(fù)制0x90080 處的硬盤參數(shù)表。112 memory_end = (120) + (ext_mem_k10); / 內(nèi)存大小=1mb 字節(jié)+擴(kuò)展內(nèi)存(k)*1024 字節(jié)。113 memory_end = 0xfffff000; / 忽視不到4kb(1 頁)的內(nèi)存數(shù)。114 if (memory_end 16*1024*1024) / 假如內(nèi)存超過16mb,則按16mb 計(jì)。115 memory_end = 16*1024*1024;116 if (memory_end 12*1024*1024) / 假如內(nèi)存

21、12mb,則設(shè)置緩沖區(qū)末端=4mb117 buffer_memory_end = 4*1024*1024;118 else if (memory_end 6*1024*1024) / 否則假如內(nèi)存6mb,則設(shè)置緩沖區(qū)末端=2mb119 buffer_memory_end = 2*1024*1024;120 else121 buffer_memory_end = 1*1024*1024;/ 否則則設(shè)置緩沖區(qū)末端=1mb122 main_memory_start = buffer_memory_end; / 主內(nèi)存起始位置=緩沖區(qū)末端;/ 假如定義了內(nèi)存虛擬盤,則初始化虛擬盤。此時(shí)主內(nèi)存將削減。參

22、見kernel/blk_drv/ramdisk.c。123 #ifdef ramdisk124 main_memory_start += rd_init(main_memory_start, ramdisk*1024);125 #endif/ 以下是內(nèi)核進(jìn)行全部方面的初始化工作。閱讀時(shí)最好跟著調(diào)用的程序深化進(jìn)去看,若實(shí)在看/ 不下去了,就先放一放,連續(xù)看下一個(gè)初始化調(diào)用 - 這是閱歷之談.。126 mem_init(main_memory_start,memory_end);127 trap_init(); / 陷阱門(硬件中斷向量)初始化。(kernel/traps.c,181)128 bl

23、k_dev_init(); / 塊設(shè)備初始化。 (kernel/blk_drv/ll_rw_blk.c,157)129 chr_dev_init(); / 字符設(shè)備初始化。 (kernel/chr_drv/tty_io.c,347)130 tty_init(); / tty 初始化。 (kernel/chr_drv/tty_io.c,105)131 time_init(); / 設(shè)置開機(jī)啟動(dòng)時(shí)間.startup_time(見76 行)。132 sched_init(); / 調(diào)度程序初始化(加載了任務(wù)0 的tr,ldtr)(kernel/sched.c,385)133 buffer_init(

24、buffer_memory_end); / 緩沖管理初始化,建內(nèi)存鏈表等。(fs/buffer.c,348)134 hd_init(); / 硬盤初始化。 (kernel/blk_drv/hd.c,343)135 floppy_init(); / 軟驅(qū)初始化。 (kernel/blk_drv/floppy.c,457)136 sti(); / 全部初始化工作都做完了,開啟中斷。/ 下面過程通過在堆棧中設(shè)置的參數(shù),利用中斷返回指令啟動(dòng)任務(wù)0 執(zhí)行。137 move_to_user_mode(); / 移到用戶模式下執(zhí)行。(include/asm/system.h,第1 行)138 if (!fo

25、rk() /* we count on this going ok */139 init(); / 在新建的子進(jìn)程(任務(wù)1)中執(zhí)行。140 / 下面代碼開頭以任務(wù)0 的身份運(yùn)行。141 /*142 * note! for any other task 'pause()' would mean we have to get a143 * signal to awaken, but task0 is the sole exception (see 's chedule()') 144 * as task 0 gets activated at every idle

26、moment (when no other tasks145 * can run). for task0 'pause()' just means we go check if some other146 * task can run, and if not we return here.147 */* 留意! 對(duì)于任何其它的任務(wù),'pause()'將意味著我們必需等待收到一個(gè)信號(hào)才會(huì)返* 回就緒運(yùn)行態(tài),但任務(wù)0(task0)是唯一的例外狀況(參見'schedule()'),由于任務(wù)0 在* 任何空閑時(shí)間里都會(huì)被激活(當(dāng)沒有其它任務(wù)在運(yùn)行時(shí)),因

27、此對(duì)于任務(wù)0'pause()'僅意味著* 我們返回來查看是否有其它任務(wù)可以運(yùn)行,假如沒有的話我們就回到這里,始終循環(huán)執(zhí)行'pause()'。*/ pause()系統(tǒng)調(diào)用(kernel/sched.c,144)會(huì)把任務(wù)0 轉(zhuǎn)換成可中斷等待狀態(tài),再執(zhí)行調(diào)度函數(shù)。/ 但是調(diào)度函數(shù)只要發(fā)覺系統(tǒng)中沒有其它任務(wù)可以運(yùn)行時(shí)就會(huì)切換到任務(wù)0,而不依靠于任務(wù)0 的/ 狀態(tài)。148 for(;) pause();149 150151 static int printf(const char *fmt, .)/ 產(chǎn)生格式化信息并輸出到標(biāo)準(zhǔn)輸出設(shè)備stdout(1),這里是指屏幕上顯示

28、。參數(shù)'*fmt'指定輸出將/ 采納的格式,參見各種標(biāo)準(zhǔn)c 語言書籍。該子程序正好是vsprintf 如何使用的一個(gè)例子。/ 該程序使用vsprintf()將格式化的字符串放入printbuf 緩沖區(qū),然后用write()將緩沖區(qū)的內(nèi)容/ 輸出到標(biāo)準(zhǔn)設(shè)備(1-stdout)。vsprintf()函數(shù)的實(shí)現(xiàn)見kernel/vsprintf.c。152 153 va_list args;154 int i;155156 va_start(args, fmt);157 write(1,printbuf,i=vsprintf(printbuf, fmt, args);158 va_en

29、d(args);159 return i;160 161162 static char * argv_rc = /bin/sh, null ; / 調(diào)用執(zhí)行程序時(shí)參數(shù)的字符串?dāng)?shù)組。163 static char * envp_rc = home=/, null ; / 調(diào)用執(zhí)行程序時(shí)的環(huán)境字符串?dāng)?shù)組。164165 static char * argv = -/bin/sh,null ; / 同上。166 static char * envp = home=/usr/root, null ;/ 上面165 行中argv0中的字符“-”是傳遞給shell 程序sh 的一個(gè)標(biāo)志。通過識(shí)別該標(biāo)志,sh

30、/ 程序會(huì)作為登錄shell 執(zhí)行。其執(zhí)行過程與在shell 提示符下執(zhí)行sh 不太一樣。167/ 在main()中已經(jīng)進(jìn)行了系統(tǒng)初始化,包括內(nèi)存管理、各種硬件設(shè)備和驅(qū)動(dòng)程序。init()函數(shù)運(yùn)行在/ 任務(wù)0 第1 次創(chuàng)建的子進(jìn)程(任務(wù)1)中。它首先對(duì)第一個(gè)將要執(zhí)行的程序(shell)的環(huán)境進(jìn)行/ 初始化,然后加載該程序并執(zhí)行之。168 void init(void)169 170 int pid,i;171/ 這是一個(gè)系統(tǒng)調(diào)用。用于讀取硬盤參數(shù)包括分區(qū)表信息并加載虛擬盤(若存在的話)和安裝根文件/ 系統(tǒng)設(shè)備。該函數(shù)是用25 行上的宏定義的,對(duì)應(yīng)函數(shù)是sys_setup(),在kernel/b

31、lk_drv/hd.c,71行。172 setup(void *) drive_info);/ 下面以讀寫訪問方式打開設(shè)備“/dev/tty0”,它對(duì)應(yīng)終端掌握臺(tái)。/ 由于這是第一次打開文件操作 ,因此產(chǎn)生的文件句柄號(hào)(文件描述符)確定是0。該句柄是unix 類 / 操作系統(tǒng)默認(rèn)的掌握臺(tái)標(biāo)準(zhǔn)輸入句柄stdin。這里把它以讀和寫的方式打開是為了復(fù)制產(chǎn)生標(biāo)準(zhǔn)/ 輸出(寫)句柄stdout 和標(biāo)準(zhǔn)出錯(cuò)輸出句柄stderr。173 (void) open(/dev/tty0,o_rdwr,0);174 (void) dup(0); / 復(fù)制句柄,產(chǎn)生句柄1 號(hào) - stdout 標(biāo)準(zhǔn)輸出設(shè)備。175

32、(void) dup(0); / 復(fù)制句柄,產(chǎn)生句柄2 號(hào) - stderr 標(biāo)準(zhǔn)出錯(cuò)輸出設(shè)備。/ 下面打印緩沖區(qū)塊數(shù)和總字節(jié)數(shù),每塊1024 字節(jié),以及主內(nèi)存區(qū)空閑內(nèi)存字節(jié)數(shù)。176 printf(%d buffers = %d bytes buffer spacenr,nr_buffers,177 nr_buffers*block_size);178 printf(free mem: %d bytesnr,memory_end-main_memory_start);/ 下面fork()用于創(chuàng)建一個(gè)子進(jìn)程(任務(wù)2)。對(duì)于被創(chuàng)建的子進(jìn)程,fork()將返回0 值,對(duì)于原進(jìn)程/ (父進(jìn)程)則返回

33、子進(jìn)程的進(jìn)程號(hào)pid。所以180-184 句是子進(jìn)程執(zhí)行的內(nèi)容。該子進(jìn)程關(guān)閉了句柄/ 0(stdin)、以只讀方式打開/etc/rc 文件,并使用execve()函數(shù)將進(jìn)程自身替換成/bin/sh 程序/ (即shell 程序),然后執(zhí)行/bin/sh 程序。所帶參數(shù)和環(huán)境變量分別由argv_rc 和envp_rc 數(shù)組/ 給出。關(guān)于execve()請(qǐng)參見fs/exec.c 程序,182 行。/ 函數(shù)_exit()退出時(shí)的出錯(cuò)碼1 操作未許可;2 - 文件或名目不存在。179 if (!(pid=fork() 180 close(0);181 if (open(/etc/rc,o_rdonly,0)182 _exit(1); / 假如打開文件失敗,則退出(lib/_exit.c,10)。183 execve(/bin/sh,argv_rc,envp_rc); / 替換成/bin/sh 程序并執(zhí)行。184 _exit(2); / 若execve()執(zhí)行失敗則退出。185 / 下面還是父進(jìn)程(1)執(zhí)行的語句

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論