linux内核配置编译以及模块开发(代码片段)

_WILLPOWER_ _WILLPOWER_     2023-01-06     494

关键词:

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内核开发_1_编译linux内核(代码片段)

目录1.准备工作1.1学习环境1.2下载Linux内核源码1.3解压Linux内核1.4目录结构介绍2.Linux内核配置2.1配置选项1.makeconfig2.makemenuconfig3. makegconfig3开始配置1.配置解释Generalsetup通用选项Enableloadablemodulesupport可加载模块Enabletheblocklayer块设备... 查看详情

linux内核开发_1_编译linux内核(代码片段)

目录1.准备工作1.1学习环境1.2下载Linux内核源码1.3解压Linux内核1.4目录结构介绍2.Linux内核配置2.1配置选项1.makeconfig2.makemenuconfig3. makegconfig3开始配置1.配置解释Generalsetup通用选项Enableloadablemodulesupport可加载模块Enabletheblocklayer块设备... 查看详情

树莓派linux内核配置编译以及烧录详细步骤(代码片段)

目录一、内核配置第一种方式:(cp厂家.config.config)第二种方式(makemenuconfig一项项配置,通常是基于厂家的config来配置)二、内核编译三、烧录1、创建两个文件夹2、挂载u盘3、安装modules4、安装更新kernel... 查看详情

linux内核配置和编译原理&menuconfigmakefile.config三者之间的关系(代码片段)

1、内核的配置体系内核是高度可裁剪的,开发产品时根据产品的需求将无用的模块裁剪掉,也就是不要编译进内核,这样编译出来的内核体积小,节省内存,还可以节省性能。由此就需要条件编译,但是... 查看详情

linux内核移植入门(代码片段)

文章目录基本概念内核源码目录结构内核配置主目录Makefile各子目录Makefile如何配置内核?1.配置仓库选取2.交叉编译器的修改3.体系结构体的选择4.修改配置文件内核编译编译结果:几种linux内核文件的区别开发板上U-Boot启动linux内核... 查看详情

linux下wifi模块使用:iw工具交叉编译以及配置(代码片段)

...工具,它替代了Wirelesstools中的iwconfig,支持最近已添加到内核所有新的驱动程序,有两种加密认证加密方式:open(开放系统认证+有效等线加密)、wep方式(共享秘钥认证+有效等线加密)。iw工具的交叉编译1.iw依赖libnl库,首先... 查看详情

linux3.5内核模块开发编程(代码片段)

1.1Linux内核模块介绍1.1.1Linux内核模块概述嵌入式设备驱动开发中将驱动程序以模块的形式发布,更是极大地提高了设备使用的灵活性——用户只需要拿到相关驱动模块,再插入到用户的内核中,即可灵活地使用你的设... 查看详情

linux内核编译linux内核⑦(安装内核模块|安装内核|重启系统|查看当前内核版本)(代码片段)

文章目录一、安装内核模块二、安装内核三、重启系统四、查看当前内核版本一、安装内核模块确保Linux内核编译完成,没有任何报错之后;参考【Linux内核】编译Linux内核⑥(安装OpenSSL|安装其它依赖库|内核编译完成)博客;进入Linux... 查看详情

linux内核移植初探(代码片段)

内核移植的梯度:初级:根据芯片公司的参考配置,编译开发板内核并了解执行过程中极:添加内核驱动的方式方法高级:修改或添加BSP包linux内核特性:可移植性强、支持的硬件平台广泛;超强的网络功能;多任务多用户系统... 查看详情

linux3.5内核模块开发编程(代码片段)

1.1Linux内核模块介绍1.1.1Linux内核模块概述嵌入式设备驱动开发中将驱动程序以模块的形式发布,更是极大地提高了设备使用的灵活性——用户只需要拿到相关驱动模块,再插入到用户的内核中,即可灵活地使用你的设... 查看详情

编译安装内核(代码片段)

编译安装内核升级内核到linux-4.20.3.tar.xz查看当前内核版本:[[email protected]data]#uname-r3.10.0-862.el7.x86_64获取内核源代码包:www.kernel.orglinux-4.20.3.tar.xz==实施步骤1.安装编译所需的工具gccncurses-develmake(开发工具)2.下载内核源码a.w... 查看详情

配置介绍(代码片段)

1.1常用命令    当前uboot的配置已经完全变成Linux内核的配置形式了,完全可以按照Linux内核的分析方是区分析uboot。  uboot和 Linux的代码配置项由Kconfig来完成的,关于Kconfig语法,可参见:linux/Documentation/kbuild/kconfig-language.tx... 查看详情

配置介绍(代码片段)

1.1常用命令    当前uboot的配置已经完全变成Linux内核的配置形式了,完全可以按照Linux内核的分析方是区分析uboot。  uboot和 Linux的代码配置项由Kconfig来完成的,关于Kconfig语法,可参见:linux/Documentation/kbuild/kconfig-language.tx... 查看详情

配置介绍(代码片段)

1.1常用命令    当前uboot的配置已经完全变成Linux内核的配置形式了,完全可以按照Linux内核的分析方是区分析uboot。  uboot和 Linux的代码配置项由Kconfig来完成的,关于Kconfig语法,可参见:linux/Documentation/kbuild/kconfig-language.tx... 查看详情

linux驱动模块编译进内核中

Linux驱动模块编译进内核中BQ27501驱动编译进内核一、       驱动程序编译进内核的步骤在linux内核中增加程序需要完成以下三项工作:1.将编写的源代码复制到Linux内核源代码的相应目录;2.在目录的Kconfig文件中增加新... 查看详情

linux系统移植:原厂kernel移植到开发板(代码片段)

...Linux系统移植:原厂Kernel移植到开发板一、获取原厂内核并编译二、内核启动测试三、添加自己板子文件3.1板子配置文件3.2板子设备树3.3编译四、重要配置修改4.1主频修改4.2EMMC驱动修改4.3网络驱动修改4.4保存修改后配置文件... 查看详情

linux驱动开发笔记:基于ubuntu的helloworld驱动源码编写makefile编写以及驱动编译加载流程测试(代码片段)

...装虚拟机的过程请自行搜索查找完成。  步骤二:获取内核版本号  获取内核版本号是为了确认内核版本号一致。sudocat/proc/version  步骤三:校准编译器版本  前面获取了内核的编译器版本是gcc7.3.0,但是本机是gcc7.5,... 查看详情

linux驱动实践:带你一步一步编译内核驱动程序(代码片段)

...#43;、嵌入式、Linux。文章目录学习的困惑实践环境编译进内核创建驱动程序目录创建源文件创建Kconfig文件创建Makefile文件编译编译为驱动模块编译所有的驱动模块只编译hello这一个驱动模块验证一下资料下载别人的经验,我... 查看详情