小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

【百度分享】基于內(nèi)核模塊的測試代碼編寫(二)...

 orion360doc 2010-11-16
4. 用戶空間和內(nèi)核空間的交互

  在解決了在內(nèi)核空間置入可運(yùn)行代碼后,需要解決的是用戶空間和內(nèi)核空間的交互。具體來說,需要達(dá)到以下三個(gè)功能:用戶空間的程序向內(nèi)核空間下的程序控制,用戶空間到內(nèi)核空間的數(shù)據(jù)傳遞,內(nèi)核空間到用戶空間的數(shù)據(jù)傳遞。以下小節(jié),都旨在利用系統(tǒng)提供給我們的各種接口,實(shí)現(xiàn)以上三個(gè)目標(biāo)中的一個(gè)或幾個(gè)。

4.1 printk

  printk是內(nèi)核用來記錄系統(tǒng)運(yùn)行日志的方法。對(duì)于用戶,可以通過dmesg命令查看近期的系統(tǒng)日志信息,或者直接訪問/var/log/kernel 查看內(nèi)核輸出的所有歷史log。在kernel module中調(diào)用printk是最簡單的傳遞信息到用戶空間的方法。printk函數(shù)的使用方法和用戶態(tài)下的printf類似,區(qū)別是可以通過 KERN_INFO等宏輸出從0-7的指定級(jí)別的log信息。常見的使用方式如下:
char myname[] = "chinacodec\n";
printk(KERN_INFO "Hello, world %s!\n", myname);

4.2 偽字符設(shè)備
  在linux中,用戶對(duì)設(shè)備的操作往往被抽象為對(duì)文件的操作。利用這一特性,可以通過注冊(cè)和實(shí)現(xiàn)偽字符設(shè)備到內(nèi)核,來實(shí)現(xiàn)用戶進(jìn)程和內(nèi)核空間的交互。當(dāng)在用戶空間執(zhí)行對(duì)該偽設(shè)備的open/read/write/ioctl/mmap/release等操作時(shí),這些被復(fù)用的系統(tǒng)調(diào)用就會(huì)使進(jìn)程從用戶態(tài)進(jìn)入到內(nèi)核態(tài),從而在內(nèi)核中完成事先注冊(cè)的操作,當(dāng)然可以包括對(duì)KAPI的調(diào)用等。

  具體方法是,首先,在kernel module中通過register_chrdev注冊(cè)一種偽字符設(shè)備到內(nèi)核,參數(shù)包括:設(shè)備的major號(hào),需要和系統(tǒng)已有設(shè)備不沖突;設(shè)備的名稱name;文件操作函數(shù)集fops。register_chrdev的定義如下:
int register_chrdev(unsigned int major, const char *name, struct file_operations *fops);

  其中,結(jié)構(gòu)file_operations中包含一系列的函數(shù)指針,對(duì)應(yīng)每種系統(tǒng)調(diào)用(包含read/write/open等),使用中,可以用如下的方式賦值(而不必為每一個(gè)元素都賦值),那些未顯式賦值的元素被賦值為null。

static struct file_operations fops = {
.read = device_read,
.write = device_write,
.ioctl = device_ioctl,
.open = device_open,
.release = device_release
};

  register_chrdev一般在kernel module中的init函數(shù)中執(zhí)行,當(dāng)insmod這個(gè)module時(shí),設(shè)備就被注冊(cè)到內(nèi)核中。然后,用戶就可以通過mknod命令可以創(chuàng)建對(duì)應(yīng)的字符設(shè)備文件。然后通過open/write/read/ioctl/mmap/release等系統(tǒng)調(diào)用以訪問設(shè)備文件的方式,訪問該設(shè)備。每種調(diào)用都會(huì)執(zhí)行到在注冊(cè)設(shè)備時(shí)注冊(cè)的對(duì)應(yīng)的文件操作函數(shù)。此外,對(duì)應(yīng)于register_chrdev,從內(nèi)核卸載該偽設(shè)備驅(qū)動(dòng)的函數(shù)為 unregister_chrdev。

  以ioctl為例,當(dāng)以上面的file_operations注冊(cè)了偽字符設(shè)備后,當(dāng)用戶對(duì)偽設(shè)備文件執(zhí)行ioctl后,調(diào)用會(huì)進(jìn)入內(nèi)核態(tài),執(zhí)行 device_ioctl函數(shù)。如果我們?cè)谧远x的device_ioctl函數(shù)中去調(diào)用KAPI,就實(shí)現(xiàn)了用戶進(jìn)程對(duì)KAPI的訪問。

