linux內核之旅---"hello world"模塊

hello world模塊

0,模塊代碼

#include<linux/init.h>
#include<linux/module.h>

//指定代碼所使用的許可證
MODULE_LICENSE("Dual BSD/GPL"); //模塊採用自由許可證

/* 內核能夠識別的許可證

** Dual BSD/DPL        BSD/DPL雙重許可證

*/



static int hello_init( void ) //模塊被裝載到內核時調用
{
printk(KERN_ALERT "hello kernel!\n");
return 0;
}


static void hello_exit( void ) //模塊被移除內核時調用
{
printk(KERN_ALERT "Goodbye, kernel!");
}


module_init(hello_init); //特殊宏
module_exit(hello_exit);

保存以上代碼爲 hello.c 文件


1,makefile

makefile文件參考書籍《linux設備驅動程序》


//如果已經定義KERNELRELEASE,則表明是從內核構造系統調用的

ifneq ($(KERNELRELEASE),)
obj-m := hello.o
else
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
endif


2,查看效果

$:sudo insmod hello.ko     //加載hello.ko到內核

不會有任何東西出現在終端

//記得12.04是有的,一朋友在redhat 6.5上面測試也是有的

$:lsmod | grep hello      //查看當前所有的驅動模塊

$:remmod hello          //移除hello模塊


前面說了不會在終端上看見任何東西


查看系統日誌

$: cat /var/log/message | grep hello

在終端上顯示:

       ubuntu kernel: [12299.447211] hello kernel!

或者

$:dmseg | grep hello

在終端上顯示:

        ubuntu kernel: [12299.447211] hello kernel!


3,談一談我遇到的問題

當我保存makefile文件的名字爲 makefile時  編譯報錯!

當改爲Makefile 時正確

這是一個疑問



如下文章是我安裝編譯時參考的:

驅動程序和用戶程序可不一樣,它是作爲一個模塊連接到內核模塊來運行的,運行在內核空間裏面。

所以要運行我們自己構造的模塊,需要自己的系統已經配置好內核樹,然後把目標模塊和內核樹連接起來運行!

可以查看一下自己的電腦有沒有配置內核樹,可以到 /lib/modules/2.6.35-22-generic目錄下面,看看有沒有build這個文件夾,如果有,說明你已經有內核樹了,如果沒有,就自己構建內核樹吧。

內核樹構建過程

安裝編譯內核所需要的軟件(也可不裝,除非你要用 make menuconfig,用make oldconfig不要)

sudo apt-get install build-essential kernel-package libncurses5-dev fakeroot

下載內核源碼

先查看linux內核版本:$uname -r

網上說用apt-cache search linux-source命令, 會列出一些可選源碼包,對準你的內核版本號,選擇“with Ubuntu patche”的那個

最後用apt-get install linux-source-2.6.35下載之。解壓縮源碼包,進入解壓後的源碼目錄。

 可是我試了,搜不到,但是還是可以直接用上面的apt-get 命令下載的,但是我下載,也可以直接到這個網址下源代碼,這裏面有各個版本的內核,從1.0到2.6的,都有。

http://www.at.kernel.org/pub/linux/kernel/

在編譯之前我們需要Ubuntu原來內核的一個配置文件,這是我/usr/src目錄下的文件預覽:ls -al

drwxr-xr-x  4 root root     4096 2010-09-04 21:31 fglrx-8.723.1
drwxr-xr-x 24 root root     4096 2010-09-04 20:35 linux-headers-2.6.35-22
drwxr-xr-x  7 root root     4096 2010-09-04 20:35 linux-headers-2.6.35-22-generic
drwxr-xr-x 25 root root     4096 2010-09-16 21:39 linux-source-2.6.35
-rw-r--r--  1 root root 65846876 2010-09-01 22:41 linux-source-2.6.35.tar.bz2

現在我們需要/boot目錄下的config-2.6.35-22-generic文件,我們把它拷貝到我們剛下好解壓的目錄,也就是linux-source-2.6.35

sudo cp /boot/config-2.6.35-22-generic /usr/src/linux-source-2.6.35/.config

接下來切換到root用戶
sudo -i

cd /usr/src/linux-source-2.6.35

make menuconfig或者直接make oldconfig(無需拷貝.config)

終端會彈出一個配置界面

最後有兩項:load a alternative kernel configuration... 
save a alternative configuration... 
選擇load a kernel configuration保存,然後在選擇save akernel configuration再保存退出,並退出配置環境。

 

