Linux内核配置编译以及模块开发

Posted _WILLPOWER_

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux内核配置编译以及模块开发相关的知识,希望对你有一定的参考价值。

Linux内核简介

Linux体系结构


Linux由用户空间和内核空间组成

现代CPU通常实现了不同的工作模式,以ARM为例,实现了7种工作模式:
用户模式( usr)、快速中断(fiq)、外部中断(irq)、管理模式( svc)、数据访问中止(abt)、系统模式(sys)、未定义指令异常(und)

X86也实现了4个不同的级别:Ring0-Ring3。Ring0下,可以执行特权指令,可以访问IO设备等,在Ring3则有很多限制。Linux系统利用了CPU的这一特性,使用了其中的两级来分别运行Linux内核与应用程序,这样使操作系统本身得到充分的保护。例如:如果使用X86,用户代码运行在Ring3,内核代码运行在Ring0。

内核空间与用户空间是程序执行的两种不同状态,通过系统调用和硬件中断能够完成从用户空间到内核空间的转移。

Linux内核架构

虚拟文件系统

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

内核源码结构


arch目录

arch是architecture的缩写。内核所支持的每种CPU体系,在该目录下都有对应的子目录。每个CPU的子目录,又进一步分解为boot,mm,kernel等子目录,分别包含控制系统引导,内存管理,系统调用等。

documentation
内核的文档

drivers目录
设备驱动程序

include目录
内核所需要的头文件。与平台无关的头文件在include/linux子目录下面,与平台有关的头文件则放在对应的子目录中。

fs目录
存放各种文件系统的实现代码。每个子目录对应一种文件系统的实现,公用的源程序用于实现虚拟文件系统vfs.

net目录
网络协议的实现代码

Linux内核配置与编译

  • 配置内核

    • 为什么需要配置内核
    • 如何配置内核
      • make config
      • make menuconfig
    • 内核配置结果
  • 编译内核

    • make zlmage
    • make bzlmage
  • 编译内核模块

    • make modules
    • make modules_install
  • 安装内核

  • 清理内核

    • make clean
    • make distclean

为什么要配置内核?

  1. 硬件的需求
  2. 软件的需求
    选出需要的,去掉不需要的

内核配置方法

make config: 基于文本模式的交互式配置
make menuconfig: 基于文本模式的菜单型配置(更直观高效)

取值方式
<*> 内核镜像直接带有该功能
<m> 内核模块方式导入该功能,模块导入的功能不是随时都要用的,需要的时候才会加入到内存中运行,不需要的时候不加载。
<> 不选择该功能

配置后的结果保存在.config

要使用内核配置文件简化配置

编译内核

区别:在X86平台,zImage只能用于小于512K的内核
如需获取详细编译信息,可使用:
make zImage V=1
make bzImage V=1
编译好的内核位干arch//boot/目录下

过程

获取源码
官方网站链接

在这里面选择你想要的源码


在文件目录中
然后将本机的配置文件复制过来,节省自己配置的时间
cp /boot/config-5.11.0-27-generic ./.config


然后使用make menuconfig



然后使用tab键EXIT即可
然后使用
make bzImage
完成后使用
make modules
然后使用
make module_install
然后制作init ramdisk

在centos中使用mkinitrd
方法:
mkinitrd initrd-\\$version \\$version
例:
mkinitrd initrd-2.6.39 2.6.39
*$version可以通过查询/lib/modules下的目录得到

在ubuntu中使用mkinitramfs
mkinitramfs 5.9.0 -o /boot/initrd-5.9.0

安装内核
ubuntu命令安装内核源码及升级内核源码

cp arch/x86/boot/bzImage /boot/vmlinuz-5.9.0
将System.map复制至/boot下:
cp System.map /boot/System.map-5.9.0

如果开机没有内核选择界面
Ubuntu 系统开机 Grub 界面的开启和关闭

在 /etc/default/grub 里面找到
GRUB_TIMEOUT_STYLE=hidden
GRUB_HIDDEN_TIMEOUT=0
两个注释掉
然后使用
sudo update-grub2
重启选择advance选项,选择最新的内核

如果开机还是没有,那就再开机进入登录管理器后,选择poweroff,重启即可

然后使用unamr -r确定当前使用的内核版本

Linux内核模块开发

  • 什么是内核模块
  • 内核模块设计
    • 主体部分设计
    • 编译内核模块
    • 安装/卸载内核模块
    • 可选项使用
      • 模块申明
      • 模块参数
      • 符号输出
  • 内核打印

什么是内核模块

Linux内核的整体结构非常庞大,其包含的组件也非常多,如何使用这些组件呢?
方法1:把所有的组件都编译进内核文件,即: zImage或bzImage,但这样会导致一个问题:内核文件过大,占用内存过多.
有没有一种机制能让内核文件本身并不包含某组件,而是在该组件需要被使用的时候,动态地添加到正在运行的内核中呢?