4.3 普通文件讀寫 

內(nèi)核態(tài)中,可以完成對(duì)用戶文件系統(tǒng)任意文件的訪問。因此,可以在內(nèi)核態(tài)將要輸出的信息寫入文件,寫入后用戶態(tài)程序直接讀取文件就可以完成從內(nèi)核空間向用戶空間的數(shù)據(jù)傳遞。但是在內(nèi)核態(tài)下,對(duì)文件進(jìn)行訪問的調(diào)用函數(shù)和用戶態(tài)下的系統(tǒng)調(diào)用有所區(qū)別。通常的使用方法是通過filp_open打開文件,然后利用獲得的文件指針得到文件操作函數(shù),以讀取和寫入文件,基本代碼如下:
tmp _filp = filp_open(dst_file_name, O_RDWR | O_CREAT, 00);

tmp _copied = dst_filp->f_op->write(tmp_filep, buffer, size, offset);

tmp _len = dst_filp->f_op->read(tmp _filep, buffer, size, offset);

  因?yàn)槭窃趦?nèi)核中對(duì)文件操作,所以為了通過系統(tǒng)調(diào)用中對(duì)緩沖區(qū)內(nèi)存地址參數(shù)的檢查,需要修改檢查允許范圍。方法是在read或write操作前通過set_fs擴(kuò)大允許空間,操作后再通過setfs恢復(fù)到此前的允許范圍,具體方法是:

orig_fs = get_fs();
set_fs(KERNEL_DS);
//write or read
set_fs(orig_fs);

4.4 Proc文件系統(tǒng)

  proc文件系統(tǒng),是當(dāng)前內(nèi)核或內(nèi)核模塊,和用戶交互的主要方式,它通過將虛擬的文件系統(tǒng)掛載在/proc下,利用虛擬文件讀寫在用戶和內(nèi)核態(tài)間傳遞信息。通過內(nèi)核模塊,可以向/proc下注冊(cè)新的文件,指定用戶讀寫該文件時(shí)的回調(diào)函數(shù);這樣,當(dāng)用戶讀寫該文件時(shí),工作在內(nèi)核態(tài)的回調(diào)函數(shù)就可以執(zhí)行信息交互的有關(guān)工作。

  向內(nèi)核中注冊(cè)/proc下文件的調(diào)用是create_proc_entry,創(chuàng)建中需要指定文件名,訪問權(quán)限和父節(jié)點(diǎn)名,返回為指向 proc_dir_entry結(jié)構(gòu)的指針。通過該返回指針,可以進(jìn)一步修改文件的用戶id,組id,綁定的內(nèi)核數(shù)據(jù)等;但最為關(guān)鍵的是可以指定用戶讀或?qū)懺撐募r(shí),在內(nèi)核中被執(zhí)行的回調(diào)函數(shù)。下面是一個(gè)向proc文件系統(tǒng)中注冊(cè)新文件的示例:

static int __init proc_module_init(void){
entry = create_proc_entry("astring", 0644, myprocroot);
if (entry) {
entry->data = &string_var;
entry->read_proc = &string_read_proc;
entry->write_proc = &string_write_proc;
}
return 0
}
static void __exit procfs_exam_exit(void){
remove_proc_entry("astring", myprocroot);
remove_proc_entry("myproctest", NULL);
}
//read proc
int string_read_proc(char *page, char **start, off_t off,
int count, int *eof, void *data){
count = sprintf(page, "%s", (char *)data);
return count;
}
//write proc
int string_write_proc(struct file *file, const char __user *buffer,
unsigned long count, void *data){
if (count > STR_MAX_SIZE) {
count = 255;
}
copy_from_user(data, buffer, count);
return count;
}

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多