歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux基礎 >> Linux服務器

Linux 2.6內核的編譯步驟及模塊動態加載

本文是基於2.6的內核,也建議各位可以先看一下《Linux內核設計與實現(第二版)》作為一個基礎知識的鋪墊。當然,從實踐角度來看,只要按著以下的步驟去做也應該可以實現成功編譯內核及加載模塊。

  個人用的Linux版本為:Debian GNU/Linux,內核版本為:2.6.20-1-686.

  第一步,下載Linux內核的源代碼,即構建LDD3(Linux Device Drivers 3rd)上面所說的內核樹。

  如過安裝的Linux系統中已經自帶了源代碼的話,應該在/usr/src目錄下。如果該目錄為空的話,則需要自己手動下載源代碼。下載代碼的方法和鏈接很多,也可以在CU上通過http://download.chinaunix.net/search/?key=&q=kernel&frmid=53去下載。不過,下載的內核版本最好和所運行的Linux系統的內核版本一致。當然,也可以比Linux系統內核的版本低,但高的話應該不行(個人尚未實踐)。

  Debian下可以很方便的通過Debian源下載:

  首先查找一下可下載的內核源代碼:

  # apt-cache search linux-source

  其中顯示的有:linux-source-2.6.20,沒有和我的內核版本完全匹配,不過也沒關系,直接下載就可以了:

  # apt-get install linux-source-2.6.20

  下載完成後,安裝在/usr/src下,文件名為:linux-source-2.6.20.tar.bz2,是一個壓縮包,解壓縮既可以得到整個內核的源代碼:

  # tar jxvf linux-source-2.6.20.tar.bz2

  解壓後生成一個新的目錄/usr/src/linux——source-2.6.20,所有的源代碼都在該目錄下。

  注:該目錄會因內核版本的不同而不同,各位動手實踐的朋友只需知道自己的源代碼所在的具體位置即可。

  第二步:配置及編譯內核。

  進入/usr/src/linux——source-2.6.20目錄下,可以看到Makefile文件,它包含了整個內核樹編譯信息。該文件最上面四行是關於內核版本的信息。對於整個Makefile可以不用做修改,采用默認的就可以了。

  一般情況下,需要先用命令諸如"make menuconfig", "make xconfig"或者"make oldcofig"對內核進行配置,這幾個都是對內核進行配置的命令,只是它們運行的環境不一樣,執行一下這幾個命令中的任何一個即可對內核進行配置:

  make menuconfig是基於界面的內核配置方法,make xconfig應該是基於QT庫的,還有make gcofig也是基於圖形的配置方法,應該是需要GTK的環境,make oldcofig就是對內核樹原有的.config文件進行配置一下即可。

  其實內核的配置部分,主要是保證內核啟動模塊可動態加載的配置,默認配置裡面應該已經包含了這樣的內容,因此,我用的是make oldconfig.

  在內核源碼的目錄下執行:

  # make

  # make bzImage

  其中,第一個make也可以不執行,直接make bzImage。這個過程可能要持續一個小時左右,因此是對整個內核重新編譯了。執行結束後,可以看到在當前目錄下生成了一個新的文件: vmlinux, 其屬性為-rwxr-xr-x。

  然後執行:

  # make modules

  # make modules_install

  對內核的所有模塊進行編譯和安裝。

  執行結束之後,會在/lib/modules下生成新的目錄/lib/modules/2.6.20/。 在隨後的編譯模塊文件時,要用到這個路徑下的build目錄。至此,內核編譯完成。可以重啟一下系統。

  第三步:編寫模塊文件及Makefile

  以LDD3上的hello.c為例:

//hello.c
#include <linux/init.h>
#include <linux/module.h>
MODULE_LICENSE("Dual BSD/GPL");

static int hello_init(void)
{
    printk(KERN_ALERT "Hello, world\n");
    return 0;
}

static void hello_exit(void)
{
    printk(KERN_ALERT"Goodbye, cruel world\n");
}

module_init(hello_init);
module_exit(hello_exit);


  Makefile文件的內容為:

obj-m := hello.o
KERNELDIR := /lib/modules/2.6.20/build
PWD := $(shell pwd)

modules:
    $(MAKE) -C $(KERNELDIR) M=$(PWD) modules

modules_install:
    $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install

clean:
    rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions


  其中,hello.c和Makefile文件應該位於同一個目錄下,可以放在/home下,我的兩個文件都位於/home/david/.

  第四步:編譯和裝載模塊

  在文件所處的目錄下,執行:

  debian:/home/david # make

  然後查看該目錄下有哪些文件生成:

