Linux核心/模組開發常見問題集(FAQ)

來源:互聯網
上載者:User
 

         轉載自水木清華
  歡迎大家補充

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

2. 原始碼問題
2.1 如何得到某一版本的Linux核心原始碼?
2.2 請問xx命令、xx庫的源碼是哪個檔案?
2.3 linux-2.x.x.tar.gz.sign 檔案有什麼用途?
2.4 請推薦一些原始碼查看工具?
2.5 核心patch如patch-2.6.3怎麼用?
2.6 如何統計linux核心有多少行代碼?
2.7 xx結構的定義在哪個核心源檔案中?
2.8 volatile和__volatile__是什麼意思?
2.9 do{ ... } while(0)是什麼意思?
2.10 list_entry的定義是怎麼回事?
2.11 校內查看linux 核心原始碼地址

3. 模組編程問題
3.1 模組編程需要注意什嗎?
3.2 為什麼insmod一個模組時顯示版本不匹配?
3.3 為什麼出現Unresolved Symbol錯誤?
3.4 為什麼出現no license錯誤?
3.5 為什麼看不到用printk列印的資訊?

4. 核心開發問題
4.1 怎麼製作、使用patch檔案?
4.2 在核心中可以使用系統調用嗎?
4.3 在核心中怎麼開啟並操作一個檔案?
4.4 在核心中讀寫檔案時為什麼會出現EFAULT(-14)錯誤?
4.5 怎麼在系統中增加一個自己的系統調用?
4.6 怎麼在核心中加入我自己的驅動程式?
4.7 怎麼通過程式得到cpu和mem使用率?
4.8 如何獲得高精度的系統時間?
4.9 怎麼進行系統效能調諧?
4.10 核心中怎麼進行互斥?

5. 其它問題
5.1 如何學習Linux核心?
5.2 如何下載精華區?
5.3 init進程是核心進程嗎?init與初始進程是不是一回事?
5.4 initrd(.img)有什麼用?

6. 關於本FAQ
7. Changelog

1. 請推薦一些好的Linux核心參考書?
  a.《Linux Device Drivers, 2nd Edition》,有中文譯本
  b.《Understanding the Linux Kernel, 2nd Edition》
  c.《Linux核心原始碼情景分析》,分上下兩冊
  d.《邊幹邊學-Linux核心指導》
  e.《Linux核心2.4版原始碼分析大全》
  f.《Linux Kernel Development》
  g.《IA-64 Linux Kernel: Design and Implementation》
  註:a電子版可在http://www.oreilly.com/catalog/linuxdrive2/下載;
      f和g比較新,在國內比較難買到。
    也可以版面查詢文章標題 "Linux核心書籍推薦&介紹"

2. 原始碼問題
2.1 如何得到某一版本的Linux核心原始碼?
   a. http://www.kernel.org或ftp://ftp.kernel.org,這是Linux核心版本的發布
      網站。
   b. 很多鏡像或以磁碟為基礎的網站也提供部分Linux核心版本的下載,多用ftp搜尋引擎。
      linuxaid.com提供的mirror:
      ftp://ftp.linuxaid.lkams.kernel.org/pub/mirrors/kernel/linux/kernel
   c. 一般的Linux發行版如Redhat之類會隨盤提供相應的核心原始碼,不過這個源代
      碼往往是改動過的,與標準Linux核心有差異。

2.2 請問xx命令、xx庫的源碼是哪個檔案?
   a. 一個系統除了核心以外,還需要有shell、gcc等一系列工具和命令以及C庫等一
      系列庫,這些作為應用程式其原始碼都不在核心中,需要另外下載相應的原始碼。
   b. 對於Redhat系統,可以用rpm -qf命令來尋找某一命令所在的軟體包,然後再找
      相應的原始碼包安裝。
   c. gnu.org有很多軟體原始碼如bash/glibc/binutils/make/gcc的原始碼。
   d. 可在http://www.rpmfind.net或http://www.google.com去搜一搜。

2.3 linux-2.x.x.tar.gz.sign 檔案有什麼用途?
    這是一個數位簽章檔案,用來校正linux-2.x.x.tar.gz這個檔案在簽名後是沒有
    被第三方修改過,更詳細的資訊參考http://www.kernel.org/signature.html。

