linux-2.6 核心模組編程探索

來源:互聯網
上載者:User
轉自:http://hi.baidu.com/zkheartboy/blog/item/6331d5cec964f60093457e0d.html

一個LINUX 核心模組編程的手記, 未寫完不斷更新中…

一 相關命令
0 查看系統裝載了哪些 核心模組
lsmod modulename

1 載入核心模組
insmod modulename

2 卸載核心模組
rmmod modulename

3 建立裝置檔案
mknod filename dev_type major_number minor_number
說明: 參數 filename 建立的裝置檔案名稱
dev_type 裝置檔案的類型,
c character device (字元裝置)
b block device (塊裝置)
兩種檔案類型的主要區別, block device 有 buffer
major_number 主要號碼 用於標記那個驅動可以使用此裝置(每一個驅動只有唯一的 )
minor_number 鏡像號碼 the driver to distinguish between the various hardware it controls(不能準確翻譯)

———————————————
例:
ls -l /dev/hda[1-3]
brw-rw—- 1 root disk 3, 1 Jul 5 2000 /dev/hda1
brw-rw—- 1 root disk 3, 2 Jul 5 2000 /dev/hda2
brw-rw—- 1 root disk 3, 3 Jul 5 2000 /dev/hda3

b 表示裝置類型

3 表示 major number
1,2,3 表示 minor number
———————————————-

4 查看程式執行過程( 一般用於 檢查程式用了哪些系統調用)
strace ./app

5 自動載入模組(調試好了再用, 要不系統容易掛)
depmod -a (檢查核心 依賴關係是否正確) 產生 /lib/modules/version/modules.dep 檔案
modprobe 在 insmod之前掛載 (核心模組也有依賴性~~) 可以編輯 /etc/modules.conf 讓系統啟動時載入 重要的,比如驅動
modprobe -a msdos (載入 於msdos有依賴關係的所有模組)

二 相關檔案
1 /proc/modules.
存放載入核心的資訊。 lsmod 就是讀的這個檔案

2/etc/modules.conf
讓系統啟動時載入 重要的,比如驅動

3/lib/modules/version/modules.dep
核心依賴關係 ( 猜的, 沒看)

4/var/log/message
我是用turbo 10 案頭版本 作的測試 所以 printk() 函數 輸出時不能顯示在我的kde的終端上
這個問題曾經鬱悶 我 20 分鐘, 後來 情急之下 查看 message檔案 才發現都printk輸出資訊都記錄在 這裡了, 我也夠笨的:(
當知道怎麼建立使用 "字元裝置檔案" 之後 就能寫自己的 printx函數了。也知道為什麼不能顯示在 kede的終端上了 :)

5 /proc/devices
已經使用的裝置檔案 裡面資料的結構是 major number device name

三 使用者空間 VS 核心空間 | 系統調用 (有趣)
核心可以訪問所有的資源,使用者程式也是如此, 只不過,要藉助驅動來訪問。
核心要管理所有的資源,他是使用者程式於硬體的一個橋樑。一個使用者程式運行過程當中, 他把通過系統調用,把資料傳送給核心空間, 然後核心處理這個請求, 之後又把結果返回給使用者空間。核心可以捕獲到所有的這些資訊, 你可以替換到原來的系統調用, 你可一
讓open打不開檔案, 你可以讓mkdir建立不了目錄!!

三 該死的MakeFile!!!
一開始看的所有相關的文章,幾乎都是基於2.4版本的,照著2。4版本的makefile寫,但是我的核心是2.6的, 所以我百試不爽,編譯完了不能載入,鬱悶了好久,差一點沒換掉核心,後來找到了2。6 的手冊才知道問題所在。

2.6 版本核心模組的MakeFile 編譯成.ko檔案
————————————————————
ifneq ($(KERNELRELEASE),)
obj-m:= test.o #模組名稱
else
KDIR:= /lib/modules/$(shell uname -r)/build  #核心路徑
PWD:= $(shell pwd)
default:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
endif
————————————————————

2.4 版本核心模組的MakeFile 編譯成.o檔案
————————————————————
ARGET =test
WARN =-W -Wall -Wstrict-prototypes -Wmissing-prototypes
INCLUDE=-isystem /lib/modules/2.6.0-1/build/include  #核心路徑
CFLAG =-O2 -DMODULE -D__KERNEL__ ${WARN} ${INCLUDE}
CC =gcc

${TARGET}.o: ${TARGET}.c
${CC} ${CFLAG} -c ${TARGET}.c
.PHONY: clean

clean:
rm -rf ${TARGET}.o
————————————————————

四 核心模組程式結構

————————————————-
/*
* hello-1.c - 簡單的hello the world 程式摘自手冊
*/
#include <linux/module.h>/* 所有的核心模組都需要的 */
#include <linux/kernel.h>/* Needed for KERN_ALERT */

//初始化程式,載入模組時執行
int init_module(void)
{
printk("<1>Hello world 1.n");  //本函數輸出資訊, 相當於使用者空間的printf

/*
* 返回非0值,表示出錯,核心不能被載入
*/
return 0;
}

