GB | BIG5
|
| 首頁 > 編程技術 > 其它 > 正文 |
 |
| FreeBSD4.0 動態內核鏈接機制(KLD)編程指南 |
| 本文出自: http://www.asfocus.com (2001-07-04 09:04:00) |
作者:Andrew Reiter < mailto: arr@watson.org >
整理:小四 < mailto: scz@nsfocus.com >
出處:http://www.watson.org/~arr/
主頁:http://www.nsfocus.com
日期:2000-10-26
目錄:
★ 簡介
★ 所有KLD的共性
★ KLD系統調用實現框架
★ KLD字符型設備驅動程序實現框架
★ 參考資料
★ 簡介
本文的目的在介紹FreeBSD操作系統下基礎的KLD開發設計技術。
FreeBSD 3.1下提供過可加載內核模塊技術(LKM),FreeBSD 4.0下提供的動態內
核鏈接機制(KLD),可以簡單地理解成LKM的升級。採用KLD,可以增加系統調用、調
試設備驅動程序、提供訪問內核數據空間的方便接口。下面我們對比一下LKM和KLD:
--------------------------------------------------------------------------
1. LKM採用用戶態的鏈接器重定位二進制數據再壓入內核空間。
KLD機制由內核親自進行重定位操作
2. LKM採用特殊的數據結構,LKM Driver了解這種數據結構,並通過它與內核交互,
比如VFS LKM採用一個結構,該結構裡包含指向VFS TABLES的指針。
LKM的目的單純明確,很難將LKM代碼移植成真正的內核代碼。
KLD採用常規代碼,一個KLD文件可以不包含任何模塊,也可以包含多個模塊。每
個模塊均包含自初始化代碼,並完成自注冊。
KLD的代碼和內核代碼保持一致。很容易從內核中提取部分代碼移植成KLD代碼。
3. 現在KLD的依賴關系和版本信息從內核裡剝離出來,完全位模塊層。
--------------------------------------------------------------------------
這份指南直奔兩個KLD開發者感興趣的主題,希望你具有基本的FreeBSD內核知識
以及K & R C編程技能。必須提醒的是,例子代碼在FreeBSD 4.0下調試通過。下面我
們將要介紹的主題有三:
--------------------------------------------------------------------------
1. 所有KLD的共性
2. KLD系統調用實現框架
3. KLD字符型設備驅動程序實現框架
--------------------------------------------------------------------------
本文的目的是幫助那些正在學習KLD編程的朋友快速掌握KLD編程接口,進入更高
層次。
★ 所有KLD的共性
所有的KLD代碼都有一個主入口函數和一個宏,並且簡單地採用Makefile文件編譯。
--------------------------------------------------------------------------
1. 主入口函數,或者說加載/卸載句柄
2. DECLARE_MODULE()宏
3. 利用Makefile文件進行編譯
--------------------------------------------------------------------------
下面是一個典型的主入口函數:
--------------------------------------------------------------------------
static int helloworld_load ( module_t mod, int what, void * arg )
{
int err = 0;
switch ( what )
{
case MOD_LOAD:
/*
* uprintf() 是內核空間函數,類似printf()。當在內核空間使用
* printf()時,輸出內容需要用dmesg查看。uprintf()將直接輸出到
* 當前正在使用的tty上
*/
printf( "MOD_LOAD: dmesg -c test\n" );
uprintf( "System call loaded at slot: %d\n", syscall_num );
break;
case MOD_UNLOAD:
printf( "MOD_UNLOAD: dmesg -c test\n" );
uprintf( "System call unloaded from slot: %d\n", syscall_num );
break;
case MOD_SHUTDOWN:
uprintf( "System shutdown\n" );
break;
default:
err = EINVAL;
break;
} /* end of switch */
return( err );
} /* end of helloworld_load */
--------------------------------------------------------------------------
該函數類似Linux下的init_module和cleanup_module,注意無論加載/卸載KLD,都要
經過該函數。函數名字自己定義,將來作為函數指針傳遞給DECLARE_MODULE()宏。當
使用kldload/kldunload加載/卸載KLD的時候,helloworld_load()被調用。
在/usr/include/sys/module.h裡定義了一個函數指針類型:
typedef int ( * modeventhand_t ) ( module_t mod, int /*modeventtype_t*/ what, void * arg );
helloworld_load()正是modeventhand_t型常量,從名字看,模塊--事件--句柄,有
意思。
typedef struct module * module_t;
module_t mod是指向module結構的指針。module結構按照鏈表方式組織,可以從結構
中獲取指向其它module結構的指針。結構成員還包含諸如KLD ID號之類的有用信息。
int what實際是枚舉類型變量,modeventtype_t( enum modeventtype ),目前只有
三個有效值:
MOD_LOAD 執行kldload時被調用
MOD_UNLOAD 執行kldunload時被調用
MOD_SHUTDOWN shutdown時被調用
DECLARE_MODULE()對KLD很重要,然而通常所見並不是DECLARE_MODULE(),有兩個
宏封裝了它,使得編程更加方便。/usr/include/sys/module.h裡定義了
DECLARE_MODULE 宏:
--------------------------------------------------------------------------
#define DECLARE_MODULE(name, data, sub, order) \
SYSINIT(name##module, sub, order, module_register_init, &data) \
struct __hack
--------------------------------------------------------------------------
下面我們來看看各個參數的意義:
name 模塊名,注意這個不是KLD名,KLD名就是將來Makefile編譯產生的靜態文件名
模塊名將在SYSINIT調用中被使用。下面這個例子清楚表明了KLD名和模塊名的
區別。
[root@ /usr/home/scz/src]> kldstat -v -i 4
Id Refs Address Size Name
4 1 0xc0ae2000 2000 flkm_2 <-- 這是KLD名
Contains modules:
Id Name
84 donothing <-- 這是模塊名
85 helloworld <-- 這也是模塊名
[root@ /usr/home/scz/src]>
data 指向 struct moduledata 的指針。/usr/include/sys/module.h裡定義了該結
構:
--------------------------------------------------------------------------
/*
* Struct for registering modules statically via SYSINIT.
*/
typedef struct moduledata
{
char *name; /* module name */
modeventhand_t evhand; /* event handler */
void *priv; /* extra data */
} moduledata_t;
--------------------------------------------------------------------------
name 模塊名
evhand 對應上面介紹過的helloworld_load()
sub 該參數的有效取值參看/usr/include/sys/kernel.h文件裡定義的
enum sysinit_sub_id {} 枚舉列表。我們將要介紹的兩種類型的KLD固定採用
SI_SUB_DRIVERS
order 該參數的有效取值參看/usr/include/sys/kernel.h文件裡定義的
enum sysinit_elem_order {} 枚舉列表。我們將要介紹的兩種類型的KLD固定採用
SI_ORDER_MIDDLE
一般並不直接使用DECLARE_MODULE()宏,常見的是SYSCALL_MODULE和DEV_MODULE,它
們分別對DECLARE_MODULE進行了封裝,這種封裝便開發KLD代碼,也便理解KLD代
碼。
/usr/include/sys/sysent.h裡定義了 SYSCALL_MODULE 宏
--------------------------------------------------------------------------
#define SYSCALL_MODULE(name, offset, new_sysent, evh, arg) \
static struct syscall_module_data name##_syscall_mod = { \
evh, arg, offset, new_sysent \
}; \
\
static moduledata_t name##_mod = { \
#name, \
syscall_module_handler, \
&name##_syscall_mod \
}; \
DECLARE_MODULE(name, name##_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE)
--------------------------------------------------------------------------
name 模塊名
offset 對應系統調用號。通常利用KLD機制增加系統調用的時候,並沒有保留系統調
用號供它使用。正確的做法是指定NO_SYSCALL,此時系統將動態選取一個可
用系統調用號對應我們增加的系統調用
new_sysent
指向struct sysent結構的指針,每個系統調用都對應一個這樣的結構,結構
裡定義了形參個數和系統調用實現體指針。
evh 對應上面介紹過的helloworld_load()
arg 用struct syscall_module_data結構,通常該參數設置成NULL
/usr/include/sys/conf.h裡定義了 DECLARE_MODULE 宏
--------------------------------------------------------------------------
#define DEV_MODULE(name, evh, arg) \
static moduledata_t name##_mod = { \
#name, \
evh, \
arg \
}; \
DECLARE_MODULE(name, name##_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE)
--------------------------------------------------------------------------
name 模塊名
evh 類似上面介紹過的helloworld_load()
arg 用struct module_data結構,通常該值設置成NULL
無論開發什樣的KLD,至少有一個加載/卸載句柄(主入口函數),至少有一個上
面介紹的宏。在這份編程指南裡不討論更復雜的情形,
http://thc.pimmel.com/files/thc/bsdkern.html討論了更多的復雜的編程技巧,如
果你對KLD編程想進一步的話,請參看上述鏈接。
我們不必擔心Makefile的復雜性,/usr/share/mk目錄下提供了許多普適性很強
的預設置的Makefile,可以簡單採用.include <...>命令引用它們。此次感興趣的是
/usr/share/mk/bsd.kmod.mk文件,建議你先閱讀一下該文件。可能需要的設置是
--------------------------------------------------------------------------
SRCS = flkm.c
KMOD = flkm
KO = ${KMOD}.ko
.include
--------------------------------------------------------------------------
SRCS 源文件名
KMOD KLD名,注意不是模塊名
★ KLD系統調用實現框架
下面是一個非常簡單的例子,演示如何利用動態內核鏈接機制增加系統調用。除
了必須有一個加載/卸載句柄和一個DECLARE_MODULE宏(或者針對它的封裝),還有四
點需要注意:
--------------------------------------------------------------------------
1. 如果增加的系統調用需要形參,必須採用自定義結構組織這些形參
2. 系統調用實現體必須是static int型的函數
3. 根據系統調用具體實現組織struct sysent結構
4. 設置offset變量為NO_SYSCALL
--------------------------------------------------------------------------
所有的系統調用,在內核裡的函數實現體只有兩個形參:
--------------------------------------------------------------------------
1. struct proc *
2. void *
--------------------------------------------------------------------------
來自用戶空間的形參需要定義到一個自定義結構中,比如:
--------------------------------------------------------------------------
/*
* 來自用戶空間的syscall()將把函數形參組織到這個結構裡,如果對應系統調用並
* 不需要形參,則無須定義這樣一個結構,該結構完全為了傳遞形參
*/
struct helloworld_args
{
char * str;
int val;
};
--------------------------------------------------------------------------
一般libc會將用戶空間的形參組織到類似這樣的結構中。而我們通過KLD增加的系統
調用沒有經過libc的封裝處理,所以只能使用syscall(2)直接調用這個新增加的系統
調用,面會有例子演示。
下面是一個系統調用內核函數實現體:
--------------------------------------------------------------------------
/* 這是我們將要增加的系統調用 */
static int helloworld ( struct proc * p, struct helloworld_args * arg )
{
int err = 0; /* Generic return(err) */
int size = 0;
char kernel_str[ 1024 + 1 ]; /* Holds kernel land copy of arg->str */
/*
* _IMPORTANT_:
*
* When one has a contiguous set of data and wish to copy this from
* user land to kernel land (or vice versa) the copy(9) functions
* are recommended for doing this.
*/
/*
* 不知道這裡是否和Linux一樣,可以直接訪問用戶空間?看面代碼意思是
* 可以的,只不過不建議直接訪問用戶空間而已
*
* 剛才自己增加了一點代碼驗証這個問題,答案是肯定的
* 參看flkm_call.c的演示代碼
*
* 注意拷貝方向,源/目的與常見函數不一樣
*/
err = copyinstr( arg->str, &kernel_str, 1024, &size );
if ( err == EFAULT )
{
return( err );
}
uprintf( "hello world\n" );
uprintf( "The user string passed was: %s\n", arg->str );
uprintf( "The value passed was: %d\n", arg->val );
uprintf( "The kernel string passed was: %s\n", kernel_str );
return( 0 );
} /* end of helloworld */
--------------------------------------------------------------------------
該系統調用取出來自用戶空間的形參,一個字符串和一個整型變量,並在當前使用的
tty(發生該系統調用時進程所使用的終端)上顯示它們。
接下來需要根據系統調用具體實現組織一個struct sysent結構,該結構在
/usr/include/sys/sysent.h文件裡定義:
--------------------------------------------------------------------------
struct sysent /* system call table */
{
int sy_narg; /* number of arguments */
sy_call_t * sy_call; /* implementing function */
};
--------------------------------------------------------------------------
每個系統調用對應有一個struct sysent結構,sy_narg定義來自用戶空間的形參個數,
顯然只有函數指針對C調用風格是不夠的,想想*printf()這種可變參數的函數。
sy_call對應系統調用內核函數實現體。/usr/include/sys/sysent.h文件裡定義了:
typedef int sy_call_t __P( ( struct proc *, void * ) );
下面是該結構的例子:
--------------------------------------------------------------------------
/*
* on FreeBSD every system call is described by a sysent structure, which
* holds the corresponding system call function (here helloworld) and the
* appropriate count of arguments (here 2)
*/
static struct sysent helloworld_sysent =
{
2, /* sy_narg */
helloworld /* sy_call */
};
--------------------------------------------------------------------------
現在,如果你還記得前面提到過的,最應該提供一個offset參數到
SYSCALL_MODULE宏。這個參數對應系統調用號,作為通過KLD動態增加的新系統調用,
應該設置該值成NO_SYSCALL,意味著由系統找出下一個可用系統調用號,當然你可以
明確指定一個系統調用號,不推薦這樣做。可以直接傳遞NO_SYSCALL給宏,然而最好
給一個靜態整型變量賦值NO_SYSCALL,傳遞一個指針給宏,KLD加載成功系統會將
最終選取的系統調用號回填到這個靜態整型變量。順便提一句,
/usr/include/sys/syscall.h裡定義了已經實現的系統調用號列表。是,我們只需
要這樣一行代碼:
--------------------------------------------------------------------------
/*
* every system call has a certain number (called slot or syscall_num on BSD).
* This number represents the index in the global sysent list holding every
* syscall. BSD is able to search a free slot for a syscall (by setting it
* to NO_SYSCALL) which is used here.
*/
static int syscall_num = NO_SYSCALL;
--------------------------------------------------------------------------
NO_SYSCALL在/usr/include/sys/sysent.h裡定義,值為-1。
我們已經介紹完通過KLD動態增加一個系統調用的必須操作,剩下的就是編寫加
載/卸載句柄,並調用SYSCALL_MODULE()宏:
--------------------------------------------------------------------------
/*
* 該函數類似Linux下的init_module和cleanup_module
* 函數名字自己定義,將來作為函數指針傳遞給SYSCALL_MODULE()宏
*/
static int helloworld_load ( module_t mod, int what, void * arg )
{
int err = 0;
switch ( what )
{
case MOD_LOAD:
/*
* uprintf() 是內核空間函數,類似printf()。當在內核空間使用
* printf()時,輸出內容需要用dmesg查看。uprintf()將直接輸出到
* 當前正在使用的tty上
*/
printf( "MOD_LOAD: dmesg -c test\n" );
uprintf( "System call loaded at slot: %d\n", syscall_num );
break;
case MOD_UNLOAD:
printf( "MOD_UNLOAD: dmesg -c test\n" );
uprintf( "System call unloaded from slot: %d\n", syscall_num );
break;
case MOD_SHUTDOWN:
uprintf( "System shutdown\n" );
break;
default:
err = EINVAL;
break;
} /* end of switch */
return( err );
} /* end of helloworld_load */
SYSCALL_MODULE( helloworld, &syscall_num, &helloworld_sysent, helloworld_load, NULL );
--------------------------------------------------------------------------
Makefile文件很簡單,如下:
--------------------------------------------------------------------------
SRCS = flkm.c
KMOD = flkm
KO = ${KMOD}.ko
.include
--------------------------------------------------------------------------
make -f flkm.mk產生flkm文件,可以用file flkm查看文件類型。以root身份執行
kldload -v ./flkm加載該KLD文件。
下面是從用戶空間通過syscall(2)調用helloworld系統調用的例子:
--------------------------------------------------------------------------
#include
#include
#include
#include
int main ( int argc, char * argv[] )
{
int syscall_num;
struct module_stat stat;
char hello[] = "I'll be back.";
stat.version = sizeof( stat );
/*
modstat will retrieve the module_stat structure for our module named
helloworld (see the SYSCALL_MODULE macro which sets the name to syscall)
*/
modstat( modfind( "helloworld" ), &stat );
/* extract the slot (syscall) number */
syscall_num = stat.data.intval;
/* 必須在調用前加載內核模塊,否則core dump,程序沒有做邊界檢查 */
return( syscall( syscall_num, hello, 1977 ) );
} /* end of main */
--------------------------------------------------------------------------
★ KLD字符型設備驅動程序實現框架
絕大多數Unix系統支持字符型設備驅動程序,它們通常不對應真實物理設備,僅
僅提供一種對偽設備的讀/寫/IO控制接口。類似前面介紹增加系統調用,下面將逐步
介紹如何編寫KLD模式的字符設備驅動程序,幸運的是,你會發現創建一個非常有用
的字符型設備驅動程序並不困難。
下面4點對所有字符型設備驅動程序實現都是必要的:
--------------------------------------------------------------------------
1. 定義一個struct cdevsw結構
2. 設備回調函數
3. 加載/卸載句柄
4. DEV_MODULE()宏
--------------------------------------------------------------------------
/usr/include/sys/conf.h裡定義了 struct cdevsw 結構
--------------------------------------------------------------------------
/*
* Character device switch table
*/
struct cdevsw
{
d_open_t *d_open; /* Func. pointer to dev open function */
d_close_t *d_close; /* Func. pointer to dev close function */
d_read_t *d_read; /* Func. pointer to dev read function */
d_write_t *d_write; /* Func. pointer to dev write function */
d_ioctl_t *d_ioctl; /* Func. pointer to dev ioctl function */
d_poll_t *d_poll; /* Func. pointer to dev poll function */
d_mmap_t *d_mmap; /* Func. pointer to dev mmap function */
d_strategy_t *d_strategy; /* Func. pointer to dev strategy func. */
const char *d_name; /* base device name, e.g. 'vn' */
int d_maj; /* Device major value */
d_dump_t *d_dump; /* Func. pointer to dev dump function */
d_psize_t *d_psize; /* Func. pointer to dev psize function */
u_int d_flags; /* D_TAPE, D_DISK, D_TTY, D_MEM */
int d_bmaj; /* Block Device major value (used by D_DISK) */
};
--------------------------------------------------------------------------
顯然該結構類似Linux下的struct file_operations結構,定義了設備相關的回調函
數。並不需要提供所有的回調函數,如果你想提供一個只寫設備,不但/dev/目錄下
的設備文件權限設置成只寫,更重要的是struct cdevsw結構中d_read成員賦值
noread。為了簡化討論,在我們的例子中,只提供了d_open、d_close、d_read和
d_write四個回調函數,我們的struct cdevsw結構如下:
--------------------------------------------------------------------------
static struct cdevsw chardev_cdevsw =
{
chardev_open,
chardev_close,
chardev_read,
chardev_write,
noioctl,
nopoll,
nommap,
nostrategy,
"chardev", /* 這裡和/dev/下的名字不必一致 */
38, /* /usr/src/sys/conf/majors 主設備號是重要標識 */
nodump,
nopsize,
D_TTY, /* D_TAPE, D_DISK, D_TTY, D_MEM */
-1 /* Block Device major value (used by D_DISK) */
};
--------------------------------------------------------------------------
/usr/share/examples/kld/cdev/目錄下提供了其他一些字符型設備驅動程序例子。
注意我們的例子採用38作為主設備號,/usr/src/sys/conf/majors文件裡對此定義如
下:
38 lkm ssigned to Loadable Kernel Modules
假設將來來自應用層的調用步驟如下:
open(2) -> write(2) -> read(2) -> close(2)
首先打開/dev/目錄下的設備文件,然寫一個字符串到該設備,攜入的字符串被保
存在驅動程序靜態緩沖區中,稍應用程序會讀取這個字符串,最關閉前面所打開
的設備文件。
--------------------------------------------------------------------------
/*******************************************************************
* *
* Function Prototype *
* *
*******************************************************************/
static int chardev_close ( dev_t dev, int cflag, int devtype, struct proc * p );
static int chardev_open ( dev_t dev, int oflags, int devtype, struct proc * p );
static int chardev_read ( dev_t dev, struct uio * uio, int ioflag );
static int chardev_write ( dev_t dev, struct uio * uio, int ioflag );
/*******************************************************************
* *
* Static Global Var *
* *
*******************************************************************/
/*
* Used as the variable that is the reference to our device
* in devfs... we must keep this variable sane until we
* call kldunload.
*/
static dev_t chardev;
static char chardev_buf[ 512 + 1 ]; /* 設備驅動程序維護的內部緩沖區 */
static int chardev_buflen;
/*----------------------------------------------------------------------*/
/*
* Simply "closes" our device that was opened with chardev_open.
*/
static int chardev_close ( dev_t dev, int cflag, int devtype, struct proc * p )
{
memset( chardev_buf, 0, 513 );
chardev_buflen = 0;
uprintf( "Closing device \"chardev\"\n" );
return( 0 );
} /* end of chardev_close */
/*
* This open function soley checks for open(2) flags. We are only
* allowing for the flags to be O_RDWR for the purpose of showing
* how one could only allow a read-only device, for example.
*/
static int chardev_open ( dev_t dev, int oflags, int devtype, struct proc * p )
{
memset( chardev_buf, 0, 513 );
chardev_buflen = 0;
uprintf( "Opened device \"chardev\" successfully\n" );
return( 0 );
} /* end of chardev_open */
/*
* The read function just takes the buf that was saved
* via chardev_write() and returns it to userland for
* accessing.
*/
static int chardev_read ( dev_t dev, struct uio * uio, int ioflag )
{
int err = 0;
if ( chardev_buflen <= 0 )
{
err = -1;
}
else
{
/* 對象是以NULL結尾的串,長度包括結尾的NULL */
/* copy buf to userland */
err = copystr( chardev_buf, uio->uio_iov->iov_base, 513, &chardev_buflen );
}
return( err );
} /* end of chardev_read */
/*
* chardev_write takes in a character string and saves it
* to buf for later accessing.
*/
static int chardev_write ( dev_t dev, struct uio * uio, int ioflag )
{
int err = 0;
/* 對象是以NULL結尾的串,長度包括結尾的NULL */
err = copyinstr( uio->uio_iov->iov_base, chardev_buf, 513, &chardev_buflen );
if ( err != 0 )
{
uprintf( "Write to \"chardev\" failed\n" );
}
return( err );
} /* end of chardev_write */
--------------------------------------------------------------------------
現在你該相信我了吧,實現一個簡單的字符型設備驅動程序相當容易。通過這種
技術向內核空間傳遞數據,對比sysctl能夠實現的功能。man 3 sysctl,
man 8 sysctl看看。
下面是這個字符型設備驅動程序的加載/卸載句柄。對設備驅動程序,在
MOD_LOAD流程那裡,必須調用make_dev()向設備文件系統(devfs)中注冊我們的設備。
devfs是設備文件系統,提供訪問FreeBSD內核中設備名字空間的能力。在
MOD_UNLOAD流程那裡,必須調用destroy_dev(),形參來自make_dev()的返回值
(dev_t型)。
--------------------------------------------------------------------------
/*
* 該函數類似Linux下的init_module和cleanup_module
* 函數名字自己定義,將來作為函數指針傳遞給DEV_MODULE()宏
*/
static int chardev_load ( module_t mod, int what, void * arg )
{
int err = 0;
switch ( what )
{
case MOD_LOAD:
chardev = make_dev( &chardev_cdevsw,
0,
UID_ROOT,
GID_WHEEL,
0600,
"chardev" );
uprintf( "chardev loaded\n" );
break;
case MOD_UNLOAD:
destroy_dev( chardev );
uprintf( "chardev unloaded\n" );
break;
case MOD_SHUTDOWN:
uprintf( "System shutdown\n" );
break;
default:
err = EINVAL;
break;
} /* end of switch */
return( err );
} /* end of chardev_load */
DEV_MODULE( chardev, chardev_load, NULL );
--------------------------------------------------------------------------
無論什類型的KLD,必須有一個*_MODULE宏,至少指明本模塊加載/卸載句柄以及何
種類型。如上最一行代碼所示。
至此一個非常簡單的字符型設備驅動程序框架完成了。編寫類似前面的Makefile,
編譯產生KLD靜態文件,並在/dev/目錄下創建設備文件:
[root@ /usr/home/scz/src]> mknod /dev/chardev c 38 0
[root@ /usr/home/scz/src]> ls -l /dev/chardev
crw-r--r-- 1 root wheel 38, 0 Oct 28 04:56 /dev/chardev
[root@ /usr/home/scz/src]>
這個KLD被加載,open()、close()、read()和write()系統調用都可以用
/dev/chardev設備文件。記得在KLD被卸載出內核前調用close()關閉該設備,否則,
嘿嘿,你死定了。
正如簡介裡所言,本文講述的是KLD編寫基礎知識,相當簡短。再深入的技巧請
翻閱THC的技術資料。
★ 參考資料
1) man 4 kld
關KLD的man手冊
2) http://thc.pimmel.com/files/thc/bsdkern.html
THC編寫的利用LKM/KLD攻擊FreeBSD的經典文獻
3) /usr/share/mk/*
缺省Makefile
4) http://subterrain.net/~awr/KLD-Tutorial/code/kld-examples.tar.gz
文中所附例子代碼
5) /usr/share/examples/kld/cdev/
系統自帶的其他字符型設備驅動程序例子
(http://www.fanqiang.com)
進入【UNIX論壇】
|
|
| 相關文章 |
|
===閩=== |
|
|
 |
★ 樊強制作 歡迎分享 ★ |