内核模块设计

helloworld.c

#include <linux/module.h>
#include <linux/init.h>
MODULE_LICENSE("GPL");//必须要加这句,不加报错
static int hello_init(void)
{
    printk(KERN_WARNING "Hello, world!\\n");
    return 0;
}

static void hello_exit(void)
{
    printk(KERN_INFO "Goodbye, world\\n");
}

module_init(hello_init);
module_exit(hello_exit);

Makefile

obj-m := hello.o

KDIR := /lib/modules/`uname -r`/build

all:
	make -C $(KDIR) M=$(PWD) modules

如果有多个文件要生成内核模块
Makefile

obj-m := test.o
test-objs := hello.o hello1.o
KDIR := /lib/modules/`uname -r`/build

all:
	make -C $(KDIR) M=$(PWD) modules

安装与卸载

安装 insmod
insmod hello.ko
卸载 rmmod
rmmod hello
查看 lsmod

模块可选信息

  • 模块申明
  • 模块参数
  • 符号输出

模块申明

  1. MODULE_LICENSE(“遵守的协议”)
  2. MODULE_AUTHOR(“作者”)
  3. MODULE_DESCRIPTION(“模块功能描述”)
  4. MODULE_VERSION(“V1.0版本”)

模块参数

  1. 内核模块可以通过命令行输入参数

通过宏module param指定保存模块参数的变量。模块参数用于在加载模块时传递参数给模块。
module_param(name ,type,perm)
name:变量的名称
type:变量类型,bool:布尔型i nt:整型 charp:字符串型
perm是访问权限。S_IRUGO:读权限 S_IWUSR:写权限

例;
int a = 3;
char *st;
module_param(a , int , S_IRUGO);
module_param(st,charp, S_IRUGO);

#include <linux/module.h>
#include <linux/init.h>
MODULE_LICENSE("willpower");

int a = 9;
module_param(a, int, S_IRUGO);
static int hello_init(void)
{
    printk("a is %d\\n", a);
    printk(KERN_WARNING "Hello, world!\\n");
    return 0;
}

static void hello_exit(void)
{
    printk(KERN_INFO "Goodbye, world\\n");
}

module_init(hello_init);
module_exit(hello_exit);

符号导出

为什么到导出符号?
申明此函数是可以其他文件来使用的

内核符号的导出使用宏
EXPORT_SYMBOL(符号名)
EXPORT_SYMBOL_GPL(符号名)
说明:
其中EXPORT_SYMBOL_GPL智能包含用于包含GPL许可证的模块

总结-对比应用

对比应用程序,内核模块具有以下不同:

  1. 应用程序是从头(main)到尾执行任务,执
    行结束后从内存中消失。
  2. 内核模块的初始化函数结束时,模块仍然
    存在于内核中,直到卸载函数被调用,模块才从内核中消失。

内核打印
printk是内核中出现最频繁的函数之一,通过将printk与printf对比,将有助于理解。
相同点:

  • 打印信息
    不同点:
  • printk在内核中使用,printf在应用程序中使用
  • printk允许根据严重程度,通过附加不同的“优先级”来对消息分类。

在<linux/kernel.h>中定义了8种记录级别。按照优先级递减的顺序分别是:

KERN_EMERG	   “<0>”       用于紧急消息,常常是那些崩溃前的消息。
KERN_ALERT     “<1>"      需要立刻行动的消息。
KERN_CRIT	   “<2>"  	   严重情况。
KERN_ERR	   “<3>"       错误情况。

没有指定优先级的printk默认使用
DEFAULT_MESSAGE_LOGLEVEL优先级,它是一个在kernel/printk.c中定义的整数。

编译问题

在ubuntu16.04中编译成功了linux2.6.39版本,18.04及其以上没有成功

编译内核错误:Can’t use ‘defined(@array)’ (Maybe you should just omit the defined()?) at kernel/timeconst.p…

参考文章

linux/compiler-gcc9.h:没有那个文件或目录

include/linux/的compiler-gcc3.h复制一份,改为compiler-gcc9.h的名字

编译内核出现:cc1: error: code model kernel does not support PIC mode

参考文章

‘make menuconfig’ requires the ncurses libraries

安装libncurses5-dev

/bin/sh: 1: flex: not found

sudo apt install flex -y

/bin/sh: 1: bison: not found

sudo apt install bison -y

fatal error: openssl/opensslv.h: 没有那个文件或目录

sudo apt install libssl-dev

make[1]: *** 没有规则可制作目标“debian/canonical-certs.pem”

以上是关于Linux内核配置编译以及模块开发的主要内容,如果未能解决你的问题,请参考以下文章

linux内核模块编译makefile

linux驱动开发-模块驱动

Linux驱动linux内核模块简介

在linux中编写了一个小的内核模块,怎么编译成.ko文件?

Linux驱动基础开发

Linux内核开发_1_编译LInux内核