接下來我們就要開始編譯了。

#cd /usr/src/linux-source-2.6.35
#make
記住一定要是管理員帳號運行,這個過程很久,如果你的cpu是雙核的可以在make後面加個參數,make -j4.

#make bzImage 執行結束後,可以看到在當前目錄下生成了一個新的文件: vmlinux, 其屬性爲-rwxr-xr-x。 

下面就要編譯模塊了,但是編譯模塊時可能會出現如下問題
編譯問題(ld: /ubuntu/omnibook/sections.lds: No such file: No such file or directory 
解決方法:

在/usr/src/linux-source-2.6.35/ubuntu/omnibook/Makefile 中

ifeq ($(KERNELRELEASE),)

# Support for direct Makefile invocation

的前面增加:
PWD=$(shell pwd)

 也就是在ifeq的上一行增加。

然後再編譯模塊

#make modules /* 編譯 模塊 */


#make modules_install  這條命令能在/lib/modules目錄下產生一個目錄

 如果一切順利,編譯過程中不出現什麼錯誤的話,接下來我們就可以開始linux模塊的helloworld了。

我在 /home/xxxx/linux_modules/ 目錄下創建2個文本文件 hello.c Makefile

 //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

# Makefile2.6(2.6內核專門的Makefile文件)
ifneq ($(KERNELRELEASE),)
#kbuild syntax. dependency relationshsip of files and target modules are listed here.
mymodule-objs := hello.o #param-objs := file1.o file2.o
obj-m := hello.o         #obj-m := param.o
else
PWD := $(shell pwd)
KVER ?= $(shell uname -r)
KDIR := /lib/modules/$(KVER)/build
all:
    $(MAKE) -C $(KDIR) M=$(PWD)
clean:
    rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions #這個僞命令沒起作用,待解決,不影響make

.PHONY: modules modules_install clean
endif
#KERNELRELEASE 是在內核源碼的頂層Makefile中定義的一個變量,在第一次讀取執行此Makefile時,KERNELRELEASE沒有被定義,所以make將讀 取執行else之後的內容,如果 make的目標是clean,直接執行clean操作,然後結束。當make的目標爲all時,-C $(KDIR)指明跳轉到內核源碼目錄下讀取那裏的Makefile;M=$(PWD) 表明然後返回到當前目錄繼續讀入、執行當前的Makefile。當從內核源碼目錄返回時,KERNELRELEASE已被定義,kbuild也被啓動去解 析kbuild語法的語句,make將繼續讀取else之前的內容。else之前的內容爲kbuild語法的語句,指明模塊源碼中各文件的依賴關係,以及 要生成的目標模塊名。param-objs := file1.o file2.o 表示param.o由file1.o與file2.o 連接生成,obj-m := param.o表示編譯連接後將生成param.o模塊。

需要注意的是makefile的格式$(MAKE)前面要加個tab.
make 編譯,不出現錯誤的話,用ls -al查看linux_modules目錄下產生了如下文件:
hello.c   hello.mod.c  hello.o   modules.order
hello.ko  hello.mod.o  Makefile  Module.symvers

其中hello.ko就是可加載的模塊文件

現在我們就可以將編譯好的模塊helloworld加載到內核中去了

#insmod ./hello.ko   //這個命令把hello.ko加載到內核

#lsmod|grep hello   //lsmod 這個命令可以查看當前所有的驅動模塊,結果應該顯示hello 680 0

#rmmod hello         //這個命令是把hello這個模塊移除掉

程序的輸出結果可以在(printk 不會輸出到終端)

 

dmesg |grep world
或是/var/log/syslog文件中查看

Hello,World
Goodbye,cruel world

這是程序的輸出。


如果在輸入insmod ./hello.ko時出現如下錯誤提示:insmod: error inserting 'hello.ko': -1 Invalid module format

是因爲記載版本號的字符串和當前正在運行的內核模塊的不一樣,這個版本印戳作爲一個靜態的字符串存在於內核模塊中,叫vermagic,可以從編譯模塊中間生成的文件helloworld.moc.h中,如果出現這種情況:

1,根據modinfo hello.ko命令查看vermagic的值 
2,根據uname -r查看內核版本 
3,對比上邊兩步的值是否相同 
若相同,我就不知道了 
若不同,採用make -C /lib/modules/此處爲你內核版本號對應的文件夾/build M=你模塊源碼的路徑 modules















發佈了33 篇原創文章 · 獲贊 11 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章