2.4 請推薦一些原始碼查看工具?
   a. Windows系統可以用Source Insight,Linux系統可以用Source Navigator。
   b. vim或emacs編輯器,配合cscope、ctags、etags等交叉索引工具。
   c. vim或emacs編輯器,配合grep、egrep等文本搜尋工具,不過最好要對原始碼目
      錄結構有所熟悉
   d. LXR,以網頁的形式通過瀏覽器瀏覽,安裝複雜(debian下安裝容易,請版面
搜尋lxr)
    校外:可以直接存取http://lxr.linux.no/source/線上閱讀Linux核心原始碼。
    校內:可以訪問http://10.214.14.127/lxr/http/source/,如果需要特定版本
可以聯絡vatano,只有空間足夠就放上去。
   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.6 如何統計linux核心有多少行代碼?
   嘗試以下shell命令:
   find /usr/src/linux-2.x.x  ->

2.7 xx結構的定義在哪個核心源檔案中?
   a. 請使用源碼查看工具,見問題2.4。
   b. 如果用grep等文本搜尋工具,主要在include/linux和include/asm兩個目錄下
      搜尋。

2.8 volatile和__volatile__是什麼意思?
   a. volatile是C語言定義的關鍵字,gcc為了需要又定義了__volatile__,它和
      volatile表達的是同一意思。
   b. volatile的本意是"易變的",由於訪問寄存器的速度快於訪存,所以編譯器一般
      都會作最佳化以減少訪存。如果變數加上volatile修飾,則編譯器就不會對此變數
      的讀寫操作進行最佳化,即不通過寄存器緩衝而直接訪存。
   c. __asm__ __volatile__一起指示編譯器不要改動最佳化後面的彙編語句。

2.9 do{ ... } while(0)是什麼意思?
   a. 主要是為了避免宏在不同情況展開可能會出現的一些錯誤。
   b. 在http://www.kernelnewbies.org/faq/上有詳細介紹。

2.10 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*)。

2.11 校內查看Linux核心原始碼的地址
http://10.214.14.127/lxr/http/source/

3. 模組編程問題
3.1 模組編程需要注意什嗎?
   a. 在gcc編譯選項中增加-c
   b. 在gcc編譯選項中定義兩個宏:-DMODULE -D__KERENL__
      或直接在源檔案中定義這兩個宏:
      #define MODULE
      #define __KERNEL__
   c. 在源檔案中包括module.h檔案:
      #i nclude <linux/module.h>
   d. 假定你現在啟動並執行核心的源碼目錄絕對路徑是MyKernelSrcPath,在gcc編譯時間
      增加選項:
         -I $MyKernelSrcPath/include (如-I /usr/src/linux/include)
      注意MyKernelSrcPath必須是指向與當前啟動並執行系統核心匹配的(版本一致)、
      能編譯成功的(保證原始碼目錄的完整性)、已經config過的(保證有.config和
      include/linux/autoconf.h檔案)核心源碼目錄
      注意:通常不要 -I /usr/include/linux
   e. 如果要用inline功能,需要在gcc編譯選項中增加-O2
   f. init_module()函數必須return 0,否則會出現Device or resource busy錯誤。

3.2 為什麼insmod一個模組時顯示版本不匹配?
   a. 見上面3.1->d
   b. 某些時候用insmod -f能夠成功載入,但需謹慎使用。

3.3 為什麼出現Unresolved Symbol錯誤?
   a. 首先查看檔案/proc/ksyms,看核心有沒有輸出這個符號,不同的核心版本如
      2.2和2.4輸出的符號會有些變化。
   b. 如果核心輸出的符號帶有版本控制資訊如符號printk_R12345678,則性質同
      問題3.2。
   c. 注意:現在有很多版本都不輸出sys_call_table了,另想辦法吧!

3.4 為什麼出現no license錯誤?
   在源檔案加入下面一行(加在檔案頭部,尾部均可):
   MODULE_LICENSE("GPL");

