版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
1、 計(jì)算機(jī)科學(xué)與工程學(xué)院課程設(shè)計(jì)報(bào)告題目全稱:linux 內(nèi)核初起代碼分析 學(xué)生學(xué)號: 姓名: 指導(dǎo)老師: 職稱: 指導(dǎo)老師評語: 簽字: 課程設(shè)計(jì)成績:設(shè)計(jì)過程表現(xiàn)設(shè)計(jì)報(bào)告質(zhì)量總分linux 內(nèi)核初起代碼分析目錄目錄摘摘 要要.1第一章第一章 引引 言言.11.1 問題的提出問題的提出.11.2 任務(wù)與分析任務(wù)與分析.1第二章第二章 代碼分析代碼分析.22.1 系統(tǒng)初始化過程流程.22.2 數(shù)據(jù)結(jié)構(gòu) .22.3 常量和出錯(cuò)信息的意義.42.4 調(diào)用關(guān)系圖.42.5 各模塊/函數(shù)的功能及詳細(xì)框圖.52.5.1 static void time_init(void)分析.62.5.2 void m
2、ain(void)分析.62.5.3 pause()分析.82.5.4 static int printf(const char *fmt, .)分析.82.5.5 void init(void)分析.9第三章第三章 內(nèi)核調(diào)試內(nèi)核調(diào)試.123.1 運(yùn)行環(huán)境 .123.2 編譯內(nèi)核過程 .12第四章第四章 總結(jié)與體會總結(jié)與體會 .15致致 謝謝.16參考文獻(xiàn)參考文獻(xiàn) .17linux 內(nèi)核初起代碼分析摘摘 要要隨著計(jì)算機(jī)的普及,計(jì)算機(jī)發(fā)揮著越來越重要的作用,計(jì)算機(jī)的使用也越來越普遍,所以讓更多的人能夠更好的使用和掌握一些計(jì)算機(jī)方法顯得十分重要。充分發(fā)揮計(jì)算機(jī)的作用也顯得十分重要。操作系統(tǒng)應(yīng)運(yùn)而生
3、。操作系統(tǒng)是一種軟件,用來幫助其他的程序控制計(jì)算機(jī)并和用戶進(jìn)行交互。因而,對操作系統(tǒng)的研究是很有必要的。操作系統(tǒng)包含了多個(gè)部分或者組件,最核心的部分是內(nè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)程,并檢測是否出錯(cuò),出錯(cuò)則再次創(chuàng)建執(zhí)行并打印出出錯(cuò)信息。init()函數(shù)運(yùn)行在任
4、務(wù) 0 第 1 次創(chuàng)建的子進(jìn)程(任務(wù) 1)中。它首先對第一個(gè)將要執(zhí)行的程序(shell)的環(huán)境進(jìn)行初始化,然后加載該程序并執(zhí)行之。對linux 初起代碼的分析有助于了解操作系統(tǒng)的啟動,可以更好地理解和認(rèn)識操作系統(tǒng)是如何管理計(jì)算機(jī)資源的。關(guān)鍵詞關(guān)鍵詞:操作系統(tǒng);linux;初起代碼linux 內(nèi)核初起代碼分析-1-第一章第一章 引引 言言 1.1 問題的提出問題的提出 操作系統(tǒng)是一種軟件,用來幫助其他的程序控制計(jì)算機(jī)并和用戶進(jìn)行交互。操作系統(tǒng)包含了眾多程序用來控制計(jì)算機(jī)的核心功能,并且操作系統(tǒng)是鏈接用戶和計(jì)算機(jī)硬件的橋梁,便于人們有效管理。盡管在過去操作系統(tǒng)取得了長足的進(jìn)步,但是基本的目標(biāo)并未改
5、變:通過使用操作系統(tǒng)來處理公共任務(wù),程序員便可以更容易地編寫應(yīng)用程序。應(yīng)用程序是一種軟件,用來向計(jì)算機(jī)的用戶提供某種服務(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ī)范的訪問接口。操作系統(tǒng)包含了多個(gè)部分或者組件,最核心的部分是內(nèi)核。其他的部分用來幫助內(nèi)核完成計(jì)算機(jī)資源的管理和應(yīng)用程序的控制。操作系統(tǒng)控制了計(jì)算機(jī)上運(yùn)行的各種應(yīng)用程序。沒有操作系統(tǒng)各類函數(shù)的調(diào)用,應(yīng)用程序就無法執(zhí)行。因而,對
6、操作系統(tǒng)的研究是很有必要的。 linux 操作系統(tǒng)是使用很廣泛的,高質(zhì)量的一個(gè)操作系統(tǒng),而且作為一個(gè)開源的系統(tǒng),可以很方便的查看起代碼并進(jìn)行分析,有利于更好的認(rèn)識和了解操作系統(tǒng)。此次對 linux 初起代碼的分析有助于了解操作系統(tǒng)的啟動,可以更好地理解和認(rèn)識操作系統(tǒng)是如何管理計(jì)算機(jī)資源的。1.2 任務(wù)與分析任務(wù)與分析 本課題主要的目的是了解一個(gè)操作系統(tǒng)的初起過程。根據(jù)操作系統(tǒng)的基礎(chǔ)知識,分析init/main.c 中關(guān)于系統(tǒng)初起的相關(guān)代碼,了解一個(gè)操作系統(tǒng)的初起過程,得到相關(guān)的框圖,寫出設(shè)計(jì)說明書。1)代碼分析結(jié)果, 包括但不限于:2)數(shù)據(jù)結(jié)構(gòu)3)常量和出錯(cuò)信息的意義4)調(diào)用關(guān)系圖5)各模塊/
7、函數(shù)詳細(xì)框圖分析思路:1)了解基礎(chǔ)知識,找到相關(guān)的源碼;2)對代碼充分閱讀,先得到單個(gè)函數(shù)的數(shù)據(jù)結(jié)構(gòu)和框圖;3)將多個(gè)函數(shù)的框圖匯總,繪出整體的框圖;使用的源代碼是linux/init/main.c (c) 1991 linus torvaldslinux 內(nèi)核初起代碼分析-2-第二章第二章 代碼分析代碼分析 2.1 系統(tǒng)初始化過程流程系統(tǒng)初始化過程流程系統(tǒng)整個(gè)初始化過程見圖 2.1 所示:進(jìn)程 n進(jìn)程 1開始系統(tǒng)初始化對物理內(nèi)存各部分進(jìn)行功能劃分和分配系統(tǒng)各個(gè)部分初始化,包括對任務(wù) 0 初始化移到任務(wù) 0 中執(zhí)行創(chuàng)建進(jìn)程 1(init)空閑時(shí)執(zhí)行 pause()加載根文件系統(tǒng)設(shè)置終端標(biāo)準(zhǔn) i
8、o創(chuàng)建進(jìn)程 2循環(huán)等待進(jìn)程 2 退出創(chuàng)建子進(jìn)程循環(huán)等待進(jìn)程結(jié)束任務(wù)進(jìn)程 0終端輸入定向到 rc執(zhí)行 shell退 出設(shè)置終端標(biāo)準(zhǔn) io執(zhí)行 shell退 出進(jìn)程 2圖2.1 內(nèi)核初始化程序流程示意圖2.2 數(shù)據(jù)結(jié)構(gòu)數(shù)據(jù)結(jié)構(gòu)1) 時(shí)間結(jié)構(gòu):#define clocks_per_sec 100/* 系統(tǒng)時(shí)鐘滴答頻率,100hz */typedef long clock_t;/* 從進(jìn)程開始系統(tǒng)經(jīng)過的時(shí)鐘滴答數(shù) */struct tm int tm_sec;/* 秒數(shù) 0,59 */ int tm_min;/* 分鐘數(shù) 0,59 */ int tm_hour;/* 小時(shí)數(shù) 0,59 */ int t
9、m_mday;/* 1 個(gè)月的天數(shù) 0,31 */ int tm_mon;/* 1 年中月份 0,11 */ int tm_year;/* 從 1900 年開始的年數(shù) */ int tm_wday;/* 1 星期中的某天 0,6(星期天=0) */linux 內(nèi)核初起代碼分析-3- int tm_yday;/* 1 年中的某天 0,365 */ int tm_isdst;/* 夏令時(shí)標(biāo)志 */;2) 存放硬盤參數(shù)表信息:struct drive_info char dummy32;drive_info;/* 用于存放硬盤參數(shù)表信息 */3) tty 等待隊(duì)列數(shù)據(jù)結(jié)構(gòu)和 tty 數(shù)據(jù)結(jié)構(gòu):str
10、uct tty_queue unsigned long data;/* 等待隊(duì)列緩沖區(qū)中當(dāng)前數(shù)據(jù)指針字符數(shù) */ unsigned long head;/* 緩沖區(qū)中數(shù)據(jù)頭指針 */ unsigned long tail;/* 緩沖區(qū)中數(shù)據(jù)尾指針 */ struct task_struct *proc_list; /* 等待進(jìn)程列表 */ char buftty_buf_size;/* 隊(duì)列的緩沖區(qū) */;struct tty_struct /* tty 數(shù)據(jù)結(jié)構(gòu) */ struct termios termios;/* 終端 io 屬性和控制字符數(shù)據(jù)結(jié)構(gòu) */ int pgrp;/* 所屬進(jìn)
11、程組 */ int stopped;/* 停止標(biāo)志 */ void (*write) (struct tty_struct * tty); /* tty 寫函數(shù)指針 */ struct tty_queue read_q;/* tty 讀隊(duì)列 */ struct tty_queue write_q; /* tty 寫隊(duì)列 */ struct tty_queue secondary; /* tty 輔助隊(duì)列(存放規(guī)范模式字符序列) */;/* 可稱為規(guī)范(熟)模式隊(duì)列 */4) 請求隊(duì)列中項(xiàng)的結(jié)構(gòu)和塊設(shè)備結(jié)構(gòu):struct request/* 請求隊(duì)列中項(xiàng)的結(jié)構(gòu)。其中如果 dev=-1,則表示該項(xiàng)
12、沒有被使用 */ int dev;/* 使用的設(shè)備號 */ int cmd;/* 命令(read 或 write) */ int errors;/* 操作時(shí)產(chǎn)生的錯(cuò)誤次數(shù) */ unsigned long sector;/* 起始扇區(qū)(1 塊=2 扇區(qū)) */ unsigned long nr_sectors; /* 讀/寫扇區(qū)數(shù) */ char *buffer;/* 數(shù)據(jù)緩沖區(qū) */ struct task_struct *waiting; /* 任務(wù)等待操作執(zhí)行完成的地方 */ struct buffer_head *bh;/* 緩沖區(qū)頭指針(include/linux/fs.h,68)
13、*/ struct request *next;/* 指向下一請求項(xiàng) */;struct blk_dev_struct/* 塊設(shè)備結(jié)構(gòu) */ void (*request_fn) (void); /* 請求操作的函數(shù)指針 */ struct request *current_request; /* 請求信息結(jié)構(gòu) */;linux 內(nèi)核初起代碼分析-4-2.3 常量和出錯(cuò)信息的意義常量和出錯(cuò)信息的意義定義系統(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)用的名稱,與 _
14、nr_ 組合形成上面的系統(tǒng)調(diào)用符號常數(shù),從而用來對系統(tǒng)調(diào)用表中函數(shù)指針尋址。返回:如果返回值大于等于 0,則返回該值,否則置出錯(cuò)號 errno,并返回-1。#define _syscall0(type,name) type name(void) long _res; _asm_ volatile ( int $0 x80 /* 調(diào)用系統(tǒng)中斷 0 x80 */:=a (_res) /* 返回值 eax(_res) */: (_nr_#name); /* 輸入為系統(tǒng)中斷調(diào)用號_nr_name */ if (_res = 0) /* 如果返回值=0,則直接返回該值 */ return (type)
15、_res; errno = -_res; /* 否則置出錯(cuò)號,并返回-1 */ return -1;/* 有 1 個(gè)參數(shù)的系統(tǒng)調(diào)用宏函數(shù)。type name(atype a) */* %0 - eax(_res),%1 - eax(_nr_name),%2 - ebx(a) */#define _syscall1(type,name,atype,a) type name(atype a) long _res; _asm_ volatile ( int $0 x80 : =a (_res) : (_nr_#name), b (long)(a); if (_res = 0) return (typ
16、e) _res; errno = -_res; return -1; extern int errno;/* 出錯(cuò)號,全局變量 */static inline _syscall0(int,fork)/*這是unistd.h 中的內(nèi)嵌宏代碼。以嵌入?yún)R編的形式調(diào)用linux 的系統(tǒng)調(diào)用中斷0 x80。該中斷是所有系統(tǒng)調(diào)用的入口。該條語句實(shí)際上是int fork()創(chuàng)建進(jìn)程系統(tǒng)調(diào)用。syscall0 名稱中最后的0 表示無參數(shù),1 表示1 個(gè)參數(shù) */static inline _syscall0(int,pause) /* int pause()系統(tǒng)調(diào)用:暫停進(jìn)程的執(zhí)行,直到收到一個(gè)信號 */st
17、atic inline _syscall1(int,setup,void *,bios)/* int setup(void * bios)系統(tǒng)調(diào)用,僅用于linux 初始化(僅在這個(gè)程序中被調(diào)用)*/static inline _syscall0(int,sync) /* int sync()系統(tǒng)調(diào)用更新文件系統(tǒng) */2.4 調(diào)用關(guān)系圖調(diào)用關(guān)系圖在內(nèi)核源代碼的init/目錄中只有一個(gè)main.c 文件。系統(tǒng)在執(zhí)行完boot/目錄中的head.s 程序后就linux 內(nèi)核初起代碼分析-5-會將執(zhí)行權(quán)交給main.c。該程序雖然不長,但卻包括了內(nèi)核初始化的所有工作。main.c 程序首先利用前面s
18、etup.s 程序取得的系統(tǒng)參數(shù)設(shè)置系統(tǒng)的根文件設(shè)備號以及一些內(nèi)存全局變量。這些內(nèi)存變量指明了主內(nèi)存的開始地址、系統(tǒng)所擁有的內(nèi)存容量和作為高速緩沖區(qū)內(nèi)存的末端地址。如果還定義了虛擬盤(ramdisk),則主內(nèi)存將適當(dāng)減少。整個(gè)內(nèi)存的映像示意圖見圖3.1 所示。內(nèi)核程序高速緩存主內(nèi)存區(qū)虛擬盤圖 2.1 系統(tǒng)中內(nèi)存功能劃分示意圖圖中,高速緩沖部分還要扣除被顯存和rom bios 占用的部分。高速緩沖區(qū)是用于磁盤等塊設(shè)備臨時(shí)存放數(shù)據(jù)的地方,以1k(1024)字節(jié)為一個(gè)數(shù)據(jù)塊單位。主內(nèi)存區(qū)域的內(nèi)存是由內(nèi)存管理模塊mm通過分頁機(jī)制進(jìn)行管理分配,以4k 字節(jié)為一個(gè)內(nèi)存頁單位。內(nèi)核程序可以自由訪問高速緩沖中
19、的數(shù)據(jù),但需要通過mm 才能使用分配到的內(nèi)存頁面。然后,內(nèi)核進(jìn)行所有方面的硬件初始化工作。包括陷阱門、塊設(shè)備、字符設(shè)備和 tty,包括人工設(shè)置第一個(gè)任務(wù)(task 0)。待所有初始化工作完成后就設(shè)置中斷允許標(biāo)志以開啟中斷,main()也切換到了任務(wù) 0 中運(yùn)行。在整個(gè)內(nèi)核完成初始化后,內(nèi)核將執(zhí)行權(quán)切換到了用戶模式(任務(wù)0),也即cpu 從0 特權(quán)級切換到了第3 特權(quán)級。此時(shí)main.c 的主程序就工作在任務(wù)0 中。然后系統(tǒng)第一次調(diào)用進(jìn)程創(chuàng)建函數(shù)fork(),創(chuàng)建出一個(gè)用于運(yùn)行init()的子進(jìn)程。2.5 各模塊各模塊/函數(shù)的功能及詳細(xì)框圖函數(shù)的功能及詳細(xì)框圖該程序首先確定如何分配使用系統(tǒng)物理內(nèi)
20、存,然后調(diào)用內(nèi)核各部分的初始化函數(shù)分別對內(nèi)存管理、中斷處理、塊設(shè)備和字符設(shè)備、進(jìn)程管理以及硬盤和軟盤硬件進(jìn)行初始化處理。在完成了這些操作之后,系統(tǒng)各部分已處于可運(yùn)行狀態(tài)。此后程序把自己“手工”移動到任務(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則會在系統(tǒng)空閑時(shí)被調(diào)度執(zhí)行,此時(shí)任務(wù)0僅執(zhí)行pause()系統(tǒng)調(diào)用,并又會調(diào)用調(diào)度函數(shù)。在init 進(jìn)程中,如果終端環(huán)境建立成功,則會再生成一個(gè)子進(jìn)程(進(jìn)程2),用于運(yùn)行shell 程序/bin/sh。若該子進(jìn)程退出,則父進(jìn)程進(jìn)入一個(gè)死
21、循環(huán)內(nèi),繼續(xù)生成子進(jìn)程,并在此子進(jìn)程中再次執(zhí)行shell 程序/bin/sh,而父進(jìn)程則繼續(xù)等待。由于創(chuàng)建新進(jìn)程的過程是通過完全復(fù)制父進(jìn)程代碼段和數(shù)據(jù)段的方式實(shí)現(xiàn)的,因此在首次使用fork()創(chuàng)建新進(jìn)程init 時(shí),為了確保新進(jìn)程用戶態(tài)堆棧沒有進(jìn)程0 的多余信息,要求進(jìn)程0 在創(chuàng)建首個(gè)新進(jìn)程之前不要使用用戶態(tài)堆棧,也即要求任務(wù)0 不要調(diào)用函數(shù)。因此在main.c 主程序移動到任務(wù)0 執(zhí)行后,任務(wù)0 中的代碼fork()不能以函數(shù)形式進(jìn)行調(diào)用。程序中實(shí)現(xiàn)的方法是采用gcc 函數(shù)內(nèi)嵌的形式來執(zhí)行這個(gè)系統(tǒng)調(diào)用。通過申明一個(gè)內(nèi)嵌(inline)函數(shù),可以讓gcc 把函數(shù)的代碼集成到調(diào)用它的代碼中。這會
22、提高代碼執(zhí)行的速度,因?yàn)槭∪チ撕瘮?shù)調(diào)用的開銷。另外,如果任何一個(gè)實(shí)際參數(shù)是一個(gè)常量,那么在編譯時(shí)這些已知值就可能使得無需把內(nèi)嵌函數(shù)的所有代碼都包括進(jìn)來而讓代碼也得到簡化。另外,任務(wù)0 中的pause()也需要使用函數(shù)內(nèi)嵌形式來定義。如果調(diào)度程序首先執(zhí)行新創(chuàng)建的子進(jìn)程init,那么pause()采用函數(shù)調(diào)用形式不會有什么問題。但是內(nèi)核調(diào)度程序執(zhí)行父進(jìn)程(進(jìn)程0)和子進(jìn)程init 的次序是隨機(jī)的,在創(chuàng)建了init 后有可能首先會調(diào)度進(jìn)程0 執(zhí)行。因此pause()也必須采用宏定義來實(shí)現(xiàn)。對于linux 來說,所有任務(wù)都是在用戶模式運(yùn)行的,包括很多系統(tǒng)應(yīng)用程序,如shell 程序、網(wǎng)絡(luò)子系統(tǒng)程序等。
23、內(nèi)核源代碼lib/目錄下的庫文件就是專門為這里新創(chuàng)建的進(jìn)程提供支持函數(shù)的。linux 內(nèi)核初起代碼分析-6-2.5.1 static void time_init(void)分析分析該子程用于讀取取 cmos 時(shí)鐘,并設(shè)置開機(jī)時(shí)間 startup_time(秒)。struct tm time; /* 時(shí)間結(jié)構(gòu) tm 定義在 include/time.h 中 */ do time.tm_sec = cmos_read(0); /* 當(dāng)前時(shí)間秒值(均是 bcd 碼值)*/ time.tm_min = cmos_read(2); /* 當(dāng)前分鐘值 */ time.tm_hour = cmos_rea
24、d(4); /* 當(dāng)前小時(shí)值 */ time.tm_mday = cmos_read(7); /* 一月中的當(dāng)天日期 */ time.tm_mon = cmos_read(8); /* 當(dāng)前月份(112)*/ time.tm_year = cmos_read(9); /* 當(dāng)前年份 */ while (time.tm_sec != cmos_read(0);cmos 的訪問速度很慢。為了減小時(shí)間誤差,在讀取了下面循環(huán)中所有數(shù)值后,若此時(shí)cmos 中秒值發(fā)生了變化,那么就重新讀取所有值。 bcd_to_bin(time.tm_sec); /* 轉(zhuǎn)換成二進(jìn)制數(shù)值 */ bcd_to_bin(tim
25、e.tm_min); bcd_to_bin(time.tm_hour); bcd_to_bin(time.tm_mday); bcd_to_bin(time.tm_mon); bcd_to_bin(time.tm_year); time.tm_mon-; /* tm_mon 中月份范圍是 011 */startup_time = kernel_mktime(&time); /* 調(diào)用 kernel/mktime.c 中函數(shù),計(jì)算從 1970 年 1 月 1 日 0 時(shí)起到開機(jī)當(dāng)日經(jīng)過的秒數(shù),作為開機(jī)時(shí)間 */2.5.2 void main(void)分析分析main()函數(shù)中完成啟動時(shí)對設(shè)備內(nèi)
26、核初始化,以及創(chuàng)建進(jìn)程。此時(shí)中斷仍被禁止著,做完必要的設(shè)置后就將其開啟。下面這段代碼用于保存:根設(shè)備號:root_dev; 高速緩存末端地址:buffer_memory_end;機(jī)器內(nèi)存:memory_end;主內(nèi)存開始地址 :main_memory_start; root_dev = orig_root_dev; /* root_dev 定義在 fs/super.c */ drive_info = drive_info; /* 復(fù)制 0 x90080 處的硬盤參數(shù)表 */ memory_end = (120) + (ext_mem_k 16*1024*1024) /* 如果內(nèi)存超過 16mb
27、,則按 16mb 計(jì) */ memory_end = 16*1024*1024; if (memory_end 12*1024*1024) /* 如果內(nèi)存12mb,則設(shè)置緩沖區(qū)末端=4mb */ buffer_memory_end = 4*1024*1024; else if (memory_end 6*1024*1024) /* 否則如果內(nèi)存6mb,則設(shè)置緩沖區(qū)末端=2mb */ buffer_memory_end = 2*1024*1024; else buffer_memory_end = 1*1024*1024; /* 否則則設(shè)置緩沖區(qū)末端=1mb */linux 內(nèi)核初起代碼分析-7
28、- main_memory_start = buffer_memory_end; /* 主內(nèi)存起始位置=緩沖區(qū)末端 */* 如果定義了內(nèi)存虛擬盤,則初始化虛擬盤。此時(shí)主內(nèi)存將減少。參見kernel/blk_drv/ramdisk.c。*/#ifdef ramdiskmain_memory_start += rd_init(main_memory_start, ramdisk*1024);#endifmem_init(main_memory_start,memory_end); /* 內(nèi)核進(jìn)行所有方面的初始化工作 */trap_init(); /* 陷阱門(硬件中斷向量)初始化。(kernel/
29、traps.c) */blk_dev_init(); /* 塊設(shè)備初始化。 (kernel/blk_drv/ll_rw_blk.c)*/chr_dev_init(); /* 字符設(shè)備初始化。 (kernel/chr_drv/tty_io.c)*/tty_init(); /* tty 初始化。 (kernel/chr_drv/tty_io.c)*/time_init(); /* 設(shè)置開機(jī)啟動時(shí)間:startup_time */sched_init(); /* 調(diào)度程序初始化(加載了任務(wù) 0 的 tr,ldtr)(kernel/sched.c)*/buffer_init(buffer_memory
30、_end); /* 緩沖管理初始化,建內(nèi)存鏈表等。(fs/buffer.c)*/hd_init(); /* 硬盤初始化。 (kernel/blk_drv/hd.c)*/floppy_init(); /* 軟驅(qū)初始化。 (kernel/blk_drv/floppy.c)*/sti(); /* 所有初始化工作都做完了,開啟中斷 */* 下面過程通過在堆棧中設(shè)置的參數(shù),利用中斷返回指令啟動任務(wù) 0 執(zhí)行 */move_to_user_mode(); /* 移到用戶模式下執(zhí)行。(include/asm/system.h)*/if (!fork() init(); /* 在新建的子進(jìn)程(任務(wù) 1)中執(zhí)行
31、 */main()流程圖如圖 2.2:linux 內(nèi)核初起代碼分析-8- yn開始內(nèi)存起始分配啟動設(shè)備和程序初始化開啟中斷切換到用戶模式fork()!=0調(diào)用 init()初始化調(diào)用 pause ()運(yùn)行任務(wù) 0結(jié) 束圖 2.2 main()流程圖2.5.3 pause()分析分析代碼開始以任務(wù) 0 的身份運(yùn)行。對于任何其它的任務(wù),pause()將意味著我們必須等待收到一個(gè)信號才會返回就緒運(yùn)行態(tài),但任務(wù) 0(task0)是唯一的例外情況,因?yàn)槿蝿?wù) 0 在任何空閑時(shí)間里都會被激活(當(dāng)沒有其它任務(wù)在運(yùn)行時(shí)),因此對于任務(wù) 0 pause()僅意味著我們返回來查看是否有其它任務(wù)可以運(yùn)行,如果沒有的話
32、我們就回到這里,一直循環(huán)執(zhí)行 pause()。pause()系統(tǒng)調(diào)用(kernel/sched.c,144)會把任務(wù) 0 轉(zhuǎn)換成可中斷等待狀態(tài),再執(zhí)行調(diào)度函數(shù)。但是調(diào)度函數(shù)只要發(fā)現(xiàn)系統(tǒng)中沒有其它任務(wù)可以運(yùn)行時(shí)就會切換到任務(wù) 0,而不依賴于任務(wù) 0 的狀態(tài)。2.5.4 static int printf(const char *fmt, .)分析分析產(chǎn)生格式化信息并輸出到標(biāo)準(zhǔn)輸出設(shè)備 stdout(1),這里是指屏幕上顯示。參數(shù)*fmt指定輸出將采用的格式。該子程序正好是 vsprintf 如何使用的一個(gè)例子。該程序使用 vsprintf()將格式化的字符串放入 printbuf 緩沖區(qū),然后用
33、 write()將緩沖區(qū)的內(nèi)容輸出到標(biāo)準(zhǔn)設(shè)備(1-stdout)。static int printf(const char *fmt, .)va_list args;int i;va_start(args, fmt);write(1,printbuf,i=vsprintf(printbuf, fmt, args);va_end(args);return i;linux 內(nèi)核初起代碼分析-9-2.5.5 void init(void)分析分析 argv0中的字符“-”是傳遞給 shell 程序 sh 的一個(gè)標(biāo)志。通過識別該標(biāo)志,sh程序會作為登錄 shell 執(zhí)行。其執(zhí)行過程與在 shell 提
34、示符下執(zhí)行 sh 不太一樣。static char * argv_rc = /bin/sh, null ; /* 調(diào)用執(zhí)行程序時(shí)參數(shù)的字符串?dāng)?shù)組 */static char * envp_rc = home=/, null ; /* 調(diào)用執(zhí)行程序時(shí)的環(huán)境字符串?dāng)?shù)組 */static char * argv = -/bin/sh,null ; /* 同上 */static char * envp = home=/usr/root, null ; 在 main()中已經(jīng)進(jìn)行了系統(tǒng)初始化,包括內(nèi)存管理、各種硬件設(shè)備和驅(qū)動程序。init()函數(shù)運(yùn)行在任務(wù) 0 第 1 次創(chuàng)建的子進(jìn)程(任務(wù) 1)中。它首
35、先對第一個(gè)將要執(zhí)行的程序(shell)的環(huán)境進(jìn)行初始化,然后加載該程序并執(zhí)行之。setup(void *) &drive_info);/* 這是一個(gè)系統(tǒng)調(diào)用。用于讀取硬盤參數(shù)包括分區(qū)表信息并加載虛擬盤(若存在的話)和安裝根文件系統(tǒng)設(shè)備。該函數(shù)對應(yīng)函數(shù)是 sys_setup() */然后以讀寫訪問方式打開設(shè)備“/dev/tty0”,它對應(yīng)終端控制臺。由于這是第一次打開文件操作,因此產(chǎn)生的文件句柄號(文件描述符)肯定是 0。該句柄是 unix 類操作系統(tǒng)默認(rèn)的控制臺標(biāo)準(zhǔn)輸入句柄 stdin。這里把它以讀和寫的方式打開是為了復(fù)制產(chǎn)生標(biāo)準(zhǔn) 輸出(寫)句柄 stdout 和標(biāo)準(zhǔn)出錯(cuò)輸出句柄 stderr
36、。(void) open(/dev/tty0,o_rdwr,0);(void) dup(0); /* 復(fù)制句柄,產(chǎn)生句柄 1 號 - stdout 標(biāo)準(zhǔn)輸出設(shè)備 */(void) dup(0); /* 復(fù)制句柄,產(chǎn)生句柄 2 號 - stderr 標(biāo)準(zhǔn)出錯(cuò)輸出設(shè)備 */ 打印緩沖區(qū)塊數(shù)和總字節(jié)數(shù),每塊 1024 字節(jié),以及主內(nèi)存區(qū)空閑內(nèi)存字節(jié)數(shù)。printf(%d buffers = %d bytes buffer spacenr,nr_buffers,nr_buffers*block_size);printf(free mem: %d bytesnr,memory_end-main_memo
37、ry_start); fork()用于創(chuàng)建一個(gè)子進(jìn)程(任務(wù) 2)。對于被創(chuàng)建的子進(jìn)程,fork()將返回 0 值,對于原進(jìn)程(父進(jìn)程)則返回子進(jìn)程的進(jìn)程號 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 - 文件或目錄不存在。 if (!(pid=fork() close(0); if (open(/etc/rc,o
38、_rdonly,0) _exit(1); /* 如果打開文件失敗,則退出(lib/_exit.c,10) */ execve(/bin/sh,argv_rc,envp_rc); /* 替換成/bin/sh 程序并執(zhí)行 */ _exit(2); /* 若 execve()執(zhí)行失敗則退出 */ 下面還是父進(jìn)程(1)執(zhí)行的語句。wait()等待子進(jìn)程停止或終止,返回值應(yīng)是子進(jìn)程的進(jìn)程號(pid)。這三句的作用是父進(jìn)程等待子進(jìn)程的結(jié)束。&i 是存放返回狀態(tài)信息的位置。如果 wait()返回值不等于子進(jìn)程號,則繼續(xù)等待。if (pid0)while (pid != wait(&i) /* 空循環(huán) */如
39、果執(zhí)行到這里,說明剛創(chuàng)建的子進(jìn)程的執(zhí)行已停止或終止了。下面循環(huán)中首先再創(chuàng)建一個(gè)子進(jìn)程,如果出錯(cuò),則顯示“初始化程序創(chuàng)建子進(jìn)程失敗”信息并繼續(xù)執(zhí)行。對于所創(chuàng)建的子進(jìn)程將關(guān)linux 內(nèi)核初起代碼分析-10-閉所有以前還遺留的句柄(stdin, stdout, stderr),新創(chuàng)建一個(gè)會話并設(shè)置進(jìn)程組號,然后重新打開/dev/tty0 作為 stdin,并復(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)行,返回碼
40、是 i”,然后繼續(xù)重試下去,形成一個(gè)死循環(huán)。 while (1) if (pid=fork()0是否等待?再次創(chuàng)建?打印創(chuàng)建出錯(cuò)打開執(zhí)行pid= wait(&i)打印出錯(cuò)信息_exit(0)結(jié) 束圖 2.3 init()流程圖linux 內(nèi)核初起代碼分析-12-第三章第三章 內(nèi)核調(diào)試內(nèi)核調(diào)試3.1 運(yùn)行環(huán)境內(nèi)核編譯運(yùn)行于模擬 linux 環(huán)境的 bochs-2.1.1 中。3.2 編譯內(nèi)核過程1)用 bochs 運(yùn)行 linux0.11,開始如圖 3.1:圖 3.1 bochs 運(yùn)行 linux0.112)進(jìn)入 /usr/src/linux/init, 使用 ls 命令顯示當(dāng)前目錄文件,可以看
41、到我們需要的 main.c 文件,如圖3.2:圖 3.2 ls 命令顯示當(dāng)前目錄文件3)vi main.c 可以編譯啟動代碼,insert 插入,esc+:wq 保存并退出,如圖 3.3:圖 3.3 vi編譯啟動代碼4)返回 linux 目錄,使用 make clean 清除源代碼生成的執(zhí)行文件和中間的目標(biāo)文件,如圖 3.4:linux 內(nèi)核初起代碼分析-13-圖 3.4 make clean5)然后使用 make 命令編譯生成新的內(nèi)核,如圖 3.5:圖 3.5 make 命令編譯生成新的內(nèi)核6)然后修復(fù) grub 引導(dǎo)(這里不再贅述),重啟后可看到多選菜單,默認(rèn)首選就是我修改 main.c
42、編譯的內(nèi)核,如圖 3.6:圖 3.6 新建 grub 引導(dǎo)7)進(jìn)入后啟動顯示信息。首先,顯示的是硬盤信息以及執(zhí)行起始程序(kernel() ) ,由此可見,啟動時(shí)先要對硬件初始化和起始程序位置。然后顯示硬盤是否有錯(cuò)誤信息以及磁盤使用情況。因?yàn)?linux 編程有嚴(yán)格的限制,我試著將 printf()定義移到 main()之前,修改 main()的內(nèi)容并使之顯示,沒有成功,我就只修改了 init()里的內(nèi)容??梢钥吹斤@示打印出磁盤信息,然后用fork()創(chuàng)建一個(gè)進(jìn)程,然后打開/etc/rc/、執(zhí)行 bin/sh,由于沒有出錯(cuò),就沒有跳轉(zhuǎn)到出錯(cuò)的死循環(huán)中,沒有錯(cuò)誤信息顯示,最后打印出創(chuàng)建進(jìn)程成功。系統(tǒng)初始化完成,返回值 ok。由此可以驗(yàn)證我們對初起代碼 main.c 分析的正確性。如圖 3.7:linux 內(nèi)核初起代碼分析-14-圖 3.7linux 內(nèi)核初起代碼分析-15-第四章第四章 總結(jié)與體會總結(jié)與體會該程序首先確定如何分配使用系統(tǒng)物理內(nèi)存,然后調(diào)用內(nèi)核各部分的初始化函數(shù)分別對內(nèi)
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2024年項(xiàng)目參與保密協(xié)議
- 2024無縫鋼管行業(yè)專利申請與保護(hù)協(xié)議2篇
- 2024招投標(biāo)與合同管理:知識產(chǎn)權(quán)合同保護(hù)第一課3篇
- 2024年某高速路段建設(shè)引薦服務(wù)協(xié)議
- 2024年股權(quán)變更正規(guī)協(xié)議模板版B版
- 2024年設(shè)備租賃押金借款合同
- 2025餐飲業(yè)食品安全管理體系認(rèn)證合同范本3篇
- 專業(yè)市場2024年度經(jīng)營管理承包合同書版B版
- 2024技術(shù)開發(fā)合作合同技術(shù)指標(biāo)
- 2024食品公司信息安全保密合同
- 人教版五年級上冊四則混合運(yùn)算300道及答案
- 服裝企業(yè)員工手冊模板范文
- 《低空航空器起降點(diǎn)基礎(chǔ)設(shè)施配置技術(shù)要求》(征求意見稿)
- 2024中輕度游戲全球市場趨勢洞察
- 中國兒童注意缺陷多動障礙ADHD防治指南專家講座
- 部編人教版數(shù)學(xué)二年級下冊課前預(yù)習(xí)單
- 解除勞動合同經(jīng)濟(jì)補(bǔ)償協(xié)議書
- 2024年4月自考02799獸醫(yī)臨床醫(yī)學(xué)試題
- 市政工程勞動力計(jì)劃
- 印度尼西亞發(fā)展熱帶經(jīng)濟(jì)作物的氣候條件評價(jià)-以爪哇和蘇門答臘島為例
- 吞咽障礙康復(fù)護(hù)理專家共識
評論
0/150
提交評論