手把手教你傻瓜式编译linux5.13内核与启动镜像(内置驱动)

本教程是我四天来总结的经验,期间编译了4.19.142和5.13两个版本的内核,打包了20多次initrd,踩了无数坑,希望对大家有帮助!觉得有用的话点个赞吧
咱是15岁学生,制作不易…

预计阅读时间20-30分钟,操作时间1-2小时(不含编译)

一.制作目的

1.要做一个能运行的linux kernel,并且不需要外挂.ko内核模块就能加载常用驱动(如SATA&USB)
2.使用busybox制作最小initrd(不含modules也能正常使用的),并且能正常检测硬盘并挂载等等功能

二.准备工作

1.跑Ubuntu的电脑一台,或者是虚拟机(*这回是现钱,CPU要好!*)

2.安装可能需要的lib
sudo apt-get install make gcc fakeroot build-essential ncurses-dev xz-utils libssl-dev bc flex libelf-dev bison
(如编译过程中有缺少其他依赖的报错也请一并安装)

3.获取以下源码linux-kernel-5.13 & busybox-1.33.1
linux-kernel可以从腾讯云下载linux-kernel-x.xx.xx.tar.gz压缩包,busybox找官网下压缩包(注意别下成可执行文件,一定要源码!)就行
4.把你下的东西cp到你自己的目录里,比如我是~/LinuxSource,这个目录其实挂载在一块NTFS格式的虚拟硬盘上(不推荐用NTFS格式,但事实证明没有什么问题)
5.全过程建议使用root用户

三.配置内核

0.讲一下为什么要驱动打进内核

因为正常驱动要用.ko模块加载的,咱直接给他跳过这一部分,为的是最小通用镜像嘛,不需要加载模块,也方便(*并不,主要是懒*)

1.解压你的内核源码压缩包
gzip -d linux-kernel-5.13.tar.gz

于是你发现有一个tar文件出现了!解了他!

tar -x -f linux-kernel-5.13.tar

tar解压可能比较慢,稍安勿躁,还可能会有无法提取文件的报错,一般情况下没问题忽略即可
解压之后看一下生成目录里的东西是不是跟压缩包里差不多,如果差不多就差不多了

2.开始配置内核
cd linux-kernel-5.13
make menuconfig

如果你的lib安装全了的话,是可以正常进入menuconfig的,报错了就安lib
menuconfig可能会出现加载不出来卡住的情况,按两下回车就好了

3.进入menuconfig了
手把手教你傻瓜式编译linux5.13内核与启动镜像(内置驱动)_第1张图片

写的很清楚,空格键换模式,上下键换目标,左右键换功能,回车确认,M是编译成模块(本教程不讨论),留空是不要,*是打进内核

然后我们进去General setup
手把手教你傻瓜式编译linux5.13内核与启动镜像(内置驱动)_第2张图片

右下角有v(+)说明可以向下翻页,有—>说明回车里面有子菜单

第一项留空,第二项我给他起名叫-all-in-one也就是(驱动)全都打包
进内核,
手把手教你傻瓜式编译linux5.13内核与启动镜像(内置驱动)_第3张图片
init位置是/sbin/init (busybox init的位置),设备名随便起一个,你也给他叫gensoukyo都没事
这个菜单配置完了,选Exit退出

好的,我们现在在主菜单选Firmware Drivers
再进入有EFI关键字的那个选项(如果你需要UEFI启动内核的话请务必,使用传统bios可忽略)

手把手教你傻瓜式编译linux5.13内核与启动镜像(内置驱动)_第4张图片
把EFI开头的都选上*(即打进内核)才能支持UEFI启动

现在退到主菜单
进入Device Drivers
这一部分操作就多了,准备好把空格键按烂吧,我们要把大量常用驱动打进去
进入Block devices
手把手教你傻瓜式编译linux5.13内核与启动镜像(内置驱动)_第5张图片
把除了IDE那个部分的以外的全打上*
带debug的不用打,不能的留M,下同

