linux2.6内核compat_ioctl函数
一、內(nèi)核原型(linux2.6.28-7)
???? long (*compat_ioctl)(struct tty_struct *tty, struct file * file,
???????????????????? unsigned int cmd, unsigned long arg);
???? implement ioctl processing for 32 bit process on 64 bit system
???? Optional
二、What is compat_ioctl
There is one more method called as "compat_ioctl()" that a 64 bit driver has to implement. It gets called when 64 bit kernel gets ioctl() call from 32 bit user.
Tasks to be done by compat_ioctl() :
1. Acquire BKL, since kernel calls compat_ioctl without BKL.
2. 32 to 64 bit conversion for long and pointer objects passed by user
3. Process input data, get results.
4. 64 to 32 bit conversion in order to pass the output data back to user
5. Release BKL
三、中文檔案
Linux 64Bit 下的 ioctl和compat_ioctl ioctl32 Unknown cmd fd
前段時(shí)間將我們的程序移植到Mips64的Linux 2.6環(huán)境下,做可行性試驗(yàn)。
由于用戶態(tài)程程序規(guī)模太大,而且之前沒有對(duì)64bit的情況做考慮,
所以,用戶態(tài)程序任然使用32位模式編譯,內(nèi)核運(yùn)行在64bit。
我們有一個(gè)內(nèi)核模塊之前是在2.4.21下的,拿到2.6后,把部分api做了些更改,直接編譯并加載。
用戶態(tài)程序在調(diào)用ioctl的時(shí)候,總是失敗。
dmesg看一下內(nèi)核信息,有如下類似信息:
ioctl32(add_vopp:9767): Unknown cmd fd(3) cmd(80048f00){00} arg(ff240ae0)
后來在內(nèi)核中的ioctl中添加debug代碼,發(fā)現(xiàn)根本沒調(diào)用到內(nèi)核中的ioctl函數(shù)。
經(jīng)過查找,發(fā)現(xiàn)了以下資源
The new way of ioctl()
32 bit user/64 bit kernel
What is compat_ioctl ()?
more on compat_ioctl
?
產(chǎn)生問題的分析:
我們的程序通過Linux的
ssize_t read(int fd, void *buf, size_t count);?
系統(tǒng)調(diào)用從虛擬設(shè)備中讀取內(nèi)核中。
使用
int ioctl(int fd, int request, ...);
系統(tǒng)調(diào)用來對(duì)設(shè)備進(jìn)行控制,并傳遞一些數(shù)據(jù)。
ioctl是我們擴(kuò)展非標(biāo)準(zhǔn)系統(tǒng)調(diào)用的手段。
read系統(tǒng)調(diào)用,對(duì)應(yīng)內(nèi)核中struct file_operations 結(jié)構(gòu)中的
ssize_t (*read) (struct file *filp, char *buf, size_t count, loff_t *f_pos)
當(dāng)用戶態(tài)位32bit, 內(nèi)核位64bit的時(shí)候,
用戶態(tài)的程序,和內(nèi)核態(tài)的程序,在數(shù)據(jù)類型不一致。
比如指針,用戶態(tài)的指針實(shí)際上是unsigned long 4Byte
內(nèi)核態(tài)的指針是unsigned ong: 8Byte.
對(duì)于這種不一致,從用戶態(tài)陷入內(nèi)核態(tài)的時(shí)候,大部分標(biāo)準(zhǔn)調(diào)用的參數(shù)已經(jīng)做了相應(yīng)的轉(zhuǎn)化。
不存在問題。比如ssize_t,內(nèi)核態(tài)和用戶態(tài)不一致,
對(duì)于這種已知類型,內(nèi)核代碼已經(jīng)做了轉(zhuǎn)換,因?yàn)樗涝撛趺崔D(zhuǎn),
所以我們的程序調(diào)用read,write,等系統(tǒng)調(diào)用,都能正確的返回結(jié)果。
再來看看ioctl系統(tǒng)調(diào)用,
用戶態(tài)系統(tǒng)調(diào)用,int ioctl(int fd, int request, ...);
內(nèi)核中對(duì)應(yīng)的函數(shù)
int (*ioctl) (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
request是請(qǐng)求號(hào),用來區(qū)分不同得到請(qǐng)求。后面的可變參數(shù)隨便選。
如果想傳入或傳出自定義結(jié)構(gòu),可以傳個(gè)指針類型。
如果沒數(shù)據(jù)傳遞,可以空著。
當(dāng)然也可以傳這個(gè)int或char之類的類型來向內(nèi)核傳遞數(shù)據(jù)。
問題來了,內(nèi)核不知道你傳遞的是那種類型,他無(wú)法給你轉(zhuǎn)化。
總結(jié)一下:
1). Linux2.6對(duì)64bit kernel 在struct file_operation中增加了一個(gè)成員
long (*compat_ioctl) (struct file *filp, unsigned int cmd, unsigned long arg);
用來提供32位用戶態(tài)程序的方法,
可以通過filp->f_dentry->d_inode方法獲得。
3). 關(guān)于ioctl的請(qǐng)求號(hào),經(jīng)常是通過宏定義生成的 舉例如下:
#define IoctlGetNetDeviceInfo??? _IOWR(Ioctl_Magic, 1, struct_NetDeviceInfo)
#define IoctlNetQueueInit????????? _IOR(Ioctl_Magic, 4, struct_NetDeviceListen)
#define IoctlNetQueueDestroy???? _IO(Ioctl_Magic, 5)
注意_IOWR和IOR宏, 他們的最后一個(gè)參數(shù)是一個(gè)數(shù)據(jù)類型,展開時(shí)會(huì)包含sizeof()操作,
于是32bit用戶態(tài)程序和64bit內(nèi)核之間,生成的ioctl的request號(hào)很可能就會(huì)不同,
在compat函數(shù)中switch()的時(shí)候,就會(huì)switch不到。
要想辦法避免:
提供64bit和32bit大小一致的結(jié)構(gòu)。
在用戶態(tài)下提供一個(gè)偽結(jié)構(gòu),偽結(jié)構(gòu)和內(nèi)核內(nèi)的結(jié)構(gòu)寬度一致。
用_IO宏,而不用_IOWR或_IOR宏,反正只是為了得到一個(gè)號(hào)碼,實(shí)際傳輸數(shù)據(jù)大小,自己心理有數(shù),內(nèi)核代碼處理好就行了。
4). 如果compat收到的最后參數(shù)arg是一個(gè)用戶態(tài)指針, 它在用戶態(tài)是32位的,在內(nèi)核中為了保證安全,
可以使用compat_ptr(art)宏將其安全的轉(zhuǎn)化為一個(gè)64位的指針(仍然是用戶指針)
轉(zhuǎn)載于:https://www.cnblogs.com/reality-soul/p/6124846.html
總結(jié)
以上是生活随笔為你收集整理的linux2.6内核compat_ioctl函数的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: IIS安装与MVC程序部署
- 下一篇: linux 其他常用命令