Chinaunix首页 | 论坛 | 博客
  • 博客访问: 34139
  • 博文数量: 12
  • 博客积分: 252
  • 博客等级: 二等列兵
  • 技术积分: 110
  • 用 户 组: 普通用户
  • 注册时间: 2010-10-21 12:24
文章分类
文章存档

2011年(12)

我的朋友

分类: LINUX

2011-06-25 20:02:41

一、linux内核的配置安装
1、内核文件下载解压。
tar jxvf linux.XXXXX.tar.bzg
2、配置、编译内核
make distclean
make menuconfig
make bzImage
make modules
make modules_install
3、制作init ramdisk
initramdisk:格式化一个ramdisk分区,加载根文件系统到ramdisk分区。
mkinitrd initrd-2.6.29 2.6.29
4、将编译好的内核文件和启动文件安装cp到/boot/目录下
启动文件为:
/arch/x86/boot/bzImage和刚生成的 initrd-2.6.29 文件
5、在grub添加启动选项;
title mylinux(2.6.29) 
root (hd0,0) 
kernel /vmlinuz-2.6.29
initrd /initrd-2.6.29

二、内核模块的安装卸载
1、modules有关的命令有:
lsmod : 列出已经被内核调入的模块
insmod : 将某个module插入到内核中
rmmod :将某个module从内核中卸载
modprobe:自动根据依赖文件装入模块
depmod : 生成依赖文件,告诉modprobe和kerneld要从哪儿调入modules。这个依赖文件就在/lib/modules/kernel版本/modules.dep。
Kerneld:负责自动的将模块调入内核和把模块从内核中卸载。
2、内核程序编写
1)、不能用常用的一些glibc的库,只能用内核的库,没有main函数。示列
#include
#include
//#include
MODULE_LICENSE("Dual BSD/GPL");

static int hello_init(void)
{
        printk("<1>Hello module init.\n");
        return 0;
}

static void   hello_exit(void)
{
        printk("<1>Goodbye module exit.\n");
}

module_init(hello_init);
module_exit(hello_exit);

MODULE_AUTHOR("lizeliang");
MODULE_DESCRIPTION("a simple module");
MODULE_ALIAS("hello");
关于printk的一些说明:
1、查看当前控制台的打印级别
cat /proc/sys/kernel/printk
4    4    1    7
其中第一个“4”表示内核打印函数printk的打印级别,只有级别比他高的信息才

能在控制台上打印出来,既 0-3级别的信息

2、修改打印
echo "新的打印级别  4    1    7" >/proc/sys/kernel/printk

3、不够打印级别的信息会被写到日志中可通过dmesg 命令来查看

4、printk的打印级别

#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 condition */
#define KERN_INFO            "<6>" /* informational */
#define KERN_DEBUG       "<7>" /* debug-level messages */
5、printk函数的使用
      printk(打印级别  “要打印的信息”)
       打印级别  既上面定义的几个宏
2)、2.6下常用的makefile
# Makefile2.6
ifneq ($(KERNELRELEASE),)  #KERNELRELEASE
是在内核源码的顶层Makefile中定义的一个变量,在第一次读取执行此Makefile 时,KERNELRELEASE没有被定义,所以make将读取执行else之后的内容。
#kbuild syntax. dependency relationshsip of files and target modules are listed here.
#mymodule-objs := file1.o file2.o ... #
表示mymoudule.o file1.ofile2.o 等连接生成。如果有多个文件,需要把这一句加上
obj-m := mymodule.o #
表示编译连接后将生成mymodule.o模块。
else
PWD  := $(shell pwd) #
执行shell命令,把当前路径赋值给PWD
KVER ?= $(shell uname -r) #
执行shell命令,将当前系统内核版本号赋值给KVER
KDIR := /lib/modules/$(KVER)/build  
all:
    $(MAKE) -C $(KDIR) M=$(PWD) #
"$(MAKE) -C $(KDIR) SUBDIRS =$(PWD)"的作用是等效的,SUBDIRS是较老的使用方法
clean:
rm -rf .*.cmd *.o *.mod.c *.ko .tmp_versions
endif

执行路径:如果make的目标是clean,直接执行clean操作,然后结束。当make的目标为all时,-C $(KDIR) 指明跳转到内核源码目录下读取那里的MakefileM=$(PWD) 表明然后返回到当前目录继续读入、执行当前的Makefile。当从内核源码目录返回时,KERNELRELEASE已被被定义,kbuild也被启动去解析kbuild语法的语句,make将继续读取else之前的内容。else之前的内容为kbuild语法的语句指明模块源码中各文件的依赖关系,以及要生成的目标模块名。
上面的据说是IBM网站上的一个,注意的是因为makefile有格式上的限制直接粘过去的话需要调下格式,另外PWD和KVER两个变量定义的时候后面都有个空格需要去掉。
用make编译完成后会产生XXXX.ko的文件,可以通过insmod命令加载到内核中。
三、内核模块参数
内核模块参数的内容转载先网上一片文章进行说明:
module_param()理解
-------------------------------------------
在用户态下编程可以通过main()的来传递命令行参数,而编写一个内核模块则通过module_param()
module_param()宏是Linux 2.6内核中新增的,该宏被定义在include/linux/moduleparam.h文件中,具体定义如下:
#define module_param(name, type, perm)               
    module_param_named(name, name, type, perm)
