Linux系统--设备驱动程序学习记录1

说明:以下是自己阅读《linux设备驱动程序》(美)科波特   部分章节的笔记
(《Linux Device Drivers 3rd》   Corbet Jonathan & Rubini Alessandro & Kroah-Hartman Greg)

Chapter 1. 设备驱动程序简介

1)编程问题: 机制——需要提供什么功能

              策略——如何使用这些功能

 

2)驱动程序编写(机制):

提供给用户尽量多的选项;编写驱动程序要占用的时间;尽量保持程序简单以减少错误

 

3)linux内核中的输出函数  printk(优先级  “字符串”)    中间无逗号

 

4)模块退出时必须撤销初始化函数所做的一切;

仅调用内核函数,即include内核头文件(大多在include/linux或include/asm中)

 

5)驱动程序任务:模块中的某些函数作为系统调用的一部分而执行;其他函数负责中断处理

 

6)获得当前进程

#include <linux/sched.h>

printk(KERN_INFO "the process is \"%s\" (pid %i) \n", current->comm, current->pid)

 

7)内核空间很小,注意使用,若需大结构,动态分配该结构

 

8)内核不能实现浮点运算

 

Chapter 2. 构造运行模块

1)Makefile文件:

obj-m := module.o

module-objs := file1.o file2.o

make命令 make -C 源代码目录(内核) M=`pwd`modules   (modules为模块名,例如module.o)

 

2)Makefile完整版:

ifneq ($(KERNELRELEASE),)

    obj-m := hello.o

else

    KERNELDIR ?= /lib/modules/$(shell uname -r)/build

    PWD := $(shell pwd)

default:

    $(MAKE) -C $(KERNELDIR) M=$(PWD) modules

endif

 

3)实验:

hello.c

Makefile

>make

>insmod hello.ko    (消息记录在/var/log/messages)

>rmmod hello  

 

4)insmod的工作:在kernel/module.c中

sys_init_module  分配内存,复制到内存,符号表解析,模块初始化函数

 

5)modprobe: 和insmod类似,从当前目录装入自己的模块,但考虑加载模块的依赖,处理层叠模块

modprobe -r  卸载

 

6)lsmod:读取/proc/modules

也可以从/sys/module中获取

 

7)版本问题参见 linux/version.h

UTS_RELEASSE, LINUX_VERSION_CODE, KERNEK_VERSION

依赖于特定的版本的代码应隐藏在底层宏or函数中

 

8)符号导出  EXPORT_SYMBOL(name)

             EXPORT_SYMBOL_GPL(name)

 

9)必须包含头文件

#include <linux/module.h>

#include <linux/init.h>

大部分包含 moduleparam.h   传递参数

 

10)源代码最后应添加一些说明:必须有MODULE_LICENSE("GPL")    "Dual BSD/GPL"

MODULE_AUTHOR, MODULE_DESCRIPTION, MODULE_VERSION, MODULE_ALIAS, MODULE_DEVICE_TABLE

 

11)初始化函数的定义:

static int __init initializaion_function(void)

{

   

}

module_init(initialization_function)

 

12)消除函数的定义:

static void __exit cleanup_function(void)

{

   

}

module_exit(cleanup_function)

 

13)注册设施失败后,需要自行回滚,使用goto(效率)

或使用清除函数(清晰,需要在撤销设施前检查设施的注册状态)

 

14)错误编码  linux/errno.h

 

15)注意模块装载竞争:在用来支持某个设施的所有内部初始化完成之前,不要注册任何设施

 

14)模块参数:

例  static char *whom = "world";    (需要有默认值)

module_param(whom, charp, S_IRUGO);

charp是类型,还有bool, invbool, int, long, uint, ulong , ushort, short

S_IRUGO是访问许可掩码

 

数组:module_param(name, type, num, perm)

 

insmod时带参数:

例  insmod hellop whom="Mem"

 

15)许可掩码定义在  linux/stat.h

perm为0,不会有对应的sysfs入口项;否则模块参数在sys/module

S_IRUGO 可读

S_IRUGO|S_IWUSR  root用户可修改

 

Chapter 4. 调试技术

1)内核调试支持:大部分在Kernel Hacking菜单中

CONFIG_DEBUG_KERNEL 基础

CONFIG_DEBUG_SLAB   内存溢出及忘记初始化,每个字节0xa5,释放后0x6b

CONFIG_DEBUG_PAGEALLOC  定位特定内存损坏错误,会大大降低速度

CONFIG_DEBUG_SPINLOCK   自旋锁

CONFIG_DEBUG_SPINLOCK_SLEEP  自旋锁休眠

CONFIG_INIT_DEBUG __init符号初始化后丢弃  (2.6.38中没有该项)

CONFIG_DEBUG_INFO

CONFIG_FRAME_POINTER 这两项使用gdb

CONFIG_MAGIC_SYSRQ  SysRq魔法按键

CONFIG_DEBUG_STACKOVERFLOW  栈

CONFIG_DEBUG_STACK_USAGE    SysRq输出

