天天看點

Linux核心常見FAQ

     推薦一些好的Linux核心參考書?

  a.《Linux Device Drivers, Second Edition》,有中文譯本

  b.《Understanding the Linux Kernel, 2nd Edition》

  c.《Linux核心源代碼情景分析》,分上下兩冊

  d.《邊幹邊學-Linux核心指導》

    如何得到某一版本的Linux核心源代碼?

  a. http://www.kernel.org或ftp://ftp.kernel.org,這是Linux核心版本的釋出網站。

  b. 很多鏡像或本地網站也提供部分Linux核心版本的下載下傳,多用ftp搜尋引擎。

  c. 一般的Linux發行版如Redhat之類會随盤提供相應的核心源代碼,不過這個源代碼往往是改動過的,與同版本的标準Linux核心可能有些差異。

    推薦一些源代碼檢視工具?

  a. Windows系統可以用Source Insight,Linux系統可以用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核心源代碼。

    xx結構的定義在哪個核心源檔案中?

  a. 請使用源碼檢視工具,見問題2.2。

  b. 如果用grep等文本搜尋工具,主要在include/linux和include/asm兩個目錄下搜尋。

    volatile和__volatile__是什麼意思?

  a. volatile是C語言定義的關鍵字,gcc為了需要又定義了__volatile__,它和volatile表達的是同一意思。

  b. volatile的本意是"易變的",由于通路寄存器的速度快于訪存,是以編譯器一般都會作優化以減少訪存。如果變量加上volatile修飾,則編譯器就不會對此變量的讀寫操作進行優化,即不通過寄存器緩沖而直接訪存。

  c. __asm__ __volatile__一起訓示編譯器不要改動優化後面的彙編語句。

    do{ ... } while(0)是什麼意思?

  a. 主要是為了避免宏在不同情況展開可能會出現的一些錯誤。

  b. 在http://www.kernelnewbies.org/faq/上有詳細介紹。

    list_entry的定義是怎麼回事?

  a. list_entry的定義在核心源檔案include/linux/list.h中:

  #define list_entry(ptr, type, member) \

  ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))

  b. 其功能是根據list_head型指針ptr換算成其宿主結構的起始位址,該宿主結構是type型的,而ptr在其宿主結構中定義為member成員。如下圖:

  req>|type型對象起始位址

  |

  |... ...

  ptr>|ptr指針所指的member成員位址

  |

  |... ...

  ptr指向圖中所示的位置,通過(unsigned long)(&((type*)0)->member)得到ptr和req之間的內插補點,ptr減去這個內插補點就得到了type型宿主結構的指針req,傳回類型為(type*)。

    子產品程式設計需要注意什麼?

  a. 在gcc編譯選項中增加-c

  b. 在gcc編譯選項中定義兩個宏:-DMODULE -D__KERENL__

  或直接在源檔案中定義這兩個宏:

  #define MODULE

  #define __KERNEL__

  c. 在源檔案中包括module.h檔案:

  #include

  d. 如果要用inline功能,需要在gcc編譯選項中增加-O2

    為什麼insmod一個子產品時顯示版本不比對?

  假定你現在運作的核心的源碼目錄絕對路徑是MyKernelSrcPath,在gcc編譯時增加選項:

  -I $MyKernelSrcPath/include

    為什麼出現Unresolved Symbol?

  a. 首先檢視檔案/proc/ksyms,看核心有沒有輸出這個符号,不同的核心版本如2.2和2.4輸出的符号會有些變化。

  b. 如果核心輸出的符号帶有版本控制資訊如符号printk_R12345678,則性質同問題3.2。

    為什麼出現no license錯誤?

  在源檔案加入下面一行:

  MODULE_LICENSE("GPL");

    為什麼看不到用printk列印的資訊?

  a. 列印消息受級别的限制,消息級别可以通過printk設定,如:

  printk("something");

  假設控制台的消息級别為m, 當n 這樣一方面可以提高要列印消息本身的級别(數字越小級别越高),另一方面可以改變控制台的消息級别(可從1到8),如改為8可用以下指令:

  # echo "8" > /proc/sys/kernel/printk

  b. 用dmesg指令看。

  c. 當系統運作klogd和syslogd時,核心消息就會由klogd分發到syslogd,syslogd會根據配置檔案/etc/syslog.conf作相應處理,具體可以檢視syslogd和syslog.conf的man頁。

    怎麼制作、使用patch檔案?

  patch檔案是由diff指令生成的,使用patch檔案用patch指令,具體可檢視diff和patch的man頁和info。

    在核心中可以使用系統調用嗎?

  a. 可以。核心源代碼中就有使用系統調用的例子,如open()、execve()等。

  b. 在核心中使用系統調用必須要在源檔案中包括以下兩行:

  #define __KERNEL_SYSCALLS__

  #include

  c. 核心中使用系統調用的相關定義可檢視檔案include/asm/unistd.h。

  如果要用的系統調用該檔案中沒有定義,可以按照其格式自行添加。

    在核心中怎麼打開并操作一個檔案?

  a. 直接用open()、read()等系統調用,見問題4.2。

  b. 用filp_open()函數打開檔案,得到struct file *的指針fp。

  使用指針fp進行相應操作,如讀檔案可以用fp->f_ops->read。

  最後用filp_close()函數關閉檔案。

  filp_open()、filp_close()函數在fs/open.c定義,在include/linux/fs.h中聲明。

  c. 自己寫包裝函數,可參照檔案fs/exec.c中的open_exec()和kernel_read()函數。

  在http://www.linuxforum.net/forum/showflat.php?Cat=&Board=linuxK&Number=363455&page=&view=&sb=&o=&vc=1上有些代碼可以參照。

    在核心中讀寫檔案時為什麼會出現EFAULT錯誤?

  a. 核心檔案系統提供的read()和write()之類的函數,期望是對使用者态程式服務的,是以它會驗證讀寫緩沖區不超過使用者空間的上限即0xC000 0000。但現在核心中要讀寫檔案,緩沖區在核心中即位址會超過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中定義。

    請問xx指令、xx庫的源碼是哪個檔案?

  a. 一個系統除了核心以外,還需要有shell、gcc等一系列工具和指令以及C庫等一系列庫,這些作為應用程式其源代碼都不在核心中,需要另外下載下傳相應的源代碼。

  b. 對于Redhat系統,可以用rqm -qf指令來查找某一指令所在的軟體包,然後再找相應的源代碼包安裝。

繼續閱讀