Linux驱动程序开发基础, -->内核模块编程,内核的调试方法
来源:互联网 发布:c语言文件指针 编辑:程序博客网 时间:2024/06/06 04:59
1. 内核模块编程
加载模块: insmod ./hello.ko卸载模块: rmmod ./hello.ko
查看模块: lsmod | grep hello
查看模块更多信息:modinfo hello
查看模块输出: dmesg
示例: insmod hello.ko num=999
grep add_integer /proc/kallsyms
hello.c
/************************************************************************* > File Name: hello.c > Author: kevin xiang > Mail: > Created Time: 2014年07月29日 星期二 11时16分53秒 ************************************************************************/#include <linux/init.h>#include <linux/module.h>MODULE_LICENSE("Dual BSD/GPL");static int num = 4000;static int hello_init(void){printk(KERN_ALERT "Hello world enter\n");printk(KERN_INFO "num is: %d\n", num);return 0;}static void hello_exit(void){printk(KERN_ALERT "Hello world exit\n");}int add_integer(int a, int b){return a+b;}module_init(hello_init);module_exit(hello_exit);module_param(num, int, S_IRUGO);EXPORT_SYMBOL(add_integer);MODULE_AUTHOR("kevin");MODULE_DESCRIPTION("a simple hello world module");MODULE_ALIAS("a simplest module");Makefile
obj-m := hello.oKDIR := /lib/modules/2.6.38-16-generic/buildall:make -C $(KDIR) M=$(PWD) modulesclean:rm -f *.ok *.o *.mod.o *.mod.c *.symvers
2. 驱动程序访问硬件的特殊性
DMA: 存在于外设中的一个硬件控制器,它的作用是 不需要CPU协助,就可以搬移内存的数据到外设的存储设备中,或者反向搬。
通过程序配置DMA控制器,告诉DMA控制器他可以访问的内存地址,DMA读写内存完成后,通过中断告诉CPU。
I/O子系统: 在嵌入式系统中,是实现对外围附属设备进行控制的有效手段,通过对I/O端口进行0或1的操作,可以发指令或者传递信息给附属设备。
Arch/arm/mach-s5pv210/mach-smdkv210.c
3. Linux设备模型
kobject
kset
sysfs
udev
4. Linux驱动分类
字符设备: 一般以串行(字节)顺序依次访问,典型的包括触摸屏,鼠标,键盘等。
块设备:
网络设备: 以态网类的设备 net_device。
杂项设备: 无法归类的部分,或者复合设备。
5. 内核的调试方法
printk
内核通过 printk() 输出的信息具有日志级别,日志级别是通过在 printk() 输出的字符串前加一个带尖括号的整数来控制的,如 printk("<6>Hello, world!/n");。内核中共提供了八种不同的日志级别,在 linux/kernel.h 中有相应的宏对应。
#define KERN_EMERG "<0>" /* system is unusable */
#define KERN_ALERT "<1>" /* action must be taken immediately */
#define KERN_CRIT "<2>" /* critical conditions */
#define KERN_ERR "<3>" /* error conditions */
#define KERN_WARNING "<4>" /* warning conditions */
#define KERN_NOTICE "<5>" /* normal but significant */
#define KERN_INFO "<6>" /* informational */
#define KERN_DEBUG "<7>" /* debug-level messages */
所以 printk() 可以这样用:printk(KERN_INFO "Hello, world!/n");。
未指定日志级别的 printk() 采用的默认级别是 DEFAULT_MESSAGE_LOGLEVEL,这个宏在 kernel/printk.c 中被定义为整数 4,即对应KERN_WARNING。
在 /proc/sys/kernel/printk 会显示4个数值(可由 echo 8 > /proc/sys/kernel/printk修改),分别表示当前控制台日志级别、未明确指定日志级别的默认消息日志级别、最小(最高)允许设置的控制台日志级别、引导时默认的日志级别。当 printk() 中的消息日志级别小于当前控制台日志级别时,printk 的信息(要有/n符)就会在控制台上显示。但无论当前控制台日志级别是何值,通过 /proc/kmsg (或使用dmesg)总能查看。另外如果配置好并运行了 syslogd 或 klogd,没有在控制台上显示的 printk 的信息也会追加到 /var/log/messages.log 中。
char myname[] = "chinacodec/n";
printk(KERN_INFO "Hello, world %s!/n", myname);
通过宏定义来控制调试信息的打开与关闭, 下面这段code 可以通过定义DEBUG_0开控制TS_DEBUG是否打印信息
//#define DEBUG_0 1#ifdef DEBUG_0#define TS_DEBUG(fmt, args...) printk(fmt, ##args)#else#define TS_DEBUG(fmt, args...)#endifMODULE_LICENSE("Dual BSD/GPL");static int num = 4000;static int hello_init(void){TS_DEBUG("this is debug info: %d\n", num);printk(KERN_ALERT "Hello world enter\n");printk(KERN_INFO "num is: %d\n", num);return 0;}
oops: 这是内核在发生panic (错误)时,所产生的一个信息。
http://www.cnblogs.com/wwang/archive/2010/11/14/1876735.html
在Linux内核开发中的Oops是什么呢?其实,它和上面的解释也没什么本质的差别,只不过说话的主角变成了Linux。当某些比较致命的问题出现时,我们的Linux内核也会抱歉的对我们说:“哎呦(Oops),对不起,我把事情搞砸了”。Linux内核在发生kernel panic时会打印出Oops信息,把目前的寄存器状态、堆栈内容、以及完整的Call trace都show给我们看,可以使用dmesg查看,这样就可以帮助我们定位错误。
kprobe:用于调试在运行的内核中的代码,可以再关键API函数的前后插入一段code,打印信息。
下面一段code,编译为module安装后,会在do_execve调用前执行handler_pre。 do_execve在终端执行ls 内核则会调用, 然后dmesg查看打出的info.
/************************************************************************* > File Name: kprobe.c > Author: kevin xiang > Mail: > Created Time: 2014年07月29日 星期二 16时37分43秒 ************************************************************************/#include <linux/module.h>#include <linux/kprobes.h>#include <linux/kallsyms.h>#include <linux/sched.h>struct kprobe kp;int handler_pre(struct kprobe *p, struct pt_regs *regs){printk(KERN_INFO "pt_regs: %p, pid: %d, jiffies: %ld\n", regs, current->tgid, jiffies);return 0;}static __init int init_kprobe_sample(void){kp.symbol_name = "do_execve";kp.pre_handler = handler_pre;register_kprobe(&kp);return 0;}module_init(init_kprobe_sample);static __exit void cleanup_kprobe_sample(void){unregister_kprobe(&kp);}module_exit(cleanup_kprobe_sample);MODULE_LICENSE("GPL");
kcore:在运行的内核的内存印像文件,位置是/proc/kcore
- Linux驱动程序开发基础, -->内核模块编程,内核的调试方法
- linux内核模块开发基础
- 内核模块的调试方法
- linux内核模块和驱动程序的编写
- linux内核模块和驱动程序的编写
- linux 学习- 编程基础之内核模块开发
- linux内核模块和驱动程序
- 内核模块调试方法
- 调试linux内核模块
- GDB简单调试linux内核与模块的方法
- GDB简单调试linux内核与模块的方法
- 内核模块编程基础
- Linux内核模块/驱动编程基础
- Linux内核模块/驱动编程基础
- linux 内核模块编程之LED驱动程序(六)
- 内核模块开发基础
- 内核模块开发基础
- Linux内核模块的概念和基本的编程方法
- 生产者消费者问题
- kernel Oops的问题
- 如何高效地输出iOS和Android标注和切图
- [转载]linux下安装wordpress的环境准备
- 基于单 camera的手势识别
- Linux驱动程序开发基础, -->内核模块编程,内核的调试方法
- java Map遍历方式
- 关于HTML文档中第一行<!DOVTYPE>命令的理解
- (个人笔记)block的使用传值回调
- PID的公式
- cocos2dx CCControlButton 按钮事件
- Socket的3次握手链接与4次断开握手
- php字符串处理方法集合
- 山东理工ACM【2761】编码