3.5 為什麼看不到用printk列印的資訊?
   a. 列印訊息受層級的限制,訊息層級可以通過printk設定,如:
        printk("<n>something");  /* 其中0<=n<=7 */
      假設控制台的訊息層級為m, 當n<m時訊息列印到控制台,否則不列印。
      這樣一方面可以提高要列印訊息本身的層級(數字越小層級越高),
      另一方面可以改變控制台的訊息層級(可從1到8),如改為8可用以下命令:
       # echo "8" > /proc/sys/kernel/printk
   b. 用dmesg命令看。
   c. 當系統運行klogd和syslogd時,核心訊息就會由klogd分發到syslogd,
      syslogd會根據設定檔/etc/syslog.conf作相應處理,具體可以查看syslogd
      和syslog.conf的man頁。

4. 核心開發問題
4.1 怎麼製作、使用patch檔案?
   a. patch檔案是由diff命令產生的,使用patch檔案用patch命令,具體可查看diff
      和patch的man頁和info。
   b. diff命令的常用選項組合是urN,如:
        diff -urN linux/ my_linux/ >mypatch.diff

4.2 在核心中可以使用系統調用嗎?
   a. 可以。核心原始碼中就有使用系統調用的例子,如open()、execve()等。
   b. 在核心中使用系統調用必須要在源檔案中包括以下兩行:
      #define __KERNEL_SYSCALLS__
      #i nclude <linux/unistd.h>
   c. 核心中使用系統調用的相關定義可查看檔案include/asm/unistd.h。
      如果要用的系統調用該檔案中沒有定義,可以按照其格式自行添加。
   d. 如果要在模組中使用系統調用,必須要自己定義errno如:
      int errno;
      核心在lib/errno.c中定義了errno,但該符號不匯出,所以模組編程時需要自己
      定義errno,用以存放系統調用出錯號。

4.3 在核心中怎麼開啟並操作一個檔案?
   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上有些代碼可以參照。

4.4 在核心中讀寫檔案時為什麼會出現EFAULT(-14)錯誤?
   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中定義。

4.5 怎麼在系統中增加一個自己的系統調用?
    去http://www.linuxaid.com.cn/engineer/ideal/kernel/new_syscall.htm
    和http://www.xenotime.net/linux/syscall_ex/看看。

4.6 怎麼在核心中加入自己的驅動程式?
   a. 去http://www-900.ibm.com/developerWorks/cn/linux/kernel/l-kerconf/
      index.shtml看看,瞭解一下整個核心的配置編譯系統。
   b. 在相應位置建立自己的源碼目錄、檔案、Makefile等。
   c. 修改上層Makefile,把自己的程式加入到核心編譯系統中。
   d. 修改上層Config.in,把自己的程式加入到核心配置系統中。
   e. 確保自己的初始化函數被調用。有兩種方法,一是顯式調用,即在原來的系統
     初始化函數中直接加入對自己的調用,如字元裝置就在drivers/char/mem.c中的
     chr_dev_init()函數中加入,塊裝置就在drivers/block/ll_rw_blk.c中的
     blk_dev_init()函數中加入。另一種方法是用initcall,用宏module_init來申
     明你的初始化函數,作業系統在初始化到一定階段後會自動通過init/main.c中
     的do_initcalls()函數來統一調用這些初始化函數。module_init宏在檔案
     include/linux/init.h中定義。

4.7 怎麼通過程式得到cpu和mem使用率?
   a. 這些資訊的最終來源都是/proc目錄下的檔案,如/proc/stat等。
   b. procps包下的命令如top、vmstat等實現了這些功能,可以參照其原始碼。
   c. procps包可從Redhat發行版中得到,也可從http://www.surriel.com/procps/
     處獲得。

4.8 如何獲得高精度的系統時間?
   a. Linux中jiffy是時鐘的基本單位,對於一般的系統來說配置成10ms。大多數時
     鐘相關的系統調用都是基於jiffy,所以精度不會太高。
   b. 可以考慮使用TSC(time stamp counter)、rtc(real time clock)等寄存器來獲得
     高精度時鐘,具體可查看相關的硬體手冊。

4.9 怎麼進行系統效能調諧?
   a. IBM developworks:
        http://www-900.ibm.com/developerWorks/cn/linux/l-kperf/index.shtml
        http://www-900.ibm.com/developerWorks/cn/linux/management/tune/index.sht
ml
   b. Linux Performance Tuning項目:http://linuxperf.nl.linux.org/
   c. http://www.fixdown.com/article/article/724.htm

