linux内核开发基础学习笔记

来源:互联网 发布:淘宝上怎么搜弹簧刀 编辑:程序博客网 时间:2024/05/24 01:38
linux内核开发基础
  
linux体系结构
用户空间(user space)
   user application
   gnu c library(blibc)
内核空间(kernel space)
   system call interface
   kernel
   archlitecture-dependent kernel code




linux内核架构
system call interface (SCI)系统调用接口
process management (PM)进程管理    virtual file system(VFS)虚拟文件系统
memory management(MM)内存管理      network stack网络协议栈
arch 休系结构代码                  device drivers(DD)设备驱动程序




linux内核源代码
目录结构
arch(architecture) 内核所支持的每种cpu体系,该目录下都有对应子目录*
block 部分块设备驱动程序
crypto 加密、压缩、CRC校验算法
Documentation 内核的文档
drivers 设备驱动程序*
firmware 
fs (file system) 各种文件系统的实现代码,公用的源程序实现虚拟文件系统(vfs)
include 内核所需要的头文件
init
ipc
kernel
lib 库文件代码
mm  实现内存管理中与体系结构无关的部分
net 实现网络协议的代码
samples 一些内核编程的范例
scripts 配置内核的角本
security selinux的模块
sound 音频设备的驱动程序
usr   cpio命令实现
virt  内核虚拟机








linux内核配置与编译


linux内核的开发过程主要有以下几个步骤:
1 清理临时文件、中间文件和配置文件
 make clean  删除产生文件保留配置文件
 make mrproper 删除产生文件和配置文件
 make distclean 删除mrproper+编辑备份和补丁文件


2 确定目标系统的软故硬件配置情况 如cpu\网卡型号
3 配置内核
  make config 基于文本模式的交互配置
  make menuconfig 基于文本模式的菜单型配置 (最为常用)
     切换选中主y\n\m 或按空格键切换
     
  make oldconfig 使用已有的配置文件(类似make config,只会询问新增的配置项)
  make xconfig 图形化的配置
配置完成后会产生.config文件


4 编译内核
  make zImage(在x86平台,小于512k的内核)
  make bzImage
  查看编译信息 后面加V=1
  编译好的内核位于arch/<cpu>/boot/ 目录下
5 编译内核模块
  make modules
6 安装内核模块
  make modules_install (从内核源代码目录copy到lib/modules/目录下)
7 制作init ramdisk
  mkinitrd initrd-$version $version




  制作文件系统
8 安装内核
  cp arch/x86/boot/bzImage /boot/vmlinuz_$version
  cp $initrd /boot/
  修改/ect/grub.conf或/etc/lilo.conf




内核模块
让内核模块不包含某组件,在需要该组件的时候动态添加到正在运行的内核中


示例代码如下:
#include <linux/init.h>
#include <linux/module.h>


static int hello_init(){
printk(KERN_WARNING"Hello world!\n");
return 0;
}


static void hello_exit(){
printk(KERN_INFO"hello exit!\n");
}


module_init(hello_init);
module_exit(hello_exit);


模块加载函数
module_init
模块卸载函数
module_exit


模块编译
makefile




示例代码如下:


hello.c文件
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>


static int __init hello_init(){
printk("Hello world!\n");
return 0;
}


static void __exit hello_exit(){
printk("hello exit!\n");
}


module_init(hello_init);
module_exit(hello_exit);


Makefile文件
ifneq($(KERNELRELEASE),)
obj-m :=hello.o
else
KDIR :=/lib/module/2.6.28/build  #内核源代码路径
all:
make -C $(KDIR) M=$(PWD) modules
clean:
rm -f *.ko *.o *.mod.o *.mod.c *.symvers
endif






包含多个内核模块
示例代码如下:
main.c文件
#include <linux/module.h>
#include <linux/init.h>


MODULE_LICENSE("GPL");
MODULE_AUTHOR("retucn yue");
MODULE_DESCRIPTION("Hello world module");
MODULE_ALLAS("a simplest module");


extern int add(int a,int b);
static int __int hello_init(){
printk("hello world!\n");
add(1,2);
}


static void __exit hello_exit(){
printk("hell world exit\n");
}


module_init(hello_init);
module_exit(hello_exit);




add.c文件
int add(int a,int b){
return a+b;
}




Makefile文件
ifneq ($(KERNELRELEASE),)


obj-m :=hello.o
hello-objs :=main.o add.o


else


