我覺得自己的目標很混亂,總是看這個又看那個.雖說這個習慣不好,可是也增加了許多見識.
今天嘗試編寫內核模塊,寫了一個hello,world,結果弄了1個小時。
主要參考了網上的人的說明,結果發現盡信書不如無書,很多人說的都不是很仔細,我覺得這對於初學者來說,很不好。
大家貼出來的東西,不僅僅給自己也是給別人,所以有時候一定要嚴謹,否則很可能誤導別人。
首先貼出代碼
1// 這兩個頭文件包含相應宏定義
2#include <linux/init.h>
3#include <linux/module.h>
4// 告知內核,這是free模塊
5MODULE_LICENSE("GPL");
6
7// 模塊進入函數
8static int __init hello_init(void){
9 printk(KERN_ALERT "Hello World/n");
10 return 0;
11}
12
13// 模塊退出函數
14static void __exit hello_exit(void){
15 printk(KERN_ALERT "Hello World exit/n");
16}
17
18// 初始化
19module_init(hello_init);
20// 退出
21module_exit(hello_exit);
22// 作者聲明
23MODULE_AUTHOR("Di Zhuang");
24MODULE_DESCRIPTION("A simple Hello World Module");
25MODULE_ALIAS("a simplest module");
那麼代碼是很簡單的,問題出現在編譯上,網上很多人說要在編譯的內核下編譯,這個我不太懂,可能是編譯後生成了我們所需要的文件?我是按照linux源代碼Documention目錄下面kbuild下的modules.txt和網上另一位仁兄的makefile寫的,之前我很多人說用gcc -D__KERNEL__ -DMODULE -DLINUX -I{"你的linux源程序目錄"} -c -o 這種編譯的,結果錯誤一大堆,上網搜索,結果也沒誰說出準確的解決方案,都是說自己解決,可我覺得這可能和不同的環境有關,很可能就是你的環境適合你的解決辦法,爲什麼沒人能夠說出一種通用的解決辦法。上面的辦法貌似聽說在2。4內核好用,我2.6還沒搞明白,估計這東西在2.6上不適合吧。
那麼還是採用2.6官方文檔和網上成功編譯人的方案,那就是寫個Makefile,寫好編譯路徑,以及模塊編譯後放置的路徑。insmod貌似總從/lib/modues/目錄下加載模塊的,至於make工具如何保證我們編譯的模塊一定能夠被正確加載,這個我暫時沒研究,以後研究一下。
下面把Makefile文件貼出來
obj-m := {你要編譯目標文件的名.o}
else
# modules所在目錄
KERNELDIR := /lib/modules/`uname -r`/build
default:
$(MAKE) -C $(KERNELDIR) M=`pwd` modules
endif
對於這段語句,說實話,我能明白,可不太知道爲什麼要if else 這麼寫,誰能解答一下?
寫好之後,運行make,然後就會發現你當前目錄多了很多文件,其中一個就是.ko文件,這個就是我們需要的。
好,現在運行insmod ./你的ko文件
網上很多人會說打出什麼打印語句,結果我在控制檯什麼也沒看見,後來才知道,這個需要用dmesg | tail命令來看
好像insmod打印重定向了??????
之後你在運行rmmod ./你的ko文件
OK , 大功告成。
說來,一個Hello,World模塊書寫真老費時間。。。。。。。。
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
(1) 模塊動態加載驅動方式
在內核源碼的“drivers/char/”目錄下新建一個名爲“hello .c”的文件,內容如下:
#include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h>
MODULE_LICENSE ("GPL");
static int __init hello_init (void) { printk (KERN_INFO "Hello world/n"); return 0; }
static void __exit hello_exit (void) { printk (KERN_INFO "Goodbye world/n"); }
module_init (hello_init); module_exit (hello_exit); |
修改Makefile裏面的內核源碼包的路徑,這裏我們必須用到一個已經編譯好的內核的源碼
這裏我們用了
KERNELDIR ?= /mnt/mengyang/source/kernel/linux-2.6.33
根據自己的實際情況修改,一定確保你的內核可以編譯通過,內核可以正常運行!
在命令行裏運行make命令,順利的會生成*.ko文件。將*.ko文件複製到nfs目錄,或是其他的存儲設備。
在命令行裏運行插入模塊的命令
insmod *.ko
順利的可以看到init函數將會被調用。
同樣,運行
rmmod *.ko
順利的可以看到clean函數被執行了。
執行上面命令時,可能報錯誤rmmod: chdir(2.6.33.2-TE2440): No such file or directory
這是由於busybox 1.13.1導致的,,原來是現在的內核模塊在插入卸載時都會要轉到/lib/modules/內核版本號目錄裏。 所以只要建立這個目錄並且把要使用的模塊*.ko文件複製到這個目錄就行了。
(2)靜態的加載驅動
在內核源碼中添加對hello 驅動的支持
修改drivers/char/目錄下的“Kconfig”文件,在7 行添加如下內容:(紅色部分所示)
#
# Character device configuration
#
menu "Character devices"
config CCTE_HELLO
tristate "CCTE2440 Hello Driver"
depends on ARCH_S3C2440
help
CCTE2440 Hello.
修改同目錄下的“Makefile”文件,在合適的行添加如下內容:
#
# Makefile for the kernel character device drivers.
#
#
# This file contains the font map for the default (hardware) font
#
obj-$(CONFIG_ CCTE_HELLO) += hello.o
配置內核
然後輸入:#make menuconfig,然後配置如下:
Device Drivers --->
Character devices --->
<*> CCTE2440 Hello Driver
將其選擇爲“M”(模塊),然後保存配置,編譯出內核鏡像燒寫到開發板中。或是下載到開發板上運行。