然后往下找到Default ramdisk size
默认应该是65536KB(64MB),我们给他改成131072KB(128M)大一点还是好的,毕竟现在机子都不缺那点内存
手把手教你傻瓜式编译linux5.13内核与启动镜像(内置驱动)_第6张图片
好的,我们现在返回Device drivers
进NVME support,能*全就全打上

返回
进SCSI/啥啥啥的 那个,能*就全打上

返回
进Serial ATA /啥啥啥的那个(即SATA和PATA驱动),能*就全打上

返回
进Network/那个 配置网络驱动,能*全打上

返回
往下翻,找到USB Support
手把手教你傻瓜式编译linux5.13内核与启动镜像(内置驱动)_第7张图片
能*全打上

至此,驱动打完了

让我们返回到主菜单
进File System(文件系统选项)
Ext2,Ext3,Ext4全部选上,把你不认识的都留空或者默认不管他
手把手教你傻瓜式编译linux5.13内核与启动镜像(内置驱动)_第8张图片
下翻,找FAT文件系统
手把手教你傻瓜式编译linux5.13内核与启动镜像(内置驱动)_第9张图片
里面有FAT和NTFS的选项,选上
手把手教你傻瓜式编译linux5.13内核与启动镜像(内置驱动)_第10张图片
返回,找到Native language support配置显示语言
找到简中(SC)和繁中(TC)选上,最下面的UTF8也要上

回到主菜单,存一下你的.config文件,至此,内核配置结束

简单来说,你认识的,知道干嘛的,觉得有用的驱动都可以给他干进去,无非就是内核体积大点
不过也不会大太多,按照本文的配置编译bzImage(压缩内核镜像)也就15MB左右

4.顺便讲一下编译之后都生成了啥

1.linux-5.13/vmlinux
这是一个非常大的,不压缩的内核镜像,不适于启动系统

2.linux-5.13/System.map
System.map用于存放内核符号表信息。符号表是所有符号和其对应地址的一个列表,随着每次内核的编译,就会产生一个新的对应的System.map文件,当内核运行出错时,通过System.map中的符号表解析,就可以查到一个地址值对应的变量名,或反之。

3.linux-5.13/modules.buidin
该文件记录了编译进内核的模块,也就是咱们刚刚打的驱动之类的

4.linux-5.13/arch/x86/boot/bzImage
这个就是咱们要的bzImage,也就是压缩的,可以启动的内核镜像,启动系统就用他配合initrd

