Linux内核编译与开发的示例分析

37次阅读
没有评论

这篇文章将为大家详细讲解有关 Linux 内核编译与开发的示例分析,丸趣 TV 小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。

一.Linux 内核简介

linux kernel map:

Linux 内核编译与开发的示例分析

linux 系统体系结构:

Linux 内核编译与开发的示例分析

linux kernel 体系结构:

arm 有 7 种工作模式,x86 也实现了 4 个不同级别 RING0-RING3,RING0 级别 ***,

这样 linux 用户代码运行在 RING3 下,内核运行在 RING0, 这样系统本身就得到了

充分的保护

用户空间 (用户模式) 转到内核空间 (系统模式) 方法:

系统调用

硬件中断

linux kernel 体系结构:

Linux 内核编译与开发的示例分析

虚拟文件系统 VFS:

VFS(虚拟文件系统)隐藏各种文件系统的具体细节,为文件操作提供统一的接口

二.Linux 内核源代码

linux 内核下载 www.kernel.org

目录结构:

解压 linux kernel tar 后目录

arch: 根据 cpu 体系结构不同而分的代码

block: 部分块设备驱动程序

crypto: 加密,压缩,CRC 校验算法

documentation: 内核文档

drivers: 设备驱动程序

fs(虚拟文件系统 vfs): 文件系统

include: 内核所需的头文件,(与平台无关的头文件在 include/linux 中)

lib: 库文件代码(与平台相关的)

mm: 实现内存管理,与硬件体系结构无关的(与硬件体系结构相关的在 arch 中)

net: 网络协议的代码

samples: 一些内核编程的范例

scripts: 配置内核的脚本

security:SElinux 的模块

sound: 音频设备的驱动程序

usr:cpio 命令实现,用于制作根文件系统的命令(文件系统与内核放到一块的命令)

virt: 内核虚拟机

linux DOC 编译生成:

linux 源根目录 /Documentation/00-INDEX: 目录索引

linux 源根目录 /Documentation/HOWTO: 指南

生成 linux 内核帮助文档: 在 linux 源根目录(Documentation) 执行 make htmldocs

ubuntu16 下需要执行 sudo apt-get install xmlto 安装插件才可生成 doc 文档

后面开发中经常要改的是 arch,drivers 中的代码

三.Linux 内核配置与编译

清理文件(在 linux 源码根目录):

make clean: 只清理所有产生的文件

make mrproper: 清理所有产生的文件与 config 配置文件

make distclean: 清理所有产生的文件与 config 配置文件,并且编辑过的与补丁文件

配置(收集硬件信息如 cpu 型号,网卡等 …):

make config: 基于文本模式的交互配置

make menuconfig: 基于文本模式的菜单模式(推荐使用)

make oldconfig: 使用已有的.config, 但会询问新增的配置项

make xconfig: 图形化的配置(需要安装图形化系统)

配置方法:

1)使用 make menuconfig 操作方法:

1 按 y: 编译 连接 镜像文件

2 按 m: 编译

3 按 n: 什么都不做

4 按 空格键 :y,n 轮换

配置完并保存后会在 linux 源码根目录下生成一个.config 文件

注意:在 ubuntu11 上要执行 apt-get install libncurses5-dev 来安装支持包

2)利用已有的配置文件模板(.config)

1 linux 源码根目录 /arch/ cpu 架构 /configs/ 具体某一的 CPU 文件,把里面对应的文件 copy 并改名为.config 至 linux 源码根目录下

2 利用当前运行已有的文件 (要用 ls /boot/  - a 查看) 把 /boot/config-2.6.18-53.e15 拷贝并改名为.config 至 linux 源码根目录下执行以上操作就可以用 make  menuconfig 在拷贝

.config 文件上面修改文件了

编译内核:

1)make zImage

2)make bzImage

区别: 在 X86 平台上,zimage 只能用于小于 512k 的内核

获取详细编译信息:make zimage V=1 或 make bzimage V=1

编译好的内核在:arch/ cpu /boot/ 目录下

注意:在把.config 配置文件 cp 到根目录编译内核前,必须进入 make menuconfig 并保存退出(否则生不了效)

编译并安装模块:

1)编译内核模块:make modules

2)安装内核模块:make modules_install INSTALL_MOD_PATH=/lib/modules

更换本机器内核: 将编译好的内核模块从内核源码目录 copy 至 /lib/modules 下

制作 init ramdisk(): 输入执行命令 mkinitrd initrd-2.6.39(任意)  2.6.39(可通过查询 /lib/modules 下的目录得到)

注意:

mkinitrd 命令为 redhat 里面的,ubuntu 的命令为:mkinitramfs -k /lib/modules/ 模块安装位置 -o  initrd-2.6.39(任意) 2.6.39(可通过查询 /lib/modules 下的目录得到)

如果 ubuntu 里面没有 mkinitramfs 命令可以用 apt-get install initrd-tools 进行安装

安装内核模块:

1)手动

1 cp linux 根目录 /arch/x86/boot/bzImage /boot/mylinux-2.6.39

2 cp linux 根目录 /initrd-2.6.39 /boot/initrd-2.6.39

*** 修改 /etc/grub.conf 或 /etc/lilo.conf 文件

2)自动

1 make install: 这个命令会自动完成上面的操作(查看当前内核版本:uname -r)

—————————————————————————–

四.linux 内核模块开发

描述:

linux 内核组件非常庞大,内核 ximage 并不包含某组件,而是在该组件需要被使用的时候,动态的添加到正在运行的内核中(也可以卸载),这种机制叫做“内核模块”的机制。内核模块通常通过使用 makefile 文件对模块进行编译

模块安装与卸载:

1)加载:insmod hello.ko

2)卸载:rmmod hello