其中使用了 3 个参数:要传递的参数变量名, 变量的数据类型, 以及访问参数的权限。
perm参数的作用是什么?
-------------------------------------------
perm参数是一个权限值,表示此参数在sysfs文件系统中所对应的文件节点的属性。你应当使用 中定义的值. 这个值控制谁可以存取这些模块参数在sysfs中的表示.当perm为0时,表示此参数不存在sysfs文件系统下对应的文件节点。 否则, 模块被加载后,在/sys/module/目录下将出现以此模块名命名的目录, 带有给定的权限.。
权限在include/linux/stat.h中有定义
#define S_IRWXU 00700
#define S_IRUSR 00400
#define S_IWUSR 00200
#define S_IXUSR 00100
#define S_IRWXG 00070
#define S_IRGRP 00040
#define S_IWGRP 00020
#define S_IXGRP 00010
#define S_IRWXO 00007
#define S_IROTH 00004
#define S_IWOTH 00002
#define S_IXOTH 00001
使用S_IRUGO作为参数可以被所有人读取, 但是不能改变; S_IRUGO|S_IWUSR允许root来改变参数. 注意, 如果一个参数被sysfs修改, 你的模块看到的参数值也改变了, 但是你的模块没有任何其他的通知. 你应当不要使模块参数可写, 除非你准备好检测这个改变并且因而作出反应.
module_param()应当放在任何函数之外, 典型地是出现在源文件的前面.定义如:
static char *whom = "world";
static int howmany = 1;
module_param(howmany, int, S_IRUGO);
module_param(whom, charp, S_IRUGO);
模块参数支持许多类型:
bool     一个布尔型(true或者false)值(相关的变量应当是int类型).
invbool invbool类型颠倒了值, 所以真值变成 false, 反之亦然.
charp    一个字符指针值. 内存为用户提供的字串分配, 指针因此设置.
int
long
short
uint
ulong
ushort
数组参数, 用逗号间隔的列表提供的值, 模块加载者也支持. 声明一个数组参数, 使用:
module_param_array(name, type, num, perm);
name    数组的名子(也是参数名),
type    数组元素的类型,
num    一个整型变量,
perm    通常的权限值.
如果数组参数在加载时设置, num被设置成提供的数的个数. 模块加载者拒绝比数组能放下的多的值.
hello.c
-------------------------------------------
#include
#include
#include
MODULE_LICENSE ("Dual BSD/GPL");

static char *who = "world";
static int times = 1;
module_param (times, int, S_IRUSR);
module_param (who, charp, S_IRUSR);

static int hello_init (void)
{
   int i;
   for (i = 0; i < times; i++)
       printk (KERN_ALERT "(%d) hello, %s!\n", i, who);
   return 0;
}

static void hello_exit (void)
{
   printk (KERN_ALERT "Goodbye, %s!\n", who);
}

module_init (hello_init);
module_exit (hello_exit);
编译生成可执行文件hello
# insmod hello who="world" times=5
#(1) hello, world!
#(2) hello, world!
#(3) hello, world!
#(4) hello, world!
#(5) hello, world!
# rmmod hello
# Goodbye,world!
注: 如果加载模块hello时,没有输入任何参数,那么who的初始值为"world",times的初始值为1
原文地址:http://hi.baidu.com/operationsystem/blog/item/c150423c1d7e7ce83c6d97ff.html

Linux内核是一个整体结构,像一个圆球,而模块是插入到内核中的插件。尽管内核不是一个可安装模块,但为了方便起见,Linux把内核也看作 一个“母”模块。那么模块与模块之间如何进行交互呢,一种常用的方法就是共享变量和函数。但并不是模块中的每个变量和函数都能被共享,内核只把各个模块中 主要的变量和函数放在一个特定的区段,这些变量和函数就统称为符号。到低哪些符号可以被共享? Linux内核有自己的规定。对于内核这个特殊的母模块,在kernel/ksyms.c中定义了从中可以“移出”的符号,例如进程管理子系统可以“移出”的符号定义如下:
EXPORT_SYMBOL(do_mmap_pgoff);
EXPORT_SYMBOL(do_munmap);
只要已经加载的模块有导出变量或者函数,新加载的模块就可以直接使用。
阅读(1232) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~