linux驱动开发模块图,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

#include

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

0818b9ca8b590ca3270a3433284dd417.png

3. Linux设备模型kobject

0818b9ca8b590ca3270a3433284dd417.png

kset

0818b9ca8b590ca3270a3433284dd417.png

sysfs

0818b9ca8b590ca3270a3433284dd417.png

udev

0818b9ca8b590ca3270a3433284dd417.png

4. Linux驱动分类

字符设备: 一般以串行(字节)顺序依次访问,典型的包括触摸屏,鼠标,键盘等。

块设备:

0818b9ca8b590ca3270a3433284dd417.png

网络设备: 以态网类的设备  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

#include

#include

#include

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值