本教程是我四天来总结的经验,期间编译了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了
写的很清楚,空格键换模式,上下键换目标,左右键换功能,回车确认,M是编译成模块(本教程不讨论),留空是不要,*是打进内核
然后我们进去General setup
右下角有v(+)说明可以向下翻页,有—>说明回车里面有子菜单
第一项留空,第二项我给他起名叫-all-in-one也就是(驱动)全都打包 进内核, init位置是/sbin/init (busybox init的位置),设备名随便起一个,你也给他叫gensoukyo都没事 这个菜单配置完了,选Exit退出
好的,我们现在在主菜单选Firmware Drivers 再进入有EFI关键字的那个选项(如果你需要UEFI启动内核的话请务必,使用传统bios可忽略)
把EFI开头的都选上*(即打进内核)才能支持UEFI启动
现在退到主菜单 进入Device Drivers 这一部分操作就多了,准备好把空格键按烂吧,我们要把大量常用驱动打进去 进入Block devices 把除了IDE那个部分的以外的全打上* 带debug的不用打,不能的留M,下同
然后往下找到Default ramdisk size 默认应该是65536KB(64MB),我们给他改成131072KB(128M)大一点还是好的,毕竟现在机子都不缺那点内存 好的,我们现在返回Device drivers 进NVME support,能*全就全打上
返回 进Misc devices(杂项设备),可以把带card reader的全打上,不打也没事,只是为了兼容读卡器启动,貌似没啥用(?)
返回 进ATA/啥啥啥的 那个,能*就全打上
返回 进SCSI/啥啥啥的 那个,能*就全打上
返回 进Serial ATA /啥啥啥的那个(即SATA和PATA驱动),能*就全打上
返回 进Network/那个 配置网络驱动,能*全打上
返回 进OpenChannelSSD那个 ,能*全打上
返回 往下翻,找到USB Support 能*全打上
返回 进MMC/SD什么什么那个 ,打闪存(貌似是)驱动,能打*就全打上
返回 翻到最下面MOST support 这里面貌似是预制好的选项,把前两个打* 至此,驱动打完了
让我们返回到主菜单 进File System(文件系统选项) Ext2,Ext3,Ext4全部选上,把你不认识的都留空或者默认不管他 下翻,找FAT文件系统 里面有FAT和NTFS的选项,选上 返回,找到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[线程数]
处理报错的预案
注意!如果编译过程中不久就出现了以下报错,赶紧Ctrl C暂停 编辑你的.config文件,查找 删掉这一整行 再次编译会让你确认,回车就行,不需要输入y/n
给大家提个醒,你现在直接编译还是会在最后时刻前功尽弃,我编译快可以再来一遍,你们可别踩坑了
查了一下解决方案,还是编辑.config文件
再次编译,又有让你确认的,你就一路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
相比之下,busybox就简陋多了 打开settings 找到 也就是让他静态编译,老规矩,打*
busybox配置就结束了,剩下的咱不用管了,退出,记得保存你的配置
开始编译
make install -j14
编译结束,生成了一个_install 目录,我们把东西cp过去
mkdir ./../rootfs
cp _install/* ./../rootfs
cd ./../rootfs
ls
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 ..
目录结构咱已经搞出来了,实际上现在打包就能开机了,只不过是瘸子腿儿走路,啥也干不了,因为初始化没有彻底完成
我们要偷懒用一下Ubuntu的初始化脚本 请把Ubuntu系统的/boot/initrd.img-x.x.x-xx-generic 这个initrd文件给他拉过来
cp /boot/initrd.img-5.8.0-55-generic .
ls
这时候你可以用归档管理器打开,会发现,哎,跟咱们做到initrd结构完全不一样啊? 这就对咯!这个文件其实是个缝合怪,好几个部分拼在一起了 让我康康!
apt install binwalk
binwalk initrd.img-5.8.0-55-generic
奥,原来是这样,它前边是cpio,后面才是打包的initrd 找到输出的第一个正经压缩格式的位置 看来用得是lz4压缩的initrd 记下来位置
dd if=initrd.img-5.8.0-55-generic bs=4641792 skip=1>>out.lz4
mkdir ubuntu_initrd
lz4 -d out.lz4
mv out ubuntu_initrd
cd ubuntu_initrd
cpio -idmv<out
rm -f out
ls
我们呢,只需要用到一个文件init 和一组文件夹scripts 编辑init可以发现是一个sh文件,里面大概是写的怎么挂载/proc之类的,反正是完成初始化,调用scripts 里的sh函数
现在把init和scripts复制过去,剩下的就没用了
cp init ./../rootfs/init.2
cp -r scripts ./../rootfs
cd ./../rootfs
ls
然后我们要准备etc目录下的东西,也就是初始化的配置 这些是必要的 有关这部分的配置我参考了一下这里,讲的听清楚的 我觉得可以再讲一遍 来到咱们的busybox1.33.1/examples/bootfloopy/etc 目录 把里面所有东西复制到rootfs/etc 里,编辑etc/inid.d/rcS rcS这个文件是init之后调用的脚本,你也可以加点自己的东西进去 在后面加一句/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
gzip initrd.cpio
mv initrd.cpio initrd.img
上机测试
做了这么多工作,现在终于可以开始测试了 你需要准备: 1.bzImage 2.initrd.img 3.Ubuntu安装盘 4.DiskGenius软件
用DiskGenius创建一个虚拟磁盘文件,包括一个EFI区和一个EXT4区,然后映射EFI到本地卷,注意要用读写模式
需要把grub从Ubuntu的安装盘里把/boot 和/EFI 这俩目录复制出来
复制文件
把bzImage和initrd.img放到虚拟磁盘/boot 目录里 修改/boot/grub/grub.cfg
创建虚拟机
我就不多说了,VMware基本操作 记得选择UEFI启动啊 我这里的运行非常成功,SATA驱动也都正常
内核信息正常 USB驱动正常 还没有测试NVME,请大家自己测试吧!
码字不容易,文章写了四个小时,期间调试也很费劲,觉得有用就点个赞吧! 咱是一个15岁的学生,第一次写长文章能写成这样我觉着很不错了x
|