使用ioctl和核心交換資料

2021-06-29 15:51:26 字數 3052 閱讀 2742

1. 前言

使用ioctl系統呼叫是使用者空間向核心交換資料的常用方法之一,從ioctl這個名稱上看,本意是針對i/o裝置進行的控制操作,但實際並不限制是真正的i/o裝置,能是所有乙個核心裝置即可。

2. 基本過程

在核心空間中ioctl是非常多核心操作結構的乙個成員函式,如檔案操作結構struct file_operations(include/linux/fs.h)、協議操作結構struct proto_ops(include/linux/net.h)等、tty操作結構struct tty_driver(include/linux/tty_driver.h)等,而這些操作結構分別對應各種核心裝置,只要在使用者空間開啟這些裝置,如i/o裝置可用open(2)開啟,網路協議可用socket(2)開啟等,獲取乙個檔案描述符後,就能在這個描述符上呼叫ioctl(2)來向核心交換資料。

3. ioctl(2)

ioctl(2)函式的基本使用格式為:

int ioctl(int fd, int cmd, void *data)

第乙個引數是檔案描述符;cmd是操作命令,一般分為get、set及其他型別命令,get是使用者空間程序從核心讀資料,set是使用者空間程序向核心寫資料,cmd雖然是個整數,不過有一定的引數格式的,下面再周詳說明;第三個引數是資料起始位置指標,

cmd命令引數是個32位整數,分為四部分:

dir(2b)  size(14b)  type(8b) nr(8b)

周詳定義cmd要包括這4個部分時可使用巨集_ioc(dir,type,nr,size)來定義,而最簡單情況下使用_io(type, nr)來定義就能了,這些巨集都在include/asm/ioctl.h中定義

本文cmd定義為:

#define newchar_ioc_magic   'm'

#define newchar_set    _io(newchar_ioc_magic, 0)

#define newchar_get    _io(newchar_ioc_magic, 1)

#define newchar_ioc_maxnr   1

要定義自己的ioctl操作,能有兩個方式,一種是在現有的核心**中直接新增相關**進行支援,比如想通過socket描述符進行ioctl操作,可在net/ipv4/af_inet.c中的inet_ioctl()函式中新增自己定義的命令和相關的處理函式,重新編譯核心即可,不過這種方法一般不推薦;第二種方法是定義自己的核心裝置,通過裝置的ioctl()來操作,能編成模組,這樣不影響原有的核心,這是最通常的做法。

4. 核心裝置

為進行ioctl操作最通常是使用字元裝置來進行,當然定義其他型別的裝置也能。在使用者空間,可使用mknod命令建立乙個字元型別裝置檔案,假設該裝置的主裝置號為123,次裝置號為0:

mknode /dev/newchar c 123 0

如果是程式設計的話,能用mknode(2)函式來建立裝置檔案。

建立裝置檔案後再將該裝置的核心模組檔案插入核心,就能使用open(2)開啟/dev/newchar檔案,然後呼叫ioctl(2)來傳遞資料,最後用close(2)關閉裝置。而如果核心中還沒有插入該裝置的模組,open(2)時就會失敗。

由於核心記憶體空間和使用者記憶體空間不同,要將核心資料拷貝到使用者空間,要使用專用拷貝函式copy_to_user();要將使用者空間資料拷貝到核心,要使用copy_from_user()。

要最簡單實現以上功能,核心模組只需要實現裝置的open, ioctl和release三個函式即可,

下面介紹程式片斷:

static int newchar_ioctl(struct inode *inode, struct file *filep,

unsigned int cmd, unsigned long arg);

static int newchar_open(struct inode *inode, struct file *filep);

static int newchar_release(struct inode *inode, struct file *filep);

// 定義檔案操作結構,結構中其他元素為空

struct file_operations newchar_fops =

;// 定義要傳輸的資料塊結構

struct newchar;

#define major_dev_num 123

#define device_name "newchar"

開啟裝置,非常簡單,就是增加模組計數器,防止在開啟裝置的情況下刪除模組,

當然想搞得複雜的話可進行各種限制檢查,如只允許指定的使用者開啟等:

static int newchar_open(struct inode *inode, struct file *filep)

關閉裝置,也非常簡單,減模組計數器:

static int newchar_release(struct inode *inode, struct file *filep)

進行ioctl呼叫的基本處理函式

static int newchar_ioctl(struct inode *inode, struct file *filep,

unsigned int cmd, unsigned long arg)

break;

case knewchar_get:

// get操作通常會在資料緩衝區中先傳遞部分初始值作為資料查詢條件,獲取全部

// 資料後重新寫回緩衝區

// 當然也能根據具體情況什麼也不傳入直接向核心獲取資料

}break;

}return ret;

}模組初始化函式,登記字元裝置

static int __init _init(void)

模組退出函式,登出字元裝置

static void __exit _cleanup(void)

module_init(_init);

module_exit(_cleanup);

5. 結論

用ioctl()在使用者空間和核心空間傳遞資料是最常用方法之一,比較簡單方便,而且能在同乙個ioctl中對不同的命令傳送不同的資料結構,本文只是為描述方便而在不同命令中使用了相同的資料結構。

使用ioctl與核心交換資料

1.前言 使用ioctl 系統呼叫是使用者空間向核心交換資料的常用方法之一,從 ioctl 這個名稱上看,本意是針對 i o裝置進行的控制操作,但實際並不限制是真正的 i o裝置,可以是任何乙個核心裝置即可。2.基本過程 在核心空間中 ioctl 是很多核心操作結構的乙個成員函式,如檔案操作結構 s...

使用ioctl與核心交換資料

1.前言 使用ioctl系統呼叫是使用者空間向核心交換資料的常用方法之一,從ioctl這個名稱上看,本意是針對i o裝置進行的控制操作,但實際並不限制是真正的i o裝置,可以是任何乙個核心裝置即可。2.基本過程 在核心空間中ioctl是很多核心操作結構的乙個成員函式,如檔案操作結構struct fi...

linux ioctl與核心交換資料

1.前言 使用ioctl系統呼叫是使用者空間向核心交換資料的常用方法之一,從ioctl這個名稱上看,本意是針對i o裝置進行的控制操作,但實際並不限制是真正的i o裝置,可以是任何乙個核心裝置即可。2.基本過程 在核心空間中ioctl是很多核心操作結構的乙個成員函式,如檔案操作結構struct fi...