debian:/home/david # ls -l
總計 28
drwxr-xr-x 2 david david 4096 2007-02-07 17:49 Desktop
-rw-r--r-- 1 david david  462 2007-07-20 13:42 hello.c
-rw-r--r-- 1 root  root  2432 2007-07-20 13:55 hello.ko
-rw-r--r-- 1 root  root   607 2007-07-20 13:55 hello.mod.c
-rw-r--r-- 1 root  root  1968 2007-07-20 13:55 hello.mod.o
-rw-r--r-- 1 root  root  1140 2007-07-20 13:55 hello.o
-rw-r--r-- 1 david david  267 2007-07-20 13:48 Makefile
-rw-r--r-- 1 root  root     0 2007-07-05 14:11 Module.symvers

可見,已經生成模塊文件hello.ko.

  然後,就可以加載該模塊:

  debian:/home/david # insmod hello.ko

  查看模塊是否加載進內核:

  debian:/home/david # lsmod

  Module Size Used by

  hello 1344 0

  nfs 219468 0

  nfsd 202224 17

  …… ……

  其中Module名為hello的即為我們所加載的模塊.

  卸載模塊:

  debian:/home/david # rmmod hello

  同樣可以通過lsmod來查看該模塊是否被卸載.

  這裡有兩個問題,其一就是printk()輸出的問題.LDD3上也說,在加載和卸載模塊的時候都會有信息輸出在屏幕上,如果在Windows下通過終端仿真器(我們常用的虛擬機算是一種),則在屏幕上看不到任何輸出.我同時在虛擬機和和物理機都運行了該模塊,均未看到有"Hello, world"(加載模塊時printk的輸出)或"Goodby, cruel world"(卸載模塊時printk的輸出). 這個不知道是我操作系統發行版的原因還是系統配置的問題,請了解這個問題的朋友指點一下.

  其二,書上講到如果屏幕上看不到信息,可能輸出在某個日志文件裡面了,並說可能在/var/log/messages文件中.並且看到網上很多網友也說是輸出到這個文件裡面.我不知道有沒有發現輸出在其他日志文件裡的,不過我的這個信息輸出在/var/log/syslog裡面.在加載和卸載完該模塊後, 執行命令:

  debian:/home/david # cat /var/log/syslog | grep world

  可以看到有兩行內容.當然,也可以不用grep world, 應該會出現在最後兩行.

  Jul 20 14:15:29 localhost kernel: Hello, world

  Jul 20 14:15:34 localhost kernel: Goodbye, cruel world

  這就是printk應該輸出的信息.

  這裡有另外一個方法,可以實現printk的信息輸出在屏幕上,即更改printk輸出的優先級.例子中的優先級為:KERN_ALERT,優先級為<1>,如果將優先級改為KERN_EMERG即<0>,則可以看到屏幕的輸出信息.

  修改的方法只是修改一下hello.c中兩句printk()的內容,修改後的hello.c如下:

#include <linux/init.h>
#include <linux/module.h>
MODULE_LICENSE("Dual BSD/GPL");

static int hello_init(void)
{
    printk(KERN_EMERG "Hello, world\n");  /*改動部分*/
    return 0;
}

static void hello_exit(void)
{
    printk(KERN_EMERG"Goodbye, cruel world\n"); /*改動部分*/
}

module_init(hello_init);
module_exit(hello_exit);
  同樣的方法編譯生成模塊,再次用insmod和rmmod,則在屏幕上看到的輸出信息為:

debian:/home/david# insmod hello.ko
debian:/home/david#
Message from syslogd@localhost at Fri Jul 20 14:27:32 2007 ...
localhost kernel: Hello, world

debian:/home/david# rmmod hello
debian:/home/david#
Message from syslogd@localhost at Fri Jul 20 14:27:42 2007 ...
localhost kernel: Goodbye, cruel world

debian:/home/david
  但是,是否能夠將printk()的優先級改為KERN_EMERG值得商榷.因為在Linux Kernel Development中,對該優先級的描述為: An emergency condition; the system is probably dead.

  以上就是整個2.6內核編譯步驟以及模塊動態加載的方法.理解和解釋有誤的地方,也請各位浏覽本文的朋友指點,也希望能和對內核和驅動感興趣的朋友交流。

 

Copyright © Linux教程網 All Rights Reserved