深入浅出Linux设备驱动编程之内核模块

榴莲persoq

榴莲persoq

2016-01-29 17:41

深入浅出Linux设备驱动编程之内核模块,深入浅出Linux设备驱动编程之内核模块

  Linux设备驱动属于内核的一部分,Linux内核的一个模块可以以两种方式被编译和加载:

  (1)直接编译进Linux内核,随同Linux启动时加载;

  (2)编译成一个可加载和删除的模块,使用insmod加载(modprobe和insmod命令类似,但依赖于相关的配置文件),rmmod删除。这种方式控制了内核的大小,而模块一旦被插入内核,它就和内核其他部分一样。

  下面我们给出一个内核模块的例子:

#include <linux/module.h //所有模块都需要的头文件
#include <linux/init.h // init&exit相关宏
MODULE_LICENSE("GPL");
static int __init hello_init (void)
{
 printk("Hello module initn");
 return 0;
}

static void __exit hello_exit (void)
{
 printk("Hello module exitn");
}

module_init(hello_init);
module_exit(hello_exit);
  分析上述程序,发现一个Linux内核模块需包含模块初始化和模块卸载函数,前者在insmod的时候运行,后者在rmmod的时候运行。初始化与卸载函数必须在宏module_init和module_exit使用前定义,否则会出现编译错误。

  程序中的MODULE_LICENSE("GPL")用于声明模块的许可证。
    
  如果要把上述程序编译为一个运行时加载和删除的模块,则编译命令为:

gcc -D__KERNEL__ -DMODULE -DLINUX -I /usr/local/src/linux2.4/include -c -o hello.o hello.c
  由此可见,Linux内核模块的编译需要给gcc指示-D__KERNEL__ -DMODULE -DLINUX参数。-I选项跟着Linux内核源代码中Include目录的路径。

  下列命令将可加载hello模块:

insmod ./hello.o
  下列命令完成相反过程:

rmmod hello
  如果要将其直接编译入Linux内核,则需要将源代码文件拷贝入Linux内核源代码的相应路径里,并修改Makefile。
我们有必要补充一下Linux内核编程的一些基本知识:

  内存

  在Linux内核模式下,我们不能使用用户态的malloc()和free()函数申请和释放内存。进行内核编程时,最常用的内存申请和释放函数为在include/linux/kernel.h文件中声明的kmalloc()和kfree(),其原型为:

void *kmalloc(unsigned int len, int priority);
void kfree(void *__ptr);
  kmalloc的priority参数通常设置为GFP_KERNEL,如果在中断服务程序里申请内存则要用GFP_ATOMIC参数,因为使用GFP_KERNEL参数可能会引起睡眠,不能用于非进程上下文中(在中断中是不允许睡眠的)。

  由于内核态和用户态使用不同的内存定义,所以二者之间不能直接访问对方的内存。而应该使用Linux中的用户和内核态内存交互函数(这些函数在include/asm/uaccess.h中被声明):

unsigned long copy_from_user(void *to, const void *from, unsigned long n);
unsigned long copy_to_user (void * to, void * from, unsigned long len);
  copy_from_user、copy_to_user函数返回不能被复制的字节数,因此,如果完全复制成功,返回值为0。

  include/asm/uaccess.h中定义的put_user和get_user用于内核空间和用户空间的单值交互(如char、int、long)。

  这里给出的仅仅是关于内核中内存管理的皮毛,关于Linux内存管理的更多细节知识,我们会在本文第9节《内存与I/O操作》进行更加深入地介绍。

  输出
 
  在内核编程中,我们不能使用用户态C库函数中的printf()函数输出信息,而只能使用printk()。但是,内核中printk()函数的设计目的并不是为了和用户交流,它实际上是内核的一种日志机制,用来记录下日志信息或者给出警告提示。

  每个printk都会有个优先级,内核一共有8个优先级,它们都有对应的宏定义。如果未指定优先级,内核会选择默认的优先级DEFAULT_MESSAGE_LOGLEVEL。如果优先级数字比int console_loglevel变量小的话,消息就会打印到控制台上。如果syslogd和klogd守护进程在运行的话,则不管是否向控制台输出,消息都会被追加进/var/log

展开更多 50%)
分享

猜你喜欢

深入浅出Linux设备驱动编程之内核模块

Linux Linux命令 Linux安装 Linux编程 Linux桌面 Linux软件 Linux内核 Linux管理
深入浅出Linux设备驱动编程之内核模块

深入浅出Linux设备驱动中断处理介绍

Linux Linux命令 Linux安装 Linux编程 Linux桌面 Linux软件 Linux内核 Linux管理
深入浅出Linux设备驱动中断处理介绍

s8lol主宰符文怎么配

英雄联盟 网络游戏
s8lol主宰符文怎么配

深入浅出Linux设备驱动异步通知介绍

Linux Linux命令 Linux安装 Linux编程 Linux桌面 Linux软件 Linux内核 Linux管理
深入浅出Linux设备驱动异步通知介绍

深入浅出Linux设备驱动之并发控制

Linux Linux命令 Linux安装 Linux编程 Linux桌面 Linux软件 Linux内核 Linux管理
深入浅出Linux设备驱动之并发控制

lol偷钱流符文搭配推荐

英雄联盟 网络游戏
lol偷钱流符文搭配推荐

深入浅出Linux字符设备驱动程序解析

Linux Linux命令 Linux安装 Linux编程 Linux桌面 Linux软件 Linux内核 Linux管理
深入浅出Linux字符设备驱动程序解析

深入浅出分析Linux设备驱动程序中断 (1)

PHP
深入浅出分析Linux设备驱动程序中断  (1)

lolAD刺客新符文搭配推荐

英雄联盟
lolAD刺客新符文搭配推荐

为Windows XP操作系统设置强健的密码

为Windows XP操作系统设置强健的密码

分有多节的Word文档如何打印指定页

分有多节的Word文档如何打印指定页
下拉加载更多内容 ↓