//清除函數,卸載模組時執行
void cleanup_module(void)
{
printk(KERN_ALERT "Goodbye world 1.n");
}
——————————————————

2.6 版本有更多的書寫方法,比如加入載入參數, 加入核心說明等等,可以參考相關文檔

http://www.tldp.org/LDP/lkmpg/2.6/html/index.html

五 應用字元裝置檔案

5.1 資料結構
1 file_operations 在<linux/fs.h> 中定義

說明: 這個結構體中包含對裝置操作的函數指標, 可以通過他的配置和實現操作函數來完成對裝置的操作
把你不使用的入口 設為NULL。

—————————————————————————————-
struct file_operations {
struct module *owner;
loff_t(*llseek) (struct file *, loff_t, int);
ssize_t(*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t(*aio_read) (struct kiocb *, char __user *, size_t, loff_t);
ssize_t(*write) (struct file *, const char __user *, size_t, loff_t *);
ssize_t(*aio_write) (struct kiocb *, const char __user *, size_t,loff_t);
int (*readdir) (struct file *, void *, filldir_t);
unsigned int (*poll) (struct file *, struct poll_table_struct *);
int (*ioctl) (struct inode *, struct file *, unsigned int,unsigned long);
int (*mmap) (struct file *, struct vm_area_struct *);
int (*open) (struct inode *, struct file *);
int (*flush) (struct file *);
int (*release) (struct inode *, struct file *);
int (*fsync) (struct file *, struct dentry *, int datasync);
int (*aio_fsync) (struct kiocb *, int datasync);
int (*fasync) (int, struct file *, int);
int (*lock) (struct file *, int, struct file_lock *);
ssize_t(*readv) (struct file *, const struct iovec *, unsigned long,loff_t *);
ssize_t(*writev) (struct file *, const struct iovec *, unsigned long,loff_t *);
ssize_t(*sendfile) (struct file *, loff_t *, size_t, read_actor_t,void __user *);
ssize_t(*sendpage) (struct file *, struct page *, int, size_t,loff_t *, int);
unsigned long (*get_unmapped_area) (struct file *, unsigned long,unsigned long,
unsigned long,unsigned long);
};
—————————————————————————————-

靠,這傢伙也太難記了,我曾經3次看到這,就去論壇灌水了,不想往下看了。 今兒耐著性子把他看完,才發現自己是個笨蛋!

在新的驅動程式中,你可能會看到一更簡單,更友好的給file_operations 賦值的方式,看下面的這個結構,手冊上說這玩意是
gcc extension gcc 擴充 (GNU c), 是這個意思吧, 反正我理解的就是,gcc在編譯它的時候 先把下面這個玩意翻譯正標準的c,然後再編譯。 哀,可憐的 c標準!不過話又說回來,這東西除了linux別的也沒什麼用處。

——————————————
struct file_operations fops = {
read: device_read, //對應 相應的函數
write: device_write,
open: device_open,
release: device_release
};
——————————————

手冊上說 下面的這個是 C99 特性寫法!(這玩意BSD 也用不了吧? 為什麼還要這麼亂!) 注意:低版本的 gcc
可能會不正常編譯地!因為它超出了GNU C 標準
(http://www-900.ibm.com/developerWorks/cn/linux/l-c99/index.shtml C99
標準參考)

——————————————
struct file_operations fops = {
.read = device_read, //對應 相應的函數
.write = device_write,
.open = device_open,
.release = device_release
};
——————————————

俺選擇 的是第一種寫法!

2 *file* 結構 在 <linux/fs.h> 中定義
說明:
* 它不同於FILE (glibc 中定義的)
* 它是核心級的結構體
* 它表示抽象的 'file'
* 它不是磁碟上的那個 file

* 驅動用結構體來給這個東西賦值,****** 完善理解 *******
* 指向它的指標類型 為 filp , 也可以直接寫成 struct file file

5.2 相關函數

1 註冊裝置函數
<linux/fs.h>
int register_chrdev(unsigned int major, const char *name, struct file_operations *fops);

還記得之前寫的建立裝置檔案的命令吧,
參數說明: major: 它就是 major number 對應唯一的驅動,記住!
name: 它就是 filename 可以在 /proc/devices 裡面找到它(叫device name 更好點)
fops: file_operations 結構體, 這個可以理解為操作裝置的 核心入口,可以用上面說的兩種方法去填充它

函數返回: 1 major 為 0: 動態分配的 major number 值
2 major 為 指定值:
3 major 為特殊數值:

特殊說明: 因為一個驅動只能有一 個 major值,所以有以下三種建立方法
1 先建立裝置檔案,你可以分配一個固定的major值
2 動態分配 major值, 讀取 /proc/devices 檔案 找到major值, 用指令碼建立(在使用者空間建立裝置檔案)
3 動態分配 major值,使用系統調用函數,直接建立裝置檔案 (在核心空間執行)

第 1 種方法不可取, 因為你不可預知 是否將來要 用到這個major number
第 2 種方法,需要在使用者空間建立
第 3 種方法最好,可以動態建立,銷毀裝置檔案,不過麻煩

2 取消註冊裝置函數
關於:counter

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.