3)查看:lsmod

4)加载(自动寻找模块依赖):modprobe hello

modprobe 会根据文件 /lib/modules/version/modules.dep 来查看要加载的模块,看它是否还依赖于其他模块,如果是, 会先找到这些模块,把它们先加载到内核

实例分析:

1)moduleDep/1(一个模块的编译)

 1 #include  linux/module.h  2 #include  linux/init.h  3 4 // 模块入口函数  5 //__init: 表示代码段中的子段, 里面的内容只运行一次并且回收内存. 6 static int __init hello_init(void) 7 { 8 printk(KERN_EMERG  hello world!\n  9 return 0;10 }11 // 模块卸载函数 12 //__exit:13 static void __exit hello_exit(void)14 {15 printk(KERN_EMERG  hello exit!\n 16 }17 // 内核符号导出   函数 18 int add_integar(int a,int b)19 {20 return a+b; 21 }22 int sub_integar(int a,int b)23 {24 return a-b; 25 }26 27 module_init(hello_init);28 module_exit(hello_exit);29 // 函数导出 30 EXPORT_SYMBOL(add_integar);31 EXPORT_SYMBOL(sub_integar);

makefile:

#*** 次执行 KERNELRELEASE 是空的, 所以执行 else 里面的  ifneq ($(KERNELRELEASE),) obj-m :=hello.o #else 块  elseKDIR:= /lib/modules/2.6.18-53.el5/build all: #KDIR  依赖内核模块源代码路径(内核编译安装路径) #PWD  表示内核代码在哪(当前目录) #modules  编译的是模块  make -C $(KDIR) M=$(PWD) modules clean: rm -f *.ko *.o *.mod.o *.mod.c *.symvers *.order endif

2)moduleDep/2(两个模块的编译)

#include  linux/module.h  #include  linux/init.h  // 模块可选信息  MODULE_LICENSE(GPL // 许可证声明  MODULE_AUTHOR( liyuan // 作者声明  MODULE_DESCRIPTION( This module is a param example. // 模块描述  MODULE_VERSION( V1.0 // 模块别名  MODULE_ALIAS( a simple module // 模块别名  // 模块参数  static char *name =  liyuan arg  static int age = 30; //S_IRUGO 是参数权限,也可以用数字  module_param(age,int,S_IRUGO); module_param(name,charp,S_IRUGO); // 使用外部文件函数  extern int add(int a,int b); // 声明   外部内核符号   函数  extern int add_integar(int a,int b); extern int sub_integar(int a,int b); static int __init mains_init(void) { // 多文件编译  printk(KERN_EMERG param hi  int vle=add(1,2); printk(KERN_EMERG add value:%d\n ,vle); // 模块参数  printk(KERN_EMERG  name : %s\n ,name); printk(KERN_EMERG  age : %d\n ,age); // 使用其他模块的函数(内核符号导出) int adds=add_integar(3,1); int subs=sub_integar(3,1); printk(KERN_EMERG  add_integar : %d\n ,adds); printk(KERN_EMERG  sub_integar : %d\n ,subs); return 0; } static void __exit mains_exit(void) { printk( param exit!  } module_init(mains_init);52 module_exit(mains_exit);

add.c

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

makefile

ifneq ($(KERNELRELEASE),) #两个以上内核源文件   生成单独的内核模块名 ma #内核 ma obj-m :=ma.o # 下面的 ma-objs 前面必须和上面一样为 ma ma-objs := mains.o add.oelseKDIR:= /lib/modules/2.6.18-53.el5/build all: make -C $(KDIR) M=$(PWD) modules clean: rm -f *.ko *.o *.mod.o *.mod.c *.symvers *.order endif

运行带参模块:insmod hello.ko name=yuan age=12

内核符号导出(/proc/kallsyms 记录了内核中所有导出的符号的名字与地址):

一个内核模块的运行依赖另一个内核模块的函数实现,必须先运行 *** 个内核模块,这样就需要进行内核符号导出。

注意:

错误信息:disagrees about version of symbol struct_module insmod:error inserting  …

开发内核模块时会出现,内核模块不匹配的情况. 是你当前运行的 linux 内核与编译连接所依赖的

内核版本不匹配,解决方法:

使用 modprobe –force-modversion 强行插入

可使用 uname - r 进行查看当前运行的内核版本

printk 内核打印:

在 linux/kernel.h 中 printk 有 8 个优先级,按优先级递减的是:

KERN_EMERG 0

用于紧急的消息,常常是那些崩溃的消息

KERN_ALERT 1

需要立刻行动的消息

KERN_CRIT 2

严重情况

KERN_ERR 3

错误情况

KERN_WARNING(printk 默认级别) 4

有问题的警告

KERN_NOTICE 5

正常情况,但是仍然值得注意

KERN_INFO 6

信息消息

KERN_DEBUG 7

用作调试消息

不管是哪个级别的都会在 /var/log/messages 里面打印出来 (messages 可以删除后,运行内核进行测试内核打印情况) 控制台打印(优先级配置 /proc/sys/kernel/printk)

6 4 1 7

Console_loglevel

Default_message_loglevel

Minimum_console_level

Default_console_loglevel

在 vm+redhat 安装 2.6.39 内核时出现的错误

启动时报 could not find filesystem /dev/root

解决方法

a. 通过 make menuconfig 选中以下对应的选项

General setup —

[*] enable deprecated sysfs features to support old userspace tools

成功时下面那个也 * 了的

b. 修改.config 文件

修改.config 文件中 CONFIG_SYSFS_DEPRECATED_V2,将原本被注释掉的

CONFIG_SYSFS_DEPRECATED_V2 改成 CONFIG_SYSFS_DEPRECATED_V2=y

关于“Linux 内核编译与开发的示例分析”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。