Linux驱动程序开发基础, -->内核模块编程,内核的调试方法

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.o

KDIR :=  /lib/modules/2.6.38-16-generic/build
all:
	make -C $(KDIR) M=$(PWD) modules
clean:
	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...)
#endif

MODULE_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








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值