当前位置:  技术问答>linux和unix

【百度分享】基于内核模块的测试代码编写(二)

    来源: 互联网  发布时间:2016-10-31

    本文导语:  本帖最后由 fvceww 于 2010-11-11 14:19:19 编辑 上篇回顾:【百度分享】基于内核模块的测试代码编写(一) 4. 用户空间和内核空间的交互      在解决了在内核空间置入可运行代码后,需要解决的是用户空间和内核空...

本帖最后由 fvceww 于 2010-11-11 14:19:19 编辑
上篇回顾:【百度分享】基于内核模块的测试代码编写(一

4. 用户空间和内核空间的交互 

    在解决了在内核空间置入可运行代码后,需要解决的是用户空间和内核空间的交互。具体来说,需要达到以下三个功能:用户空间的程序向内核空间下的程序控制,用户空间到内核空间的数据传递,内核空间到用户空间的数据传递。以下小节,都旨在利用系统提供给我们的各种接口,实现以上三个目标中的一个或几个。

4.1 printk

    printk是内核用来记录系统运行日志的方法。对于用户,可以通过dmesg命令查看近期的系统日志信息,或者直接访问/var/log/kernel 查看内核输出的所有历史log。在kernel module中调用printk是最简单的传递信息到用户空间的方法。printk函数的使用方法和用户态下的printf类似,区别是可以通过 KERN_INFO等宏输出从0-7的指定级别的log信息。常见的使用方式如下:
char myname[] = "chinacodecn";
printk(KERN_INFO "Hello, world %s!n", myname);

4.2 伪字符设备
    在linux中,用户对设备的操作往往被抽象为对文件的操作。利用这一特性,可以通过注册和实现伪字符设备到内核,来实现用户进程和内核空间的交互。当在用户空间执行对该伪设备的open/read/write/ioctl/mmap/release等操作时,这些被复用的系统调用就会使进程从用户态进入到内核态,从而在内核中完成事先注册的操作,当然可以包括对KAPI的调用等。

    具体方法是,首先,在kernel module中通过register_chrdev注册一种伪字符设备到内核,参数包括:设备的major号,需要和系统已有设备不冲突;设备的名称name;文件操作函数集fops。register_chrdev的定义如下:
int register_chrdev(unsigned int major, const char *name, struct file_operations *fops);

   其中,结构file_operations中包含一系列的函数指针,对应每种系统调用(包含read/write/open等),使用中,可以用如下的方式赋值(而不必为每一个元素都赋值),那些未显式赋值的元素被赋值为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函数中执行,当insmod这个module时,设备就被注册到内核中。然后,用户就可以通过mknod命令可以创建对应的字符设备文件。然后通过open/write/read/ioctl/mmap/release等系统调用以访问设备文件的方式,访问该设备。每种调用都会执行到在注册设备时注册的对应的文件操作函数。此外,对应于register_chrdev,从内核卸载该伪设备驱动的函数为 unregister_chrdev。

   以ioctl为例,当以上面的file_operations注册了伪字符设备后,当用户对伪设备文件执行ioctl后,调用会进入内核态,执行 device_ioctl函数。如果我们在自定义的device_ioctl函数中去调用KAPI,就实现了用户进程对KAPI的访问。

4.3 普通文件读写 

内核态中,可以完成对用户文件系统任意文件的访问。因此,可以在内核态将要输出的信息写入文件,写入后用户态程序直接读取文件就可以完成从内核空间向用户空间的数据传递。但是在内核态下,对文件进行访问的调用函数和用户态下的系统调用有所区别。通常的使用方法是通过filp_open打开文件,然后利用获得的文件指针得到文件操作函数,以读取和写入文件,基本代码如下:
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);

   因为是在内核中对文件操作,所以为了通过系统调用中对缓冲区内存地址参数的检查,需要修改检查允许范围。方法是在read或write操作前通过set_fs扩大允许空间,操作后再通过setfs恢复到此前的允许范围,具体方法是:

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

