版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、<p> 計(jì)算機(jī)科學(xué)與工程學(xué)院</p><p><b> 課程設(shè)計(jì)報(bào)告</b></p><p> 題目全稱:Linux內(nèi)核初起代碼分析 </p><p> 學(xué)生學(xué)號(hào): 姓名: </p><p> 指導(dǎo)老師:
2、 職稱: </p><p><b> 指導(dǎo)老師評(píng)語(yǔ):</b></p><p> 簽字: </p><p><b> 課程設(shè)計(jì)成績(jī):</b></p><p><b> 目錄</b></p><p&
3、gt;<b> 摘 要1</b></p><p> 第一章 引 言1</p><p> 1.1 問(wèn)題的提出1</p><p> 1.2任務(wù)與分析1</p><p> 第二章 代碼分析2</p><p> 2.1系統(tǒng)初始化過(guò)程流程2</p><p&g
4、t; 2.2 數(shù)據(jù)結(jié)構(gòu)2</p><p> 2.3常量和出錯(cuò)信息的意義4</p><p> 2.4調(diào)用關(guān)系圖4</p><p> 2.5各模塊/函數(shù)的功能及詳細(xì)框圖5</p><p> 2.5.1 static void time_init(void)分析6</p><p> 2.5.2 void
5、 main(void)分析6</p><p> 2.5.3 pause()分析8</p><p> 2.5.4 static int printf(const char *fmt, ...)分析8</p><p> 2.5.5 void init(void)分析9</p><p> 第三章 內(nèi)核調(diào)試12</p>
6、<p> 3.1 運(yùn)行環(huán)境12</p><p> 3.2 編譯內(nèi)核過(guò)程12</p><p> 第四章 總結(jié)與體會(huì)15</p><p><b> 致 謝16</b></p><p><b> 參考文獻(xiàn)17</b></p><p><b&g
7、t; 摘 要</b></p><p> 隨著計(jì)算機(jī)的普及,計(jì)算機(jī)發(fā)揮著越來(lái)越重要的作用,計(jì)算機(jī)的使用也越來(lái)越普遍,所以讓更多的人能夠更好的使用和掌握一些計(jì)算機(jī)方法顯得十分重要。充分發(fā)揮計(jì)算機(jī)的作用也顯得十分重要。操作系統(tǒng)應(yīng)運(yùn)而生。操作系統(tǒng)是一種軟件,用來(lái)幫助其他的程序控制計(jì)算機(jī)并和用戶進(jìn)行交互。因而,對(duì)操作系統(tǒng)的研究是很有必要的。操作系統(tǒng)包含了多個(gè)部分或者組件,最核心的部分是內(nèi)核。其他的部分用
8、來(lái)幫助內(nèi)核完成計(jì)算機(jī)資源的管理和應(yīng)用程序的控制。Linux操作系統(tǒng)是使用很廣泛的,高質(zhì)量的一個(gè)操作系統(tǒng)。此次起始代碼分析,我分析了init/main.c文件中的main()、init()以及編譯內(nèi)核代碼。main()中主要是關(guān)于起始的調(diào)用和設(shè)備和系統(tǒng)信息初始化,以及創(chuàng)建進(jìn)程。此時(shí)中斷仍被禁止著,做完必要的設(shè)置后就將其開啟init()是創(chuàng)建進(jìn)程,并檢測(cè)是否出錯(cuò),出錯(cuò)則再次創(chuàng)建執(zhí)行并打印出出錯(cuò)信息。init()函數(shù)運(yùn)行在任務(wù)0 第1 次創(chuàng)建
9、的子進(jìn)程(任務(wù)1)中。它首先對(duì)第一個(gè)將要執(zhí)行的程序(shell)的環(huán)境進(jìn)行初始化,然后加載該程序并執(zhí)行之。對(duì)Linux 初起代碼的分析有助于了解操作系統(tǒng)的啟動(dòng),可以更好地理解和認(rèn)識(shí)操作系統(tǒng)是如何管理計(jì)算機(jī)</p><p> 關(guān)鍵詞:操作系統(tǒng);Linux;初起代碼</p><p><b> 第一章 引 言 </b></p><p> 1.
10、1 問(wèn)題的提出 </p><p> 操作系統(tǒng)是一種軟件,用來(lái)幫助其他的程序控制計(jì)算機(jī)并和用戶進(jìn)行交互。操作系統(tǒng)包含了眾多程序用來(lái)控制計(jì)算機(jī)的核心功能,并且操作系統(tǒng)是鏈接用戶和計(jì)算機(jī)硬件的橋梁,便于人們有效管理。盡管在過(guò)去操作系統(tǒng)取得了長(zhǎng)足的進(jìn)步,但是基本的目標(biāo)并未改變:通過(guò)使用操作系統(tǒng)來(lái)處理公共任務(wù),程序員便可以更容易地編寫應(yīng)用程序。</p><p> 應(yīng)用程序是一種軟件,用來(lái)向計(jì)算機(jī)
11、的用戶提供某種服務(wù),而不僅僅是控制計(jì)算機(jī)硬件。盡管在外觀上和功能上有所不同,但是所有的操作系統(tǒng)都具有一些相同之處:初始化計(jì)算機(jī)硬件,以便操作系統(tǒng)和其他持續(xù)可以正常工作;為使用操作系統(tǒng)的程序分配系統(tǒng)資源,如內(nèi)存和處理時(shí)間;跟蹤調(diào)試運(yùn)行的多個(gè)程序;為所有使用系統(tǒng)設(shè)備的程序提供規(guī)范的訪問(wèn)接口。</p><p> 操作系統(tǒng)包含了多個(gè)部分或者組件,最核心的部分是內(nèi)核。其他的部分用來(lái)幫助內(nèi)核完成計(jì)算機(jī)資源的管理和應(yīng)用程序的
12、控制。操作系統(tǒng)控制了計(jì)算機(jī)上運(yùn)行的各種應(yīng)用程序。沒(méi)有操作系統(tǒng)各類函數(shù)的調(diào)用,應(yīng)用程序就無(wú)法執(zhí)行。因而,對(duì)操作系統(tǒng)的研究是很有必要的。 Linux操作系統(tǒng)是使用很廣泛的,高質(zhì)量的一個(gè)操作系統(tǒng),而且作為一個(gè)開源的系統(tǒng),可以很方便的查看起代碼并進(jìn)行分析,有利于更好的認(rèn)識(shí)和了解操作系統(tǒng)。此次對(duì)Linux 初起代碼的分析有助于了解操作系統(tǒng)的啟動(dòng),可以更好地理解和認(rèn)識(shí)操作系統(tǒng)是如何管理計(jì)算機(jī)資源的。</p><p><
13、b> 1.2任務(wù)與分析 </b></p><p> 本課題主要的目的是了解一個(gè)操作系統(tǒng)的初起過(guò)程。根據(jù)操作系統(tǒng)的基礎(chǔ)知識(shí),分析init/main.c中關(guān)于系統(tǒng)初起的相關(guān)代碼,了解一個(gè)操作系統(tǒng)的初起過(guò)程,得到相關(guān)的框圖,寫出設(shè)計(jì)說(shuō)明書。</p><p> 代碼分析結(jié)果, 包括但不限于:</p><p><b> 數(shù)據(jù)結(jié)構(gòu)</b
14、></p><p> 常量和出錯(cuò)信息的意義</p><p><b> 調(diào)用關(guān)系圖</b></p><p> 各模塊/函數(shù)詳細(xì)框圖</p><p><b> 分析思路:</b></p><p> 了解基礎(chǔ)知識(shí),找到相關(guān)的源碼;</p><p&
15、gt; 對(duì)代碼充分閱讀,先得到單個(gè)函數(shù)的數(shù)據(jù)結(jié)構(gòu)和框圖;</p><p> 將多個(gè)函數(shù)的框圖匯總,繪出整體的框圖;</p><p><b> 使用的源代碼是</b></p><p> Linux/init/main.c</p><p> (C) 1991 Linus Torvalds</p>&l
16、t;p><b> 第二章 代碼分析 </b></p><p> 2.1系統(tǒng)初始化過(guò)程流程</p><p> 系統(tǒng)整個(gè)初始化過(guò)程見(jiàn)圖2.1所示:</p><p> 圖2.1 內(nèi)核初始化程序流程示意圖</p><p><b> 2.2 數(shù)據(jù)結(jié)構(gòu)</b></p><p&
17、gt;<b> 時(shí)間結(jié)構(gòu):</b></p><p> #define CLOCKS_PER_SEC 100/* 系統(tǒng)時(shí)鐘滴答頻率,100HZ */</p><p> typedef long clock_t;/* 從進(jìn)程開始系統(tǒng)經(jīng)過(guò)的時(shí)鐘滴答數(shù) */</p><p><b> struct tm</b><
18、/p><p><b> {</b></p><p> int tm_sec;/* 秒數(shù) [0,59] */</p><p> int tm_min;/* 分鐘數(shù) [0,59] */</p><p> int tm_hour;/* 小時(shí)數(shù) [0,59] */</p><p> int t
19、m_mday;/* 1 個(gè)月的天數(shù) [0,31] */</p><p> int tm_mon;/* 1 年中月份 [0,11] */</p><p> int tm_year;/* 從1900 年開始的年數(shù) */</p><p> int tm_wday;/* 1 星期中的某天 [0,6](星期天=0) */</p><p>
20、 int tm_yday;/* 1 年中的某天 [0,365] */</p><p> int tm_isdst;/* 夏令時(shí)標(biāo)志 */</p><p><b> };</b></p><p> 存放硬盤參數(shù)表信息:</p><p> struct drive_info</p><p&g
21、t;<b> {</b></p><p> char dummy[32];</p><p> }drive_info;/* 用于存放硬盤參數(shù)表信息 */</p><p> tty 等待隊(duì)列數(shù)據(jù)結(jié)構(gòu)和tty 數(shù)據(jù)結(jié)構(gòu):</p><p> struct tty_queue</p><p>
22、<b> {</b></p><p> unsigned long data;/* 等待隊(duì)列緩沖區(qū)中當(dāng)前數(shù)據(jù)指針字符數(shù) */</p><p> unsigned long head;/* 緩沖區(qū)中數(shù)據(jù)頭指針 */</p><p> unsigned long tail;/* 緩沖區(qū)中數(shù)據(jù)尾指針 */</p><
23、p> struct task_struct *proc_list; /* 等待進(jìn)程列表 */</p><p> char buf[TTY_BUF_SIZE];/* 隊(duì)列的緩沖區(qū) */</p><p><b> };</b></p><p> struct tty_struct /* tty 數(shù)據(jù)結(jié)構(gòu) */<
24、/p><p><b> {</b></p><p> struct termios termios;/* 終端io 屬性和控制字符數(shù)據(jù)結(jié)構(gòu) */</p><p> int pgrp;/* 所屬進(jìn)程組 */</p><p> int stopped;/* 停止標(biāo)志 */</p><p>
25、 void (*write) (struct tty_struct * tty); /* tty 寫函數(shù)指針 */</p><p> struct tty_queue read_q;/* tty 讀隊(duì)列 */</p><p> struct tty_queue write_q; /* tty 寫隊(duì)列 */</p><p> struct tty_qu
26、eue secondary; /* tty 輔助隊(duì)列(存放規(guī)范模式字符序列) */</p><p> };/* 可稱為規(guī)范(熟)模式隊(duì)列 */</p><p> 請(qǐng)求隊(duì)列中項(xiàng)的結(jié)構(gòu)和塊設(shè)備結(jié)構(gòu):</p><p> struct request</p><p> /* 請(qǐng)求隊(duì)列中項(xiàng)的結(jié)構(gòu)。其中如果dev=-1,則表示該項(xiàng)沒(méi)有被使用
27、 */</p><p><b> {</b></p><p> int dev;/* 使用的設(shè)備號(hào) */</p><p> int cmd;/* 命令(READ或 WRITE) */</p><p> int errors;/* 操作時(shí)產(chǎn)生的錯(cuò)誤次數(shù) */</p><p> uns
28、igned long sector;/* 起始扇區(qū)(1塊=2扇區(qū)) */</p><p> unsigned long nr_sectors; /* 讀/寫扇區(qū)數(shù) */</p><p> char *buffer;/* 數(shù)據(jù)緩沖區(qū) */</p><p> struct task_struct *waiting; /* 任務(wù)等待操作執(zhí)行完成的地方 */
29、</p><p> struct buffer_head *bh;/* 緩沖區(qū)頭指針(include/Linux/fs.h,68) */</p><p> struct request *next;/* 指向下一請(qǐng)求項(xiàng) */</p><p><b> };</b></p><p> struct blk_de
30、v_struct /* 塊設(shè)備結(jié)構(gòu) */</p><p> { void (*request_fn) (void); /* 請(qǐng)求操作的函數(shù)指針 */</p><p> struct request *current_request; /* 請(qǐng)求信息結(jié)構(gòu) */</p><p><b> };</b><
31、/p><p> 2.3常量和出錯(cuò)信息的意義</p><p> 定義系統(tǒng)調(diào)用嵌入式匯編宏函數(shù)。不帶參數(shù)的系統(tǒng)調(diào)用宏函數(shù)。type name(void)。%0 - eax(__res),%1 - eax(__NR_##name)。其中name 是系統(tǒng)調(diào)用的名稱,與 __NR_ 組合形成上面的系統(tǒng)調(diào)用符號(hào)常數(shù),從而用來(lái)對(duì)系統(tǒng)調(diào)用表中函數(shù)指針尋址。返回:如果返回值大于等于0,則返回該值,否則置出錯(cuò)
32、號(hào)errno,并返回-1。</p><p> #define _syscall0(type,name) </p><p> type name(void) </p><p><b> { </b></p><p> long __res; </p><p> __asm__ volati
33、le ( "int $0x80" \ /* 調(diào)用系統(tǒng)中斷0x80 */</p><p> :"=a" (__res) \/* 返回值eax(__res) */</p><p> :"" (__NR_</p><p> ##name)); \/* 輸入為系統(tǒng)中斷調(diào)用號(hào)_
34、_NR_name */</p><p> if (__res >= 0) \/* 如果返回值>=0,則直接返回該值 */</p><p> return (type) __res; errno = -__res; \ /* 否則置出錯(cuò)號(hào),并返回-1 */</p><p> return -1;}</p><p
35、> /* 有1 個(gè)參數(shù)的系統(tǒng)調(diào)用宏函數(shù)。type name(atype a) */</p><p> /* %0 - eax(__res),%1 - eax(__NR_name),%2 - ebx(a) */</p><p> #define _syscall1(type,name,atype,a) \</p><p> type name(atype
36、 a) </p><p><b> { </b></p><p> long __res; </p><p> __asm__ volatile ( "int $0x80" : "=a" (__res) : "" (__NR_##name), "b" ((lo
37、ng)(a))); </p><p> if (__res >= 0) </p><p> return (type) __res; </p><p> errno = -__res; </p><p> return -1; }</p><p> extern int errno;/* 出錯(cuò)號(hào),全局
38、變量 */</p><p> static inline _syscall0(int,fork)</p><p> /*這是unistd.h 中的內(nèi)嵌宏代碼。以嵌入?yún)R編的形式調(diào)用Linux 的系統(tǒng)調(diào)用中斷0x80。該中斷是所有系統(tǒng)調(diào)用的入口。該條語(yǔ)句實(shí)際上是int fork()創(chuàng)建進(jìn)程系統(tǒng)調(diào)用。syscall0 名稱中最后的0 表示無(wú)參數(shù),1 表示1 個(gè)參數(shù) */</p>
39、<p> static inline _syscall0(int,pause) </p><p> /* int pause()系統(tǒng)調(diào)用:暫停進(jìn)程的執(zhí)行,直到收到一個(gè)信號(hào) */</p><p> static inline _syscall1(int,setup,void *,BIOS)</p><p> /* int setup(void *
40、BIOS)系統(tǒng)調(diào)用,僅用于Linux 初始化(僅在這個(gè)程序中被調(diào)用)*/</p><p> static inline _syscall0(int,sync) </p><p> /* int sync()系統(tǒng)調(diào)用更新文件系統(tǒng) */</p><p><b> 2.4調(diào)用關(guān)系圖</b></p><p> 在內(nèi)核源代
41、碼的init/目錄中只有一個(gè)main.c 文件。系統(tǒng)在執(zhí)行完boot/目錄中的head.s 程序后就會(huì)將執(zhí)行權(quán)交給main.c。該程序雖然不長(zhǎng),但卻包括了內(nèi)核初始化的所有工作。</p><p> main.c 程序首先利用前面setup.s 程序取得的系統(tǒng)參數(shù)設(shè)置系統(tǒng)的根文件設(shè)備號(hào)以及一些內(nèi)存全局變量。這些內(nèi)存變量指明了主內(nèi)存的開始地址、系統(tǒng)所擁有的內(nèi)存容量和作為高速緩沖區(qū)內(nèi)存的末端地址。如果還定義了虛擬盤(R
42、AMDISK),則主內(nèi)存將適當(dāng)減少。整個(gè)內(nèi)存的映像示意圖見(jiàn)圖3.1 所示。</p><p> 圖2.1 系統(tǒng)中內(nèi)存功能劃分示意圖</p><p> 圖中,高速緩沖部分還要扣除被顯存和ROM BIOS 占用的部分。高速緩沖區(qū)是用于磁盤等塊設(shè)備臨時(shí)存放數(shù)據(jù)的地方,以1K(1024)字節(jié)為一個(gè)數(shù)據(jù)塊單位。主內(nèi)存區(qū)域的內(nèi)存是由內(nèi)存管理模塊mm通過(guò)分頁(yè)機(jī)制進(jìn)行管理分配,以4K 字節(jié)為一個(gè)內(nèi)存頁(yè)單
43、位。內(nèi)核程序可以自由訪問(wèn)高速緩沖中的數(shù)據(jù),但需要通過(guò)mm 才能使用分配到的內(nèi)存頁(yè)面。</p><p> 然后,內(nèi)核進(jìn)行所有方面的硬件初始化工作。包括陷阱門、塊設(shè)備、字符設(shè)備和tty,包括人工設(shè)置第一個(gè)任務(wù)(task 0)。待所有初始化工作完成后就設(shè)置中斷允許標(biāo)志以開啟中斷,main()也切換到了任務(wù)0 中運(yùn)行。</p><p> 在整個(gè)內(nèi)核完成初始化后,內(nèi)核將執(zhí)行權(quán)切換到了用戶模式(任
44、務(wù)0),也即CPU 從0 特權(quán)級(jí)切換到了第3 特權(quán)級(jí)。此時(shí)main.c 的主程序就工作在任務(wù)0 中。然后系統(tǒng)第一次調(diào)用進(jìn)程創(chuàng)建函數(shù)fork(),創(chuàng)建出一個(gè)用于運(yùn)行init()的子進(jìn)程。</p><p> 2.5各模塊/函數(shù)的功能及詳細(xì)框圖</p><p> 該程序首先確定如何分配使用系統(tǒng)物理內(nèi)存,然后調(diào)用內(nèi)核各部分的初始化函數(shù)分別對(duì)內(nèi)存管理、中斷處理、塊設(shè)備和字符設(shè)備、進(jìn)程管理以及硬盤
45、和軟盤硬件進(jìn)行初始化處理。在完成了這些操作之后,系統(tǒng)各部分已處于可運(yùn)行狀態(tài)。此后程序把自己“手工”移動(dòng)到任務(wù)0(進(jìn)程0)中運(yùn)行,并使用fork()調(diào)用首次創(chuàng)建出進(jìn)程1(init 進(jìn)程)。在init進(jìn)程中程序?qū)⒗^續(xù)進(jìn)行應(yīng)用環(huán)境的初始化并執(zhí)行shell 登錄程序。而原進(jìn)程0則會(huì)在系統(tǒng)空閑時(shí)被調(diào)度執(zhí)行,此時(shí)任務(wù)0僅執(zhí)行pause()系統(tǒng)調(diào)用,并又會(huì)調(diào)用調(diào)度函數(shù)。</p><p> 在init 進(jìn)程中,如果終端環(huán)境建立
46、成功,則會(huì)再生成一個(gè)子進(jìn)程(進(jìn)程2),用于運(yùn)行shell 程序/bin/sh。若該子進(jìn)程退出,則父進(jìn)程進(jìn)入一個(gè)死循環(huán)內(nèi),繼續(xù)生成子進(jìn)程,并在此子進(jìn)程中再次執(zhí)行shell 程序/bin/sh,而父進(jìn)程則繼續(xù)等待。</p><p> 由于創(chuàng)建新進(jìn)程的過(guò)程是通過(guò)完全復(fù)制父進(jìn)程代碼段和數(shù)據(jù)段的方式實(shí)現(xiàn)的,因此在首次使用fork()創(chuàng)建新進(jìn)程init 時(shí),為了確保新進(jìn)程用戶態(tài)堆棧沒(méi)有進(jìn)程0 的多余信息,要求進(jìn)程0 在創(chuàng)建
47、首個(gè)新進(jìn)程之前不要使用用戶態(tài)堆棧,也即要求任務(wù)0 不要調(diào)用函數(shù)。因此在main.c 主程序移動(dòng)到任務(wù)0 執(zhí)行后,任務(wù)0 中的代碼fork()不能以函數(shù)形式進(jìn)行調(diào)用。程序中實(shí)現(xiàn)的方法是采用gcc 函數(shù)內(nèi)嵌的形式來(lái)執(zhí)行這個(gè)系統(tǒng)調(diào)用。</p><p> 通過(guò)申明一個(gè)內(nèi)嵌(inline)函數(shù),可以讓gcc 把函數(shù)的代碼集成到調(diào)用它的代碼中。這會(huì)提高代碼執(zhí)行的速度,因?yàn)槭∪チ撕瘮?shù)調(diào)用的開銷。另外,如果任何一個(gè)實(shí)際參數(shù)是一
48、個(gè)常量,那么在編譯時(shí)這些已知值就可能使得無(wú)需把內(nèi)嵌函數(shù)的所有代碼都包括進(jìn)來(lái)而讓代碼也得到簡(jiǎn)化。</p><p> 另外,任務(wù)0 中的pause()也需要使用函數(shù)內(nèi)嵌形式來(lái)定義。如果調(diào)度程序首先執(zhí)行新創(chuàng)建的子進(jìn)程init,那么pause()采用函數(shù)調(diào)用形式不會(huì)有什么問(wèn)題。但是內(nèi)核調(diào)度程序執(zhí)行父進(jìn)程(進(jìn)程0)和子進(jìn)程init 的次序是隨機(jī)的,在創(chuàng)建了init 后有可能首先會(huì)調(diào)度進(jìn)程0 執(zhí)行。因此pause()也必須
49、采用宏定義來(lái)實(shí)現(xiàn)。</p><p> 對(duì)于Linux 來(lái)說(shuō),所有任務(wù)都是在用戶模式運(yùn)行的,包括很多系統(tǒng)應(yīng)用程序,如shell 程序、網(wǎng)絡(luò)子系統(tǒng)程序等。內(nèi)核源代碼lib/目錄下的庫(kù)文件就是專門為這里新創(chuàng)建的進(jìn)程提供支持函數(shù)的。</p><p> 2.5.1 static void time_init(void)分析</p><p> 該子程用于讀取取CMOS 時(shí)
50、鐘,并設(shè)置開機(jī)時(shí)間startup_time(秒)。</p><p> struct tm time; </p><p> /* 時(shí)間結(jié)構(gòu)tm 定義在include/time.h 中 */</p><p><b> do {</b></p><p> time.tm_sec = CMOS_READ(0);
51、 /* 當(dāng)前時(shí)間秒值(均是BCD 碼值)*/</p><p> time.tm_min = CMOS_READ(2); /* 當(dāng)前分鐘值 */</p><p> time.tm_hour = CMOS_READ(4); /* 當(dāng)前小時(shí)值 */</p><p> time.tm_mday = CMOS_R
52、EAD(7); /* 一月中的當(dāng)天日期 */</p><p> time.tm_mon = CMOS_READ(8); /* 當(dāng)前月份(1—12)*/</p><p> time.tm_year = CMOS_READ(9); /* 當(dāng)前年份 */</p><p> } while (time.t
53、m_sec != CMOS_READ(0));</p><p> CMOS 的訪問(wèn)速度很慢。為了減小時(shí)間誤差,在讀取了下面循環(huán)中所有數(shù)值后,若此時(shí)CMOS 中秒值發(fā)生了變化,那么就重新讀取所有值。</p><p> BCD_TO_BIN(time.tm_sec); /* 轉(zhuǎn)換成二進(jìn)制數(shù)值 */</p><p> BCD_TO_BIN
54、(time.tm_min);</p><p> BCD_TO_BIN(time.tm_hour);</p><p> BCD_TO_BIN(time.tm_mday);</p><p> BCD_TO_BIN(time.tm_mon);</p><p> BCD_TO_BIN(time.tm_year);</p><
55、;p> time.tm_mon--; /* tm_mon 中月份范圍是0—11 */</p><p> startup_time = kernel_mktime(&time); </p><p> /* 調(diào)用kernel/mktime.c 中函數(shù),計(jì)算從1970年1月1日0時(shí)起到開機(jī)當(dāng)日經(jīng)過(guò)的秒數(shù),作為開機(jī)時(shí)間 */&l
56、t;/p><p> 2.5.2 void main(void)分析</p><p> main()函數(shù)中完成啟動(dòng)時(shí)對(duì)設(shè)備內(nèi)核初始化,以及創(chuàng)建進(jìn)程。此時(shí)中斷仍被禁止著,做完必要的設(shè)置后就將其開啟。下面這段代碼用于保存:根設(shè)備號(hào):ROOT_DEV; 高速緩存末端地址:buffer_memory_end;機(jī)器內(nèi)存:memory_end;主內(nèi)存開始地址 :main_memory_start;<
57、;/p><p> ROOT_DEV = ORIG_ROOT_DEV; /* ROOT_DEV 定義在fs/super.c */</p><p> drive_info = DRIVE_INFO; /* 復(fù)制0x90080 處的硬盤參數(shù)表 */</p><p> memory_end = (1<<20) + (E
58、XT_MEM_K<<10); </p><p> /* 內(nèi)存大小=1Mb 字節(jié)+擴(kuò)展內(nèi)存(k)*1024 字節(jié) */</p><p> memory_end &= 0xfffff000; /* 忽略不到4Kb(1 頁(yè))的內(nèi)存數(shù) */</p><p> if (memory_end > 16*1024*1024)
59、 /* 如果內(nèi)存超過(guò)16Mb,則按16Mb 計(jì) */</p><p> memory_end = 16*1024*1024;</p><p> if (memory_end > 12*1024*1024) /* 如果內(nèi)存>12Mb,則設(shè)置緩沖區(qū)末端=4Mb */</p><p> buffer_memory_end = 4*1024*
60、1024;</p><p> else if (memory_end > 6*1024*1024) /* 否則如果內(nèi)存>6Mb,則設(shè)置緩沖區(qū)末端=2Mb */</p><p> buffer_memory_end = 2*1024*1024;</p><p><b> else</b></p><p>
61、; buffer_memory_end = 1*1024*1024; /* 否則則設(shè)置緩沖區(qū)末端=1Mb */</p><p> main_memory_start = buffer_memory_end; /* 主內(nèi)存起始位置=緩沖區(qū)末端 */</p><p> /* 如果定義了內(nèi)存虛擬盤,則初始化虛擬盤。此時(shí)主內(nèi)存將減少。參見(jiàn)kernel/blk_drv/ramdisk.
62、c。*/</p><p> #ifdef RAMDISK</p><p> main_memory_start += rd_init(main_memory_start, RAMDISK*1024);</p><p><b> #endif</b></p><p> mem_init(main_memory_st
63、art,memory_end); /* 內(nèi)核進(jìn)行所有方面的初始化工作 */</p><p> trap_init(); /* 陷阱門(硬件中斷向量)初始化。(kernel/traps.c) */</p><p> blk_dev_init(); /* 塊設(shè)備初始化。 (kernel/blk_drv/ll_rw_b
64、lk.c)*/</p><p> chr_dev_init(); /* 字符設(shè)備初始化。 (kernel/chr_drv/tty_io.c)*/</p><p> tty_init(); /* tty 初始化。 (kernel/chr_drv/tty_io.c)*/</p><p> time
65、_init(); /* 設(shè)置開機(jī)啟動(dòng)時(shí)間:startup_time */</p><p> sched_init(); /* 調(diào)度程序初始化(加載了任務(wù)0 的tr,ldtr)(kernel/sched.c)*/</p><p> buffer_init(buffer_memory_end); /* 緩沖管理初始化,建內(nèi)存鏈表等。(f
66、s/buffer.c)*/</p><p> hd_init(); /* 硬盤初始化。 (kernel/blk_drv/hd.c)*/</p><p> floppy_init(); /* 軟驅(qū)初始化。 (kernel/blk_drv/floppy.c)*/</p><p> st
67、i(); /* 所有初始化工作都做完了,開啟中斷 */</p><p> /* 下面過(guò)程通過(guò)在堆棧中設(shè)置的參數(shù),利用中斷返回指令啟動(dòng)任務(wù)0 執(zhí)行 */</p><p> move_to_user_mode(); /* 移到用戶模式下執(zhí)行。(include/asm/system.h)*/</p><p> if
68、 (!fork()) { </p><p> init(); /* 在新建的子進(jìn)程(任務(wù)1)中執(zhí)行 */</p><p><b> }</b></p><p> main()流程圖如圖2.2:</p><p> 圖2.2 main()流程圖</p><p> 2.5.3 pause()分
69、析</p><p> 代碼開始以任務(wù)0 的身份運(yùn)行。對(duì)于任何其它的任務(wù),pause()將意味著我們必須等待收到一個(gè)信號(hào)才會(huì)返回就緒運(yùn)行態(tài),但任務(wù)0(task0)是唯一的例外情況,因?yàn)槿蝿?wù)0 在任何空閑時(shí)間里都會(huì)被激活(當(dāng)沒(méi)有其它任務(wù)在運(yùn)行時(shí)),因此對(duì)于任務(wù)0 pause()僅意味著我們返回來(lái)查看是否有其它任務(wù)可以運(yùn)行,如果沒(méi)有的話我們就回到這里,一直循環(huán)執(zhí)行pause()。</p><p&g
70、t; pause()系統(tǒng)調(diào)用(kernel/sched.c,144)會(huì)把任務(wù)0 轉(zhuǎn)換成可中斷等待狀態(tài),再執(zhí)行調(diào)度函數(shù)。但是調(diào)度函數(shù)只要發(fā)現(xiàn)系統(tǒng)中沒(méi)有其它任務(wù)可以運(yùn)行時(shí)就會(huì)切換到任務(wù)0,而不依賴于任務(wù)0 的狀態(tài)。</p><p> 2.5.4 static int printf(const char *fmt, ...)分析</p><p> 產(chǎn)生格式化信息并輸出到標(biāo)準(zhǔn)輸出設(shè)備stdo
71、ut(1),這里是指屏幕上顯示。參數(shù)'*fmt'指定輸出將采用的格式。該子程序正好是vsprintf 如何使用的一個(gè)例子。該程序使用vsprintf()將格式化的字符串放入printbuf 緩沖區(qū),然后用write()將緩沖區(qū)的內(nèi)容輸出到標(biāo)準(zhǔn)設(shè)備(1--stdout)。</p><p> static int printf(const char *fmt, ...)</p><
72、;p><b> {</b></p><p> va_list args;</p><p><b> int i;</b></p><p> va_start(args, fmt);</p><p> write(1,printbuf,i=vsprintf(printbuf, fmt,
73、 args));</p><p> va_end(args);</p><p><b> return i;</b></p><p><b> }</b></p><p> 2.5.5 void init(void)分析</p><p> argv[0]中的字符“-
74、”是傳遞給shell 程序sh 的一個(gè)標(biāo)志。通過(guò)識(shí)別該標(biāo)志,sh</p><p> 程序會(huì)作為登錄shell 執(zhí)行。其執(zhí)行過(guò)程與在shell 提示符下執(zhí)行sh 不太一樣。</p><p> static char * argv_rc[] = { "/bin/sh", NULL }; /* 調(diào)用執(zhí)行程序時(shí)參數(shù)的字符串?dāng)?shù)組 */</p><p
75、> static char * envp_rc[] = { "HOME=/", NULL }; /* 調(diào)用執(zhí)行程序時(shí)的環(huán)境字符串?dāng)?shù)組 */</p><p> static char * argv[] = { "-/bin/sh",NULL }; /* 同上 */</p><p> static char * envp[] =
76、 { "HOME=/usr/root", NULL }; </p><p> 在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í)行之。</p><p> setup((void *) &dri
77、ve_info);</p><p> /* 這是一個(gè)系統(tǒng)調(diào)用。用于讀取硬盤參數(shù)包括分區(qū)表信息并加載虛擬盤(若存在的話)和安裝根文件系統(tǒng)設(shè)備。該函數(shù)對(duì)應(yīng)函數(shù)是sys_setup() */</p><p> 然后以讀寫訪問(wèn)方式打開設(shè)備“/dev/tty0”,它對(duì)應(yīng)終端控制臺(tái)。由于這是第一次打開文件操作,因此產(chǎn)生的文件句柄號(hào)(文件描述符)肯定是0。該句柄是UNIX 類操作系統(tǒng)默認(rèn)的控制臺(tái)標(biāo)準(zhǔn)
78、輸入句柄stdin。這里把它以讀和寫的方式打開是為了復(fù)制產(chǎn)生標(biāo)準(zhǔn) 輸出(寫)句柄stdout 和標(biāo)準(zhǔn)出錯(cuò)輸出句柄stderr。</p><p> (void) open("/dev/tty0",O_RDWR,0);</p><p> (void) dup(0); /* 復(fù)制句柄,產(chǎn)生句柄1 號(hào) -- stdout 標(biāo)準(zhǔn)輸出設(shè)備 */</p&
79、gt;<p> (void) dup(0); /* 復(fù)制句柄,產(chǎn)生句柄2 號(hào) -- stderr 標(biāo)準(zhǔn)出錯(cuò)輸出設(shè)備 */</p><p> 打印緩沖區(qū)塊數(shù)和總字節(jié)數(shù),每塊1024 字節(jié),以及主內(nèi)存區(qū)空閑內(nèi)存字節(jié)數(shù)。</p><p> printf("%d buffers = %d bytes buffer space\n\r",N
80、R_BUFFERS,</p><p> NR_BUFFERS*BLOCK_SIZE);</p><p> printf("Free mem: %d bytes\n\r",memory_end-main_memory_start);</p><p> fork()用于創(chuàng)建一個(gè)子進(jìn)程(任務(wù)2)。對(duì)于被創(chuàng)建的子進(jìn)程,fork()將返回0 值,對(duì)于
81、原進(jìn)程(父進(jìn)程)則返回子進(jìn)程的進(jìn)程號(hào)pid。該子進(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ù)組給出。函數(shù)_exit()退出時(shí)的出錯(cuò)碼1 – 操作未許可;2 -- 文件或目錄不存在。</p><p> if (!(
82、pid=fork())) {</p><p><b> close(0);</b></p><p> if (open("/etc/rc",O_RDONLY,0))</p><p> _exit(1); /* 如果打開文件失敗,則退出(lib/_exit.c,10) */<
83、;/p><p> execve("/bin/sh",argv_rc,envp_rc); /* 替換成/bin/sh 程序并執(zhí)行 */</p><p> _exit(2); /* 若execve()執(zhí)行失敗則退出 */</p><p><b> }</b></p>&l
84、t;p> 下面還是父進(jìn)程(1)執(zhí)行的語(yǔ)句。wait()等待子進(jìn)程停止或終止,返回值應(yīng)是子進(jìn)程的進(jìn)程號(hào)(pid)。這三句的作用是父進(jìn)程等待子進(jìn)程的結(jié)束。&i 是存放返回狀態(tài)信息的位置。如果wait()返回值不等于子進(jìn)程號(hào),則繼續(xù)等待。</p><p> if (pid>0)</p><p> while (pid != wait(&i))</p>
85、<p><b> /* 空循環(huán) */</b></p><p> 如果執(zhí)行到這里,說(shuō)明剛創(chuàng)建的子進(jìn)程的執(zhí)行已停止或終止了。下面循環(huán)中首先再創(chuàng)建一個(gè)子進(jìn)程,如果出錯(cuò),則顯示“初始化程序創(chuàng)建子進(jìn)程失敗”信息并繼續(xù)執(zhí)行。對(duì)于所創(chuàng)建的子進(jìn)程將關(guān)閉所有以前還遺留的句柄(stdin, stdout, stderr),新創(chuàng)建一個(gè)會(huì)話并設(shè)置進(jìn)程組號(hào),然后重新打開/dev/tty0作為stdi
86、n,并復(fù)制成stdout 和stderr。再次執(zhí)行系統(tǒng)解釋程序/bin/sh。但這次執(zhí)行所選用的參數(shù)和環(huán)境數(shù)組另選了一套。然后父進(jìn)程再次運(yùn)行wait()等待。如果子進(jìn)程又停止了執(zhí)行,則在標(biāo)準(zhǔn)輸出上顯示出錯(cuò)信息“子進(jìn)程pid 停止了運(yùn)行,返回碼是i”,然后繼續(xù)重試下去,形成一個(gè)死循環(huán)。</p><p> while (1) {</p><p> if ((pid=fork())<0
87、) {</p><p> printf("Fork failed in init\r\n");</p><p><b> continue;</b></p><p><b> }</b></p><p> if (!pid) { /* 新的子進(jìn)程 *
88、/</p><p> close(0);close(1);close(2);</p><p> setsid(); /* 創(chuàng)建一新的會(huì)話 */</p><p> (void) open("/dev/tty0",O_RDWR,0);</p><p> (void) dup(0);</p&
89、gt;<p> (void) dup(0);</p><p> _exit(execve("/bin/sh",argv,envp));</p><p><b> }</b></p><p><b> while (1)</b></p><p> if (p
90、id == wait(&i))</p><p><b> break;</b></p><p> printf("\n\rchild %d died with code %04x\n\r",pid,i);</p><p> sync(); /* 同步操作,刷新緩沖區(qū) */</p&
91、gt;<p><b> }</b></p><p> _exit(0); /* 注意!是_exit(),不是exit() */</p><p> _exit()和exit()都用于正常終止一個(gè)函數(shù)。但_exit()直接是一個(gè)sys_exit 系統(tǒng)調(diào)用,而exit()則通常是普通函數(shù)庫(kù)中的一個(gè)函數(shù)。它會(huì)先執(zhí)行一些清除操作,例如調(diào)用執(zhí)行各終止處理程序、
92、關(guān)閉所有標(biāo)準(zhǔn)IO 等,然后調(diào)用sys_exit。</p><p> init()流程圖2.3:</p><p><b> 第三章 內(nèi)核調(diào)試</b></p><p><b> 3.1 運(yùn)行環(huán)境</b></p><p> 內(nèi)核編譯運(yùn)行于模擬Linux環(huán)境的Bochs-2.1.1中。</p&
93、gt;<p> 3.2 編譯內(nèi)核過(guò)程</p><p> 用Bochs運(yùn)行Linux0.11,開始如圖3.1:</p><p> 圖3.1 Bochs運(yùn)行Linux0.11</p><p> 進(jìn)入 /usr/src/Linux/init, 使用ls命令顯示當(dāng)前目錄文件,可以看到我們需要的main.c文件,如圖3.2:</p><
94、;p> 圖3.2 ls命令顯示當(dāng)前目錄文件</p><p> vi main.c可以編譯啟動(dòng)代碼,insert插入,Esc+:wq保存并退出,如圖3.3:</p><p> 圖3.3 vi編譯啟動(dòng)代碼</p><p> 返回Linux目錄,使用make clean清除源代碼生成的執(zhí)行文件和中間的目標(biāo)文件,如圖3.4:</p><p&
95、gt; 圖3.4 make clean</p><p> 然后使用make命令編譯生成新的內(nèi)核,如圖3.5:</p><p> 圖3.5 make命令編譯生成新的內(nèi)核</p><p> 然后修復(fù)grub引導(dǎo)(這里不再贅述),重啟后可看到多選菜單,默認(rèn)首選就是我修改main.c編譯的內(nèi)核,如圖3.6:</p><p> 圖3.6 新建
96、grub引導(dǎo)</p><p> 進(jìn)入后啟動(dòng)顯示信息。首先,顯示的是硬盤信息以及執(zhí)行起始程序(kernel()),由此可見(jiàn),啟動(dòng)時(shí)先要對(duì)硬件初始化和起始程序位置。然后顯示硬盤是否有錯(cuò)誤信息以及磁盤使用情況。因?yàn)長(zhǎng)INUX編程有嚴(yán)格的限制,我試著將printf()定義移到main()之前,修改main()的內(nèi)容并使之顯示,沒(méi)有成功,我就只修改了init()里的內(nèi)容??梢钥吹斤@示打印出磁盤信息,然后用fork()創(chuàng)建
97、一個(gè)進(jìn)程,然后打開/etc/rc/、執(zhí)行bin/sh,由于沒(méi)有出錯(cuò),就沒(méi)有跳轉(zhuǎn)到出錯(cuò)的死循環(huán)中,沒(méi)有錯(cuò)誤信息顯示,最后打印出創(chuàng)建進(jìn)程成功。系統(tǒng)初始化完成,返回值OK。由此可以驗(yàn)證我們對(duì)初起代碼main.c分析的正確性。如圖3.7:</p><p><b> 圖3.7</b></p><p><b> 第四章 總結(jié)與體會(huì)</b></p&g
98、t;<p> 該程序首先確定如何分配使用系統(tǒng)物理內(nèi)存,然后調(diào)用內(nèi)核各部分的初始化函數(shù)分別對(duì)內(nèi)存管理、中斷處理、塊設(shè)備和字符設(shè)備、進(jìn)程管理以及硬盤和軟盤硬件進(jìn)行初始化處理。在內(nèi)核源代碼的init/目錄中只有一個(gè)main.c 文件。系統(tǒng)在執(zhí)行完boot/目錄中的head.s 程序后就會(huì)將執(zhí)行權(quán)交給main.c。該程序雖然不長(zhǎng),但卻包括了內(nèi)核初始化的所有工作。因此在閱讀該程序的代碼時(shí)需要參照很多其它程序中的初始化部分。而關(guān)于m
99、ain.c,其中的頭文件定義,需要引用到頭文件等,因此要分析其數(shù)據(jù)結(jié)構(gòu),就需要查看Linux目錄下的相關(guān)文件。main.c中最主要是分析main()函數(shù)調(diào)用關(guān)系,而面對(duì)大篇幅的代碼,光看是很容易迷糊的,所以我選用了代碼查看的軟件SourceInsight。此次起始代碼分析,分析了 main()、time()、init()以及各個(gè)頭文件定義等。通過(guò)申明一個(gè)內(nèi)嵌(inline)函數(shù),可以讓gcc 把函數(shù)的代碼集成到調(diào)用它的代碼中。這會(huì)提高代
100、碼執(zhí)行的速度,因?yàn)槭∪チ撕瘮?shù)調(diào)用的開銷。另外,如果任何一個(gè)實(shí)際參數(shù)是一個(gè)常量,那么在編譯時(shí)這些已知值就可能使得無(wú)需把內(nèi)嵌函數(shù)的所有代碼都包括進(jìn)來(lái)而讓代</p><p> 另外,任務(wù)0 中的pause()也需要使用函數(shù)內(nèi)嵌形式來(lái)定義。如果調(diào)度程序首先執(zhí)行新創(chuàng)建的子進(jìn)程init,那么pause()采用函數(shù)調(diào)用形式不會(huì)有什么問(wèn)題。但是內(nèi)核調(diào)度程序執(zhí)行父進(jìn)程(進(jìn)程0)和子進(jìn)程init 的次序是隨機(jī)的,在創(chuàng)建了init
101、后有可能首先會(huì)調(diào)度進(jìn)程0 執(zhí)行。因此pause()也必須采用宏定義來(lái)實(shí)現(xiàn)。</p><p> 由于自己第一次接觸內(nèi)核代碼,一時(shí)有些茫然,面對(duì)大量的代碼無(wú)從下手。Linux是基于C語(yǔ)言編寫的,所以自然需要C語(yǔ)言更為深層的知識(shí),借助一些內(nèi)核查看工具和相關(guān)書籍,可以方便的查看代碼并且分析出各個(gè)模塊的調(diào)用關(guān)系,編譯出自己的Linux內(nèi)核。出于對(duì)Linux的愛(ài)好以及平時(shí)對(duì)Linux的知識(shí)也比較豐富,所以我查找和獲取Lin
102、ux初起原代碼也比較容易。大家通力合作,最終完成了對(duì)Linux初起代碼的分析任務(wù)。過(guò)程是艱辛的,但收獲也很大,讓我認(rèn)識(shí)到面對(duì)一個(gè)Linux內(nèi)核,不能恐懼,只要靜下心來(lái),一步一步分析,最終就能得出框架,并且加深了我對(duì)Linux相關(guān)知識(shí)的認(rèn)識(shí),開闊了眼界。</p><p><b> 致 謝 </b></p><p> 能夠完成這次課程設(shè)計(jì)我要感謝老師對(duì)我的悉心指導(dǎo),
103、沒(méi)有你們的工作,我不可能完成這次對(duì)于我來(lái)說(shuō)算得上是陌生的任務(wù),沒(méi)有你們的幫助,我們會(huì)走更多的彎路;沒(méi)有你平時(shí)的教育,我知識(shí)不會(huì)得到提高,不會(huì)有豐富的眼界。另外感謝同學(xué)們的幫助,在關(guān)鍵的時(shí)候,總是能夠給我耐心的幫助,我由于對(duì)操作系統(tǒng)的知識(shí)不是很熟悉,在我遇到困難的時(shí)候你們總是能給我耐心的講解,讓我在完成任務(wù)的同時(shí)也能夠掌握一些知識(shí),我覺(jué)得這是我本次設(shè)計(jì)最大的收獲。也讓我感覺(jué)到了友誼的力量,再次謝謝你們。 </p><p
104、><b> 參考文獻(xiàn)</b></p><p> [1] 李善平. Linux內(nèi)核2.4版源代碼分析大全. 北京:機(jī)械工業(yè)出版社,2002,1.</p><p> [2] 陳莉君. 深入分析Linux內(nèi)核源代碼. 北京:人民郵電出版社,2002,8.</p><p> [3] 陳向群.操作系統(tǒng)教程.北京:北京大學(xué)出版社,2007,0
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 眾賞文庫(kù)僅提供信息存儲(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ì)自己和他人造成任何形式的傷害或損失。
最新文檔
- linux內(nèi)核裁剪課程設(shè)計(jì)
- linux內(nèi)核源代碼漫游
- Linux操作系統(tǒng)內(nèi)核及源代碼分析.pdf
- 【linux課程設(shè)計(jì)】可變分區(qū)最佳適應(yīng)算法源代碼
- 基于Linux內(nèi)核源代碼的隱蔽通道自動(dòng)化分析.pdf
- linux課程設(shè)計(jì)論文
- linux課程設(shè)計(jì)論文
- linux課程設(shè)計(jì)報(bào)告
- linux課程設(shè)計(jì)76359
- linux課程設(shè)計(jì)76359
- 課程設(shè)計(jì)代碼.txt
- 課程設(shè)計(jì)代碼.txt
- linux內(nèi)核
- 深入分析linux內(nèi)核鏈表
- linux內(nèi)核分析 - 網(wǎng)絡(luò)[五]網(wǎng)橋
- 深入分析 linux 內(nèi)核鏈表
- linux內(nèi)核搶占實(shí)現(xiàn)機(jī)制分析
- 課程設(shè)計(jì)源代碼.zip
- ucos的內(nèi)核移植課程設(shè)計(jì)
- linux課程設(shè)計(jì)---linux操作系統(tǒng)u盤驅(qū)動(dòng)設(shè)計(jì)分析報(bào)告
評(píng)論
0/150
提交評(píng)論