CONFIG_KALLSYMS(Gerneral Setup/Standard features选项)  包含符号信息,默认开启

CONFIG_IKCONFIG

CONFIG_IKCONFIG_PROC  这两项是同上选项,完成的内核配置状态  /proc

CONFIG_ACPI_DEBUG  (Power Management/ACPI)

CONFIG_DEBUG_DRIVER  (Device drivers)

CONFIG_SCSI_CONSTANTS  (Device drivers/SCSI device support)

CONFIG_INPUT_EVBUG  (Device drivers/Input deveice support)  记录所有输入内容,安全问题

CONFIG_PROFILING   (Profiling support)

 

2)printk 日志级别 0-7  高->低

KERN_EMERG, KERN_ALERT, KERN_CRIT, KERN_ERR, KERN_WARNING, KERN_NOTICE, KERN_INFO, KERN_DEBUG

默认DEFAULT_MESSAGE_LOGLEVEL    kern/printk.c    /etc/syslog.conf调整

优先级>consile_loglevel时,消息输出到控制台

系统同时运行klogd和syslogd,消息追加到/var/log/messages

klogd不保存连续相同的日志,在最后打印次数

syslogd   /proc/kmsg   dmesg

 

3)console_loglevel 默认DEFAULT_CONSOLE_LOGLEVEL

可通过sys_syslog系统调用修改

或echo num > /proc/sys/kernel/printk

 

指定接收消息控制台setconsole  在misc-progs/ioctl(TIOCLINUX)

 

4)printk将消息写入__LOG_BUF_LEN循环缓冲区

 

5)控制消息的显示

#undef PDEBUG          防止重复定义

#ifdef SCULL_DEBUG

   ifdef __KERNEL__   打开调试,并处于内核空间

       define DEBUG(fmt, args...) printk(KERN_DEBUG "scull: "fmt, ##args)

   else   处于用户空间

       define PDEBUG(fmt, args...) fprintf(stderr, fmt, ##args)

   endif

#else

   define PDEBUG(fmt, args...)  调试关闭,不做任何事

#endif

 

#undef PDEBUGG

#define PDEBUGG(fmt, args...)

 

6)消息输出速度限制   在/proc/sys/kernel/printk_ratelimit

if(printk_ratelimit())

    printk(KERN_NOTICE "The printer is still on fire\n");

 

7)打印设备编号  linux/kdev_t.h

int print_dev_t(char *buffer, dev_t dev);

char *format_dev_t(char *buffer, dev_t dev);

 

8)在proc中实现文件    (还可以用ioctl)

int (*read_proc)(char *page, char **start, off_t offset, int count, int *eof, void *data)

创建proc文件

struct proc_dir_entry *create_proc_read_entry(const char *name, mode_t mode, struct proc_dir_entry *base, read_porc_t *read_proc, void *data);

struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode, struct proc_dir_entry *parent);

void remove_proc_entry(const char *name, struct proc_dir_entry *parent);

例如:

create_proc_read_entry("scullmem", 0, NULL, scull_read_procmem, NULL)

0为默认mode,第一个NULL为/proc根目录

 

9)使用seq_file实现/proc文件

void *start(struct seq_file *sfile, loff_t *pos);

void *next(struct seq_file *sfile, void *v, loff_t *pos);

void stop(struct seq_file *sfile, void *v);

int show(struct seq_file *sfile, void *v);

int seq_printf(struct seq_file *sfile, const char *fmt, ...);  不用printk

int seq_putc(struct seq_file *sfile, char c);

int seq_puts(struct seq_file *sfile, const char *s);

int seq_escape(struct seq_file *m, const char *s, const char *esc);  esc可为"\t\n\\"

 

static struct seq_operations scull_seq_ops = {

    .start = scull_seq_start,

    .next = scull_seq_next,

    .stop = scull_seq_stop,

    .show = scull_seq_show

}

static int scull_proc_open(struct inode *inode, struct file *file)

{

    return seq_open(file, &scull_seq_ops);

}


10)oops消息:大多由于对NULL指针取值或使用不正确的指针值


11)SysRq: Alt+Sys Rq+

r 关闭键盘raw格式

k 激活SAK(secure attention key)  杀死控制台上所有进程

s 对所有磁盘进行紧急同步

u 尝试以制度模式重新挂装所有磁盘

b 重启系统  需要先s+u

p 打印当前处理器寄存器信息

t 打印当前任务列表

m 打印内存信息


启用: echo 1 > /proc/sys/kernel/sysrq

文档:Documentation/sysrq.txt

Documentation/basic_profiling.txt  剖析器


12)gdb调试:

通过/sys/module/设备名/sections    找到各段基地址

(gdb)add-symbol-file ko文件名 .text段基址 -s .bss .bss段基址 -s .data .data段基址


13)Kdb补丁   Kgdb补丁(两台机器串行线相连)

LTT(Linux Trace Toolkit)


Chapter 8. 分配内存

(to be continued...)

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值