KDIR :=/home/retacn/tools/linux-2.6.28
all:
make -C $(KDIR) M=$(PWD) modules
clean:
rm -f *.ko *.o *.mod.o *.mod.c *.symvers
endif




内核模块的安装和卸载
加载
insmod hello.ko
卸载
rmmod hello
查看
lsmod
加载
modprobe




在redhat下安装内核源代码
下载内核源代码包
http://ftp.redhat.com/pub/redhat/linux/enterprise/5Server/en/os/SRPMS/


安装
[retacn@localhost tools]$ rpm -ivh kernel-2.6.18-308.24.1.el5.src.rpm 
[retacn@localhost tools]$ cd /usr/src/redhat/SOURCES
[root@localhost SOURCES]# tar xvf linux-2.6.18.4.tar.bz2  -C /usr/src/

[root@localhost SOURCES]# uname -r # 查看当前版本信息
版本不匹配
解决办法
1 使用modprobe --force-modversion
2 编译内核模块时,保证所依赖的内核代码版本和当前运行版本一致

3 在make menuconfig时不添加版本信息

4 直接替换当前运行版本


模块可选信息
1 许可证申请
 MODULE_LIENSE 通知内核,该模块带有一个许可证
 常见的许可证有:
GPL
GPLv2
GPL and additional rigths
Dual BSD/GPL
Dual MPL/GPL
Proprietary
2 作者
 MODULE_AUTHOR("yue")
3 模块描述
 MODULE_DESCRIPTION("hello world module")
4 模块版本
 MODULE_VERSION("V1.0")
5 模块别名
 MODULE_ALIAS("a simple module")
6 模块参数
  module_param指定模块参数,用于加载模块时传递给模块
  格式:
module_param(name,type,perm)
   name 模块参数的名称
   type 参数的类型 bool int charp(字符串)
   perm 参数的访问权限 S_IRUGO(任何用户都有读权限)  S_IWUSR(允许root用户


修改参数)


示例代码:
 int x=1;
 int char *str;
 module_param(a,int,S_IRUGO);
 module_param(str,charp,S_IRUGO);




示例代码:
parm.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>


MODULE_LICENSE("GPL");


static char *name= "yue";
statice int age=29;


module_param(age,int S_IRUGO);
module_param(name,charp,S_IRUGO);


static int __init hello_init(){
printk(KERN_EMERG"first name: %s\n",name);
printk(KERN_EMERG"age: %s\n",age);
return 0;
}


static void __exit hello_exit(){
printk("hello exit!\n");
}


module_init(hello_init);
module_exit(hello_exit);


运行结果:
[retacn@localhost tools]$insmod param.ko age=30






内核符号导出
/proc/kallsyms 记录了内核中所有导出的符号的名字和地址
EXPORT_SYMBOL(符号名)
EXPORT_SYMBOL_GPL(符号名) 保能用于包含GPL许可证的模块


示例代码如下:
calculate.c
#include <linux/init.h>
#include <linux/module.h>


MODULE_LICENST("GPL");


int add_integer(int a,int b){
return a+b;
}


int sub_integer(int a,int b){
return a-b;
}


static int __init sym_init(){
return 0;
}


static void __exit sym_exit(){


}


module_init(sym_init);
module_exit(sym_exit);


#符号导出
EXPORT_SYMBOL(add_integer);
EXPORT_SYMBOL(sub_integer);


hello.c
#include <linux/module.h>
#include <linux/init.h>


MODULE_LICENSE("GPL");
MODULE_AUTHOR("retucn yue");
MODULE_DESCRIPTION("Hello world module");
MODULE_ALLAS("a simplest module");


extern int add_integer(int a,int b);
extern int sub_integer(int a,int b);


extern int add(int a,int b);
static int __int hello_init(){
int res=add_integer(1,2);
printk("res:%d\n",res);
}


static void __exit hello_exit(){
int res=sub_integer(2,1);
printk("hell world exit\n");
}


module_init(hello_init);
module_exit(hello_exit);






内核打印
printk 可以通过附加不同的优先级来对消息分类


KERN_EMERG  紧急消息 0
KERN_ALERT 立即行动的消息 1
KERN_CRIT 严重情况 2
KERN_ERR 错误情况 3
KERN_WARNING 有问题的警告 4(默认)
KERN_NOTICE 正常情况 5 
KERN_INFO 信息型消息 6
KERN_DEBUG 用作调试消息 7


原创粉丝点击