2.2 請問xx命令、xx庫的源碼是哪個文件? a. 一個系統(tǒng)除了內核以外,還需要有shell、gcc等一系列工具和命令以及C庫等一 系列庫,這些作為應用程序其源代碼都不在內核中,需要另外下載相應的源代碼。 b. 對于Redhat系統(tǒng),可以用rpm -qf命令來查找某一命令所在的軟件包,然后再找 相應的源代碼包安裝。 c. gnu.org有很多軟件源代碼如bash/glibc/binutils/make/gcc的源代碼。 d. 可在http://www.rpmfind.net或http://www.google.com去搜一搜。
2.4 請推薦一些源代碼查看工具? a. Windows系統(tǒng)可以用Source Insight,Linux系統(tǒng)可以用Source Navigator。 b. vim或emacs編輯器,配合cscope、ctags、etags等交叉索引工具。 c. vim或emacs編輯器,配合grep、egrep等文本搜索工具,不過最好要對源代碼目 錄結構有所熟悉 d. LXR,以網頁的形式通過瀏覽器瀏覽,安裝復雜,可從http://lxr.linux.no/下 載該工具也可以直接訪問http://lxr.linux.no/source/在線閱讀Linux內核源 代碼。 e. GNU global,可以在命令行用,也可以生成hypertext,類似lxr,但更省事。
2.5 內核patch如patch-2.6.3怎么用? a. 內核patch一般是針對前一個版本,如patch-2.6.3是針對2.6.2的內核。 b. 內核patch一般是和ChangeLog對應,如patch-2.6.3對應于ChangeLog-2.6.3。 c. 在內核patch中查找Makefile關鍵字可得到相關信息,如在patch-2.6.0中有: diff -Nru a/Makefile b/Makefile --- a/Makefile Wed Dec 17 19:00:07 2003 +++ b/Makefile Wed Dec 17 19:00:07 2003 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 0 -EXTRAVERSION = -test11 +EXTRAVERSION = d. 找到了針對的內核就可以用patch來升級內核了。
2.7 xx結構的定義在哪個內核源文件中? a. 請使用源碼查看工具,見問題2.4。 b. 如果用grep等文本搜索工具,主要在include/linux和include/asm兩個目錄下 搜索。
2.8 volatile和__volatile__是什么意思? a. volatile是C語言定義的關鍵字,gcc為了需要又定義了__volatile__,它和 volatile表達的是同一意思。 b. volatile的本意是"易變的",由于訪問寄存器的速度快于訪存,所以編譯器一般 都會作優(yōu)化以減少訪存。如果變量加上volatile修飾,則編譯器就不會對此變量 的讀寫操作進行優(yōu)化,即不通過寄存器緩沖而直接訪存。 c. __asm__ __volatile__一起指示編譯器不要改動優(yōu)化后面的匯編語句。
3. 模塊編程問題 3.1 模塊編程需要注意什么? a. Documentation/kbuild/目錄下提供內核模塊編程的核心資料 b. 如果要用inline功能,需要在gcc編譯選項中增加-O2
3.2 為什么insmod一個模塊時顯示版本不匹配? a. 某些時候用insmod -f能夠成功加載,但需謹慎使用。
3.3 為什么出現(xiàn)Unresolved Symbol錯誤? a. 首先查看文件/proc/ksyms,看內核有沒有輸出這個符號,不同的內核版本如 2.2和2.4輸出的符號會有些變化。 b. 如果內核輸出的符號帶有版本控制信息如符號printk_R12345678,則性質同 問題3.2。 c. 注意:現(xiàn)在有很多版本都不輸出sys_call_table了,另想辦法吧!
3.5 為什么看不到用printk打印的信息? a. 打印消息受級別的限制,消息級別可以通過printk設置,如: printk("<n>something"); /* 其中0<=n<=7 */ 假設控制臺的消息級別為m, 當n<m時消息打印到控制臺,否則不打印。 這樣一方面可以提高要打印消息本身的級別(數(shù)字越小級別越高), 另一方面可以改變控制臺的消息級別(可從1到8),如改為8可用以下命令: # echo "8" > /proc/sys/kernel/printk b. 用dmesg命令看。 c. 當系統(tǒng)運行klogd和syslogd時,內核消息就會由klogd分發(fā)到syslogd, syslogd會根據(jù)配置文件/etc/syslog.conf作相應處理,具體可以查看syslogd 和syslog.conf的man頁。
4. 內核開發(fā)問題 4.1 怎么制作、使用patch文件? a. patch文件是由diff命令生成的,使用patch文件用patch命令,具體可查看diff 和patch的man頁和info。 b. diff命令的常用選項組合是urN,如: diff -urN linux/ my_linux/ >mypatch.diff
4.2 在內核中可以使用系統(tǒng)調用嗎? a. 可以。內核源代碼中就有使用系統(tǒng)調用的例子,如open()、execve()等。 b. 在內核中使用系統(tǒng)調用必須要在源文件中包括以下兩行: #define __KERNEL_SYSCALLS__ #include <linux/unistd.h> c. 內核中使用系統(tǒng)調用的相關定義可查看文件include/asm/unistd.h。 如果要用的系統(tǒng)調用該文件中沒有定義,可以按照其格式自行添加。 d. 如果要在模塊中使用系統(tǒng)調用,必須要自己定義errno如: int errno; 內核在lib/errno.c中定義了errno,但該符號不導出,所以模塊編程時需要自己 定義errno,用以存放系統(tǒng)調用出錯號。
4.3 在內核中怎么打開并操作一個文件? a. 直接用open()、read()等系統(tǒng)調用,見問題4.2。 b. 用filp_open()函數(shù)打開文件,得到struct file *的指針fp。 使用指針fp進行相應操作,如讀文件可以用fp->f_ops->read。 最后用filp_close()函數(shù)關閉文件。 filp_open()、filp_close()函數(shù)在fs/open.c定義,在include/linux/fs.h中 聲明。 c. 自己寫包裝函數(shù),可參照文件fs/exec.c中的open_exec()和kernel_read()函數(shù)。 在http://www.linuxforum.net/forum/showflat.php?Cat=&Board=linuxK &Number=363455&page=&view=&sb=&o=&vc=1上有些代碼可以參照。
4.4 在內核中讀寫文件時為什么會出現(xiàn)EFAULT(-14)錯誤? a. 內核文件系統(tǒng)提供的read()和write()之類的函數(shù),期望是對用戶態(tài)程序服務的, 所以它會驗證讀寫緩沖區(qū)不超過用戶空間的上限即0xC000 0000。但現(xiàn)在內核中 要讀寫文件,緩沖區(qū)在內核中即地址會超過0xC000 0000。 b. 在讀寫文件前先得到當前fs:mm_segment_t old_fs=get_fs(); 并設置當前fs為內核fs:set_fs(KERNEL_DS); 在讀寫文件后再恢復原先fs: set_fs(old_fs); set_fs()、get_fs()等相關宏在文件include/asm/uaccess.h中定義。
4.6 怎么在內核中加入自己的驅動程序? a. 去http://www-900.ibm.com/developerWorks/cn/linux/kernel/l-kerconf/ index.shtml看看,了解一下整個內核的配置編譯系統(tǒng)。 b. 在相應位置建立自己的源碼目錄、文件、Makefile等。 c. 修改上層Makefile,把自己的程序加入到內核編譯系統(tǒng)中。 d. 修改上層Config.in,把自己的程序加入到內核配置系統(tǒng)中。 e. 確保自己的初始化函數(shù)被調用。有兩種方法,一是顯式調用,即在原來的系統(tǒng) 初始化函數(shù)中直接加入對自己的調用,如字符設備就在drivers/char/mem.c中的 chr_dev_init()函數(shù)中加入,塊設備就在drivers/block/ll_rw_blk.c中的 blk_dev_init()函數(shù)中加入。另一種方法是用initcall,用宏module_init來申 明你的初始化函數(shù),操作系統(tǒng)在初始化到一定階段后會自動通過init/main.c中 的do_initcalls()函數(shù)來統(tǒng)一調用這些初始化函數(shù)。module_init宏在文件 include/linux/init.h中定義。
4.7 怎么通過程序得到cpu和mem使用率? a. 這些信息的最終來源都是/proc目錄下的文件,如/proc/stat等。 b. procps包下的命令如top、vmstat等實現(xiàn)了這些功能,可以參照其源代碼。 c. procps包可從Redhat發(fā)行版中得到,也可從http://www.surriel.com/procps/ 處獲得。
4.8 如何獲得高精度的系統(tǒng)時間? a. Linux中jiffy是時鐘的基本單位,對于一般的系統(tǒng)來說配置成10ms。大多數(shù)時 鐘相關的系統(tǒng)調用都是基于jiffy,所以精度不會太高。 b. 可以考慮使用TSC(time stamp counter)、rtc(real time clock)等寄存器來獲得 高精度時鐘,具體可查看相關的硬件手冊。