linux为啥要编译内核

Posted

tags:

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

新手,不懂,希望讲的低级点,以下是几个问题。
1:平时在linux下c编程,也没有用到编译内核什么的,经常看到“内核源码树”这个词汇,就不懂的。难道我正在使用的这个linux系统不是编译出来的一个系统吗?为什么还要再编译一次?
2:下载源码后编译出来的东西,和我正在使用的linux系统,差别在哪。
3:想学习linux驱动,必须要买板子吗?现在真没头绪啊。

Linux内核版本是不断更新的,通常,更新的内核会支持更多的硬件,具备更好的进程管理能力,运行速度更快、 更稳定,并且一般会修复老版本中发现的许多漏洞等。而已安装好的Linux系统如果不是滚动升级的,或者没有内核更新选择的话,如果用户想要使用这些新特性,或想根据自己的硬件平台定制一个更高效,更稳定,更快速的内核,就需要重新编译内核。

下载源码编译内核,如果不做相关优化,直接编译,结果就跟现在正在使用的系统没什么区别。

学习linux驱动,必须要有实践的平台环境吧,至于需不需要购置平台,要看你的学习目的了。追问

还是不太理解。比如,我装了redhat 9,内核版本是2.6,我在官网下载了3.0的内核代码,然后我在机器上编译后,结果是什么?这些编译的结果代替了我现有系统,也就是我的redhat内核版本变成3.0?如果不是,那目的是什么的?

追答

新旧内核是共存于/boot下的,由grub引导菜单选择不同的内核启动系统。
如果编译的内核运行正常,可以删除原内核,也可以保留。如果新内核有问题,还可以用原来的内核引导进入系统,重新配置内核选项编译。

参考技术A 因为linux是一个开源的操作系统,提供了强有力的开放接口,允许用户自行开发、修改,从而可能会有用户的的系统经过修改,不再是一个固有的东西,这是就需要编译内核 参考技术B 编译出的不同系统就跟你用的QQ软件的不同版本一样,有不同的功能,来满足不同的需要,内核源码树就是内核代码的目录 参考技术C 内核的任务是管理 内存,CPU,磁盘,外部设备驱动程序的集合,也就是传统意义上的操作系统,内核代码树就是指内核的源代码。你用的Linux系统是由内核以及gnome桌面应用程序和shell命令管理模块构成。内核只能保证机器正常运行,只是没有桌面的枯燥的操作系统而已。 参考技术D 1.这是因为内核源码里面有一些头文件。
2.系统里有一些必要的组件,内核则没有。
3.想买就买,有总比没有好

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内核编译

为啥在编译 Linux 内核和 uBoot 时使用 arm-linux-gnueabi-gcc 而不是 arm-none-eabi-gcc?

pthread.h不属于linux内核,但是为啥很多内核源码中include了pthread.h

不修改Linux内核文件,直接用makefile编译驱动,是否要先把内核编译一遍?

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

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