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