4.4 Proc文件系统

   proc文件系统,是当前内核或内核模块,和用户交互的主要方式,它通过将虚拟的文件系统挂载在/proc下,利用虚拟文件读写在用户和内核态间传递信息。通过内核模块,可以向/proc下注册新的文件,指定用户读写该文件时的回调函数;这样,当用户读写该文件时,工作在内核态的回调函数就可以执行信息交互的有关工作。

   向内核中注册/proc下文件的调用是create_proc_entry,创建中需要指定文件名,访问权限和父节点名,返回为指向 proc_dir_entry结构的指针。通过该返回指针,可以进一步修改文件的用户id,组id,绑定的内核数据等;但最为关键的是可以指定用户读或写该文件时,在内核中被执行的回调函数。下面是一个向proc文件系统中注册新文件的示例:

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;
}

后续请看:【百度分享】基于内核模块的测试代码编写(三)

|
收藏了。。

|
顶顶,收藏

|
xuexizhong

|
好的 好的

|
很好喜欢

|

|
真的很好

|
不错不错

|
不错不错 呵呵~~

|
不错不错 !!

|
谢谢分享。。。。。。

|
该回复于2011-01-27 08:55:16被版主删除

|
很好很强大

|
不懂啊!

|
不错不错、长知识

|
不错,感谢分享

|
谢谢分享

|
收藏

|
完全不懂啊。

|
谢谢分享···

|
不错,不错,好极了!!




味道!

    
 
 

您可能感兴趣的文章:

  • 【百度分享】基于内核模块的测试代码编写(三)
  • 【百度分享】基于内核模块的测试代码编写(一)
  • 『分享』从 2.4 到 2.6:Linux 内核可装载模块机制的改变对设备驱动的影响!!! (转载)
  • 【百度分享】Socket通讯模块压力及大数据对比工具开发之aperlib(二)
  • 【百度分享】Socket通讯模块压力及大数据对比工具开发之aperlib(八)
  • python发布模块的步骤分享
  • 【百度分享】Socket通讯模块压力及大数据对比工具开发之aperlib(三)
  • 【百度分享】Socket通讯模块压力及大数据对比工具开发之aperlib(七)
  • 【百度分享】Socket通讯模块压力及大数据对比工具开发之aperlib(一)
  • ubuntu12.04使用c编写php扩展模块教程分享
  • [百度分享]Bonding模块主要工作模式相关代码分析(一)
  • 用smtplib和email封装python发送邮件模块类分享
  • [百度分享]Bonding模块工作流程综述
  • [百度分享]Bonding 模块代码及主要工作模式分析(4)
  • [百度分享]Bonding 模块代码及主要工作模式分析(1)
  • [百度分享]Bonding 模块代码及主要工作模式分析(2)
  • [百度分享]Bonding 模块代码及主要工作模式分析(3)
  • [百度分享]Bonding模块主要工作模式相关代码分析(二)
  •  
    本站(WWW.)旨在分享和传播互联网科技相关的资讯和技术,将尽最大努力为读者提供更好的信息聚合和浏览方式。
    本站(WWW.)站内文章除注明原创外,均为转载、整理或搜集自网络。欢迎任何形式的转载,转载请注明出处。












  • 相关文章推荐
  • 自己编写sqlhelper类示例分享
  • vc6编写python扩展的方法分享
  • 将c#编写的程序打包成应用程序的实现步骤分享(安装,卸载) 图文
  • c#编写webservice服务引用实例分享
  • Oracle存储过程的编写经验与优化措施(分享)
  • 如何编写健壮的Bash脚本(经验分享)
  • ​docker之轻量虚拟化技术——docker实战分享
  • php利用腾讯ip分享计划获取地理位置示例分享
  • 点对点文件分享客户端 PeerProject
  • 网络文件分享 Giver
  • IM及文件分享软件 iptux
  • P2P分享软件 Alliance P2P
  • 文件分享软件 eMule Plus
  • P2P 文件分享软件 ShakesPeer
  • 分享页面内容插件 ContentShare
  • 社交分享按钮生成JS库 Socialite.js
  • P2P分享软件 Phex
  • 前端代码编辑和分享平台 RunJS
  • jQuery 分享按钮插件 Share Button
  • 昨天考过SCJP快乐大家分享
  • P2P文件分享 GNUnet
  • 响应式社交分享按钮 RRSSB
  • 谁有免费的英文Office2003(日文也成)分享一下吧!
  • 谁有qmail的日常维护,日志分析的资料分享下?
  • 代码分享
  • 谁有xml和libxml2的说明文档,分享一下吧
  • Java代码分享工具 Java Gems


  • 站内导航:


    特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

    ©2012-2021,,E-mail:www_#163.com(请将#改为@)

    浙ICP备11055608号-3