5.linux-5.13/arch/x86/boot/compressed/*
这些是其他压缩过的内核镜像之类的,比较混乱,咱们不管他

6.linux-5.13/usr/*
这里面生成了一些initmfs cpio文件,应该是根据内核配置(本文未提及设置initrd文件目录的操作)自动打包的initrd,经过测试好像不太好用,咱们用自己的initrd,后面会讲到

四.编译内核

请务必看完再编译!!
回到shell

make bzImage -j[线程数]
#我用的是14线程,i7-10870H / 8G RAM,首次编译只需要二十多分钟
#差一点的处理器可能要数小时,这也是要好处理器的原因了

处理报错的预案

注意!如果编译过程中不久就出现了以下报错,赶紧Ctrl C暂停
Error 1
编辑你的.config文件,查找手把手教你傻瓜式编译linux5.13内核与启动镜像(内置驱动)_第11张图片
删掉这一整行
再次编译会让你确认,回车就行,不需要输入y/n

给大家提个醒,你现在直接编译还是会在最后时刻前功尽弃,我编译快可以再来一遍,你们可别踩坑了
手把手教你傻瓜式编译linux5.13内核与启动镜像(内置驱动)_第12张图片

查了一下解决方案,还是编辑.config文件
手把手教你傻瓜式编译linux5.13内核与启动镜像(内置驱动)_第13张图片

再次编译,又有让你确认的,你就一路n就行了

好了,现在你可以放心的编译了,等待过程中不妨研究下busybox的原理

制作initrd

先讲一下initrd的原理

linux2.6之前的initramfs和现在的initrd不一样了,老版本的咱们不讨论,感兴趣的可以查一下,现在的initrd是一个压缩(通常是gz或者是lz4)过的cpio归档文件.

其中包括了一个给内核提供初始化环境的最小根目录,通常情况下初始化完成后要切换到真正的根目录(通过挂载),不过有些嵌入式系统直接使用ramdisk作为根目录了.

initrd由bootloader在加载内核的同时加载进内存,内核解压initrd到虚拟的ramdisk上,作为根目录.

内核启动完毕后会调用初始化进程(通常是/sbin/init),完成用户态之前的初始化(比如创建设备节点,初始化控制台,挂载真正根目录等等)

关于busybox

这里我们用到了busybox制作
busybox是啥?让咱看下百度百科

BusyBox 是一个集成了三百多个最常用Linux命令和工具的软件。BusyBox 包含了一些简单的工具,例如ls、cat和echo等等,还包含了一些更大、更复杂的工具,例grep、find、mount以及telnet。有些人将 BusyBox 称为 Linux 工具里的瑞士军刀。简单的说BusyBox就好像是个大工具箱,它集成压缩了 Linux 的许多工具和命令,也包含了 Android 系统(//此处似乎有误,应为linux)的自带的shell。

通俗的讲,busybox包括了大量可执行程序的功能,甚至包括init,且可以静态编译(即不需要lib亦可运行)
所有生成的命令其实都是指向bin/busybox不同功能的符号链接,说白了二进制文件其实就一个
这里我们主要用它提供的init,sh,mount等功能

开始制作

1.解压你的busybox源码

bzip2 -d busybox-1.33.1.tar.bz2
tar -x -f busybox-1.33.1.tar

2.配置busybox

cd busybox-1.33.1
make menuconfig
#老朋友 menuconfig 又见面了

手把手教你傻瓜式编译linux5.13内核与启动镜像(内置驱动)_第14张图片
相比之下,busybox就简陋多了
打开settings
找到
static
也就是让他静态编译,老规矩,打*

busybox配置就结束了,剩下的咱不用管了,退出,记得保存你的配置

开始编译

make install -j14
#小工程犯不着用多线程 但是我有14线程为什么不用呢?
#不会真的有人嫌程序运行太快吧

编译结束,生成了一个_install目录,我们把东西cp过去

mkdir ./../rootfs
cp _install/* ./../rootfs
cd ./../rootfs
ls
#输出
#bin sbin usr linuxrc
ls sbin
#输出
... ...  ...
... init ...

可以看到,已经有一个根目录的雏形了,并且sbin/init初始化进程也有了
这时候我们要把它完善
或许你注意到,rootfs/linuxrc这个文件,他其实也是指向init的,只不过名字不一样,我们给他改了,防止出问题

mv linuxrc init

现在完善根文件系统

mkdir dev etc mnt proc sys
#生成必要目录
cd dev
mknod console c 5 1
#创建控制台字符设备,没有会导致报错无法运行
mknod null c 1 3
ln null tty0
ln null tty1
ln null tty2
cd ..
#创建tty字符设备,尤其是tty2,没有它控制台会疯狂报错
#注意 特殊设备文件是不能复制的,只能移动,所以如果需要更改工作目录请使用Ctrl+x

目录结构咱已经搞出来了,实际上现在打包就能开机了,只不过是瘸子腿儿走路,啥也干不了,因为初始化没有彻底完成

我们要偷懒用一下Ubuntu的初始化脚本
请把Ubuntu系统的/boot/initrd.img-x.x.x-xx-generic这个initrd文件给他拉过来

cp /boot/initrd.img-5.8.0-55-generic .
ls 
#输出
#rootfs busybox-1.33.1 initrd.img-5.8.0.55-generic

这时候你可以用归档管理器打开,会发现,哎,跟咱们做到initrd结构完全不一样啊?
这就对咯!这个文件其实是个缝合怪,好几个部分拼在一起了
让我康康!

apt install binwalk
#binwalk是一个查看文件结构的利器,会告诉你某个文件什么地方由什么组成
binwalk initrd.img-5.8.0-55-generic
#输出如下图

手把手教你傻瓜式编译linux5.13内核与启动镜像(内置驱动)_第15张图片
奥,原来是这样,它前边是cpio,后面才是打包的initrd
找到输出的第一个正经压缩格式的位置
看来用得是lz4压缩的initrd
lz4
记下来位置

dd if=initrd.img-5.8.0-55-generic bs=4641792 skip=1>>out.lz4
#把它从lz4的位置噶(割)下来
mkdir ubuntu_initrd
lz4 -d out.lz4
#解压第一层lz4
mv out ubuntu_initrd
cd ubuntu_initrd
cpio -idmv#解压第二层cpio
rm -f out
#删了它以绝后患
ls
#输出如下

Ubuntu的initrd结构
我们呢,只需要用到一个文件init和一组文件夹scripts
编辑init可以发现是一个sh文件,里面大概是写的怎么挂载/proc之类的,反正是完成初始化,调用scripts里的sh函数

现在把init和scripts复制过去,剩下的就没用了

cp init ./../rootfs/init.2
#因为已经有一个同名文件了,所以我们给他重命名成init.2,即初始化的第二步
cp -r scripts ./../rootfs
cd ./../rootfs
ls
#输出
#bin dev etc init init.2 lib mnt proc sbin scripts sys usr

然后我们要准备etc目录下的东西,也就是初始化的配置
这些是必要的
手把手教你傻瓜式编译linux5.13内核与启动镜像(内置驱动)_第16张图片
有关这部分的配置我参考了一下这里,讲的听清楚的
我觉得可以再讲一遍
来到咱们的busybox1.33.1/examples/bootfloopy/etc目录
把里面所有东西复制到rootfs/etc里,编辑etc/inid.d/rcS
rcS这个文件是init之后调用的脚本,你也可以加点自己的东西进去
手把手教你傻瓜式编译linux5.13内核与启动镜像(内置驱动)_第17张图片
在后面加一句/init.2调用咱们之前复制过去的ubuntu初始化脚本

然后再编辑etc/inittab
懒得写了,引用一下
inittab原始内容

::sysinit:/etc/init.d/rcS
::respawn:-/bin/sh
tty2::askfirst:-/bin/sh
::ctrlaltdel:/bin/umount -a -r

简单说就是每一行表示一种执行策略,例如第一行表示在系统启动时执行RCS,第二行表示如果sh挂了会自动重启sh,第三行表示使用tty2启动的sh启动时会首先询问,第四行表示使用ctrl+alt+del快捷键时执行的程序。这里我们改下配置内容

修改后的

::sysinit:/etc/init.d/rcS
console::respawn:-/bin/sh

将sh启动的控制程序交给console,并且删除其他操作。

至此,initrd内容准备完毕

cd ..
find ./rootfs | cpio -H newc -o > initrd.cpio
#打包cpio
gzip initrd.cpio
#使用gzip压缩
mv initrd.cpio initrd.img

上机测试

做了这么多工作,现在终于可以开始测试了
你需要准备:
1.bzImage
2.initrd.img
3.Ubuntu安装盘
4.DiskGenius软件
手把手教你傻瓜式编译linux5.13内核与启动镜像(内置驱动)_第18张图片

用DiskGenius创建一个虚拟磁盘文件,包括一个EFI区和一个EXT4区,然后映射EFI到本地卷,注意要用读写模式

需要把grub从Ubuntu的安装盘里把/boot/EFI这俩目录复制出来

复制文件

把bzImage和initrd.img放到虚拟磁盘/boot目录里
修改/boot/grub/grub.cfg
手把手教你傻瓜式编译linux5.13内核与启动镜像(内置驱动)_第19张图片

创建虚拟机

我就不多说了,VMware基本操作
记得选择UEFI启动啊
我这里的运行非常成功,SATA驱动也都正常
手把手教你傻瓜式编译linux5.13内核与启动镜像(内置驱动)_第20张图片

手把手教你傻瓜式编译linux5.13内核与启动镜像(内置驱动)_第21张图片

手把手教你傻瓜式编译linux5.13内核与启动镜像(内置驱动)_第22张图片
内核信息正常
在这里插入图片描述
USB驱动正常
手把手教你傻瓜式编译linux5.13内核与启动镜像(内置驱动)_第23张图片

你可能感兴趣的:(我的经验,内核,linux,initrd,busybox)