Chapter 1. 设备驱动程序简介
1)编程问题: 机制——需要提供什么功能
2)驱动程序编写(机制):
提供给用户尽量多的选项;编写驱动程序要占用的时间;尽量保持程序简单以减少错误
3)linux内核中的输出函数
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
2)Makefile完整版:
ifneq ($(KERNELRELEASE),)
else
default:
endif
3)实验:
hello.c
Makefile
>make
>insmod hello.ko
>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)符号导出
9)必须包含头文件
#include <linux/module.h>
#include <linux/init.h>
大部分包含 moduleparam.h
10)源代码最后应添加一些说明:必须有MODULE_LICENSE("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)错误编码
15)注意模块装载竞争:在用来支持某个设施的所有内部初始化完成之前,不要注册任何设施
14)模块参数:
例
module_param(whom, charp, S_IRUGO);
charp是类型,还有bool, invbool, int, long, uint, ulong , ushort, short
S_IRUGO是访问许可掩码
数组:module_param(name, type, num, perm)
insmod时带参数:
例
15)许可掩码定义在
perm为0,不会有对应的sysfs入口项;否则模块参数在sys/module
S_IRUGO 可读
S_IRUGO|S_IWUSR
Chapter 4. 调试技术
1)内核调试支持:大部分在Kernel Hacking菜单中
CONFIG_DEBUG_KERNEL 基础
CONFIG_DEBUG_SLAB
CONFIG_DEBUG_PAGEALLOC
CONFIG_DEBUG_SPINLOCK
CONFIG_DEBUG_SPINLOCK_SLEEP
CONFIG_INIT_DEBUG __init符号初始化后丢弃
CONFIG_DEBUG_INFO
CONFIG_FRAME_POINTER 这两项使用gdb
CONFIG_MAGIC_SYSRQ
CONFIG_DEBUG_STACKOVERFLOW
CONFIG_DEBUG_STACK_USAGE
CONFIG_KALLSYMS(Gerneral Setup/Standard features选项)
CONFIG_IKCONFIG
CONFIG_IKCONFIG_PROC
CONFIG_ACPI_DEBUG
CONFIG_DEBUG_DRIVER
CONFIG_SCSI_CONSTANTS
CONFIG_INPUT_EVBUG
CONFIG_PROFILING
2)printk 日志级别 0-7
KERN_EMERG, KERN_ALERT, KERN_CRIT, KERN_ERR, KERN_WARNING, KERN_NOTICE, KERN_INFO, KERN_DEBUG
默认DEFAULT_MESSAGE_LOGLEVEL
优先级>consile_loglevel时,消息输出到控制台
系统同时运行klogd和syslogd,消息追加到/var/log/messages
klogd不保存连续相同的日志,在最后打印次数
syslogd
3)console_loglevel 默认DEFAULT_CONSOLE_LOGLEVEL
可通过sys_syslog系统调用修改
或echo num > /proc/sys/kernel/printk
指定接收消息控制台setconsole
4)printk将消息写入__LOG_BUF_LEN循环缓冲区
5)控制消息的显示
#undef PDEBUG
#ifdef SCULL_DEBUG
#
#
#
#
#
#else
#
#endif
#undef PDEBUGG
#define PDEBUGG(fmt, args...)
6)消息输出速度限制
if(printk_ratelimit())
7)打印设备编号
int print_dev_t(char *buffer, dev_t dev);
char *format_dev_t(char *buffer, dev_t dev);
8)在proc中实现文件
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, ...);
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);
static struct seq_operations scull_seq_ops = {
}
static int scull_proc_open(struct inode *inode, struct file *file)
{
}
10)oops消息:大多由于对NULL指针取值或使用不正确的指针值
11)SysRq: Alt+Sys Rq+
r 关闭键盘raw格式
k 激活SAK(secure attention key)
s 对所有磁盘进行紧急同步
u 尝试以制度模式重新挂装所有磁盘
b 重启系统
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补丁
LTT(Linux Trace Toolkit)
Chapter 8. 分配内存
(to be continued...)