ubuntu虚拟机下内核模块的编译和安装

以前是在ok6410上学习linux的,所以在ubuntu下搭建的环境编译出来的内核模块是交叉编译到ARM平台的,直接在虚拟机上运行不了。所以这里说一下,在虚拟机上编译内核模块,然后安装到虚拟机内核上的方法和过程。

首先,我还是不厌其烦的介绍一些内核模块的基本知识。

一、什么是模块

模块是具有独立功能的程序,它可以被单独编译,但不能独立运行。它在运行时被链接到内核作为内核的一部分在内核空间运行,这与运行在用户空间的进程是不同的。模块通常由一组函数和数据结构组成,用来实现一种文件系统、一个驱动程序或其他内核上层的功能。

为了加深对内核模块的了解,表一给出应用程序与内核模块程序的比较。

表一应用程序与内核模块程序的比较

从表一我们可以看出,内核模块程序不能调用libc库中的函数,它运行在内核空间,且只有超级用户可以对其运行。另外,模块程序必须通过module_init()module-exit()函数来告诉内核“我来了”和“我走了”。

二、编写一个简单的模块

模块和内核都在内核空间运行,模块编程在一定意义上说就是内核编程。因为内核版本的每次变化,其中的某些函数名也会相应地发生变化,因此模块编程与内核版本密切相关。以下例子针对Ubuntu10.04内核3.2.0-23-generic-pae。要提醒读者的是,要看懂此模块必须先了解一下proc文件系统方面的知识,可以查看我的相关博客。

1.示范程序:axp192.c

#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/kernel.h>
#include <asm/access.h>
#define MAX_BUFFER_SIZE        256
#define    AXP192_PROC_FILE   "driver/axp192"
static struct proc_dir_entry *axp192_proc_file;
static int index;
static u8 buff[MAX_BUFFER_SIZE];
static void axp192_write(int index, u8 reg_val)
{
buff[index] = reg_val;
}
static void axp192_read(int index, u8 *reg_val)
{
*reg_val = buff[index];
}
static ssize_t axp192_proc_read(struct file *filp,
        char *buffer, size_t length,loff_t *offset)
{
u8 reg_val;
if ((index < 0) || (index >MAX_BUFFER_SIZE))
    return 0;
axp192_read(index, &reg_val);
printk(KERN_INFO "register0x%x: 0x%x\n", index, reg_val);
return 0;
}
static ssize_taxp192_proc_write(struct file *filp,
    const char*buff, size_t len, loff_t *off)
{
u8 reg_val;
char messages[256], vol[256];
if (len > 256)
   len = 256;
if (copy_from_user(messages, buff,len))
   return -EFAULT;
if ('-' == messages[0]) {
  /* set the register index */
   memcpy(vol,messages+1, len-1);
 index = (u8) simple_strtoul(vol, NULL, 16);
    } else {
    /* set theregister value */
   reg_val =(u8)simple_strtoul(messages, NULL, 16);
    axp192_write(index,reg_val & 0xFF);
}
return len;
}
static struct file_operationsaxp192_proc_ops = {
.read = axp192_proc_read,
.write = axp192_proc_write,
};
static voidcreate_axp192_proc_file(void)
{
printk("setup proc controlinterface\n");
axp192_proc_file = create_proc_entry(AXP192_PROC_FILE,0644, NULL);
if (axp192_proc_file) {
axp192_proc_file->proc_fops =&axp192_proc_ops;
} else
printk(KERN_INFO "proc filecreate failed!\n");
}
static voidremove_axp192_proc_file(void)
{
remove_proc_entry(AXP192_PROC_FILE,NULL);
}
static int __init axp192_init(void)
{
printk("---AXP192_init\n");
create_axp192_proc_file();
return 0;
}
static void __exitaxp192_exit(void)
{
remove_axp192_proc_file();
}
module_init(axp192_init);
module_exit(axp192_exit);
MODULE_DESCRIPTION("Axp192Driver");
MODULE_LICENSE("GPL");

说明

所有模块都要使用头文件module.h,此文件必须包含进来。

头文件kernel.h包含了常用的内核函数。

头文件init.h包含了宏_init和_exit,它们允许释放内核占用的内存。

lkp_init是模块的初始化函数,它必需包含诸如要编译的代码、初始化数据结构等内容。

使用了printk()函数,该函数是由内核定义的,功能与C库中的printf()类似,它把要打印的信息输出到终端或系统日志。

lkp_cleanup是模块的退出和清理函数。此处可以做所有终止该驱动程序时相关的清理工作。

module_init()和cleanup_exit()是模块编程中最基本也是必须的两个函数。

module_init()是驱动程序初始化的入口点。而cleanup_exit()注销由模块提供的所有功能。

2 编写Makefile文件,与axp192.c放在同一个目录里


 (注意makefile里面要求的tab)

KDIR:=/lib/modules/3.2.0-23-generic-pae/build是编译内核模块需要的Makefile的路径,Ubuntu 10.04下是

/lib/modules/3.2.0-23-generic-pae /build

make-C$(KDIR) M=$(PWD)modules编译内核模块。

-C将工作目录转到KDIR,调用该目录下的Makefile,并向这个Makefile传递参数M的值是$(PWD)modules。

3.编译模块

#sudo make(调用第一个命令default)

这时,在axp192.c所在文件夹就会有axp192.ko,这个就是我们需要的内核模块啦

#sudo make clean清理编译垃圾,axp192.ko也会清理掉。

4.插入模块,让其工作。注意必须是root权限

生成apx192.ko后,在虚拟机中insmod,成功后在/proc/driver下将会生成名为axp192的文件,改变其属性对其操作。操作过程和结果如图(ubuntu的文字界面模式下):


               

第一次echo “-0x21”>axp192  ,指定寄存器,由于没有设置值,故默认值为0    所以:register 0x21: 0x0

第二次echo “0x78”>axp192是改变寄存器0x21的值,设为0x78。设置后,观察:register 0x21: 0x78

这就是在Ubuntu虚拟机下一个最简单的模块编写过程。

 

 

 

 


你可能感兴趣的:(ubuntu虚拟机下内核模块的编译和安装)