4.10 核心中怎麼進行互斥?
    a. Linux核心中有兩種機制實現互斥:semaphore和spinlock。semaphore是讓進
      程睡眠等待資源,這一般假設無法預測資源什麼時候可以獲得;spin_lock一般
      用在SMP中,它假設所等待的資源馬上就會被釋放,所以迴圈等待資源。
      semaphore只能用於非中斷環境(典型的中斷環境過程包括象timer之類的中斷
      服務程式,softirq等)的進程間互斥,spinlock可以用於所有的進程間包括不同
      cpu的進程間的互斥,spinlock主要用於保護短小的臨界區,使用時必須要特別注
      意死結問題。
    b. semaphore是通過進程調度來實現互斥的。進程請求擷取semaphore時,如果
      semaphore空閑則該進程獲得semaphore,設定標誌並返回;如果semaphore忙
      (其它使用者已經獲得semaphore)則系統構建等待隊列並通過進程調度機制讓本進
      程睡眠。進程釋放semaphore時,系統按一定規則通過等待隊列喚醒一個睡眠進
      程。對semaphore可執行up()和down()操作,詳見include/asm/semaphore.h檔案。
    c. spinlock主要是為SMP互斥而引入的。在請求擷取spinlock時,如果空閑則獲得
      spinlock,設定標誌並返回。如果spinlock已經被其它使用者獲得而處於忙狀態,
      系統就會一直佔用CPU資源,不停查詢spinlock的狀態直到獲得spinlock。

5. 其它問題
5.1 如何學習Linux核心?
    請先閱讀本版精華區核心學習目錄的相關文章。

5.2 如何下載精華區?
   a. 除了88提供的下載,還可以通過指令碼下載-_-

5.3 init進程是核心進程嗎?init與初始進程是不是一回事?
    Linux作業系統在系統初始化之初就捏造了一個原始進程(原始進程在系統初始化
   完畢後就演化成idle進程),當系統初始化進行到一定階段,原始進程會建立(通
   過kernel_thread()函數)出來init進程,init進程繼續進行系統初始化工作並在最
   後執行execve("/sbin/init",...),這樣init就從原來的核心進程搖身一變成使用者
   進程(使用者程式/sbin/init)了。init進程的pid為1,原始進程(idle進程)的
   pid為0。所有其它的進程都由init進程派生,用ps或pstree命令可以看到這一點。

5.4 initrd(.img)有什麼用?
   a. initrd(.img)是一個檔案系統映像,裡面一般包含一些特殊的硬體模組尤其是存
     儲裝置如scsi/raid/ext3模組,以便在保持核心足夠小的同時又支援儘可能多的硬
     件裝置,常被安裝程式使用。
     initrd(.img)也不是必需的,只要必要的模組編譯進核心就可以不用initrd(.img)。
   b. 在使用了initrd(.img)時,系統引導的大致過程如下:
    1)Loader程式(如lilo和grub)載入核心和initrd(.img)
    2)核心解壓縮initrd(.img)為正常的RAM盤檔案系統並掛接為根分區
    3)執行linuxrc,在此過程中會載入硬體模組
    4)在linuxrc終止後,真正的根檔案系統被掛接
    5)在根檔案系統上完成正常的引導過程。對於正常的系統而言,執行/sbin/init,
      這時控制就會轉到正常的大家所熟知的啟動過程。而對於安裝程式,只需將控制
      轉到安裝過程的第一階段,由它完成後續的安裝環境的載入,裝置的進一步初始
      化等操作。
   c. 要使用initrd(.img)首先核心必須配置成支援initrd:
        CONFIG_BLK_DEV_RAM=y
        CONFIG_BLK_DEV_INITRD=y
      其次要在Loader指令碼中增加相應指示。如在grub.conf中增加一行:
        initrd /boot/initrd-2.4.20.img
   d. 可用mkinitrd命令建立initrd(.img)檔案:
        mkinitrd  imagefilename  kernelversion
      如對於2.4.20的核心可以:
        mkinitrd /boot/initrd-2.4.20.img 2.4.20
   e. 具體可查看Documentation/initrd.txt和man mkiinitrd。mkinitrd命令執行的詳
      細過程可以直接查看/sbin/mkinitrd(shell指令碼)檔案。

6. 關於本FAQ
   本FAQ主要根據本版以前的文章整理而成。
   特別感謝mada、pepp等網友提出寶貴意見!

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.