手搓一个linux发行版(娱乐向)
手搓Linux发行版
该文章主要引用自于小乐大佬的B站视频
自己跟着视频手搓了一遍并把视频教程做成博客,同时记录一些自己出现的问题
编译内核
第一步就是从网上找到现成的linux内核并下载下来,Linux Kernel Archives
我下载的时候,与视频中的版本不相同,这也导致我后面出现了一些无法解决的问题。在视频中的稳定内核版本为6.13.2,而我的版本为6.17.3。我出现的问题是我无法打开FB_EFI。(这在第二弹视频中有提到过)。启动系统后只有一个光标,但是一直无法显示后续内容的黑屏。在下面我给出GPT的相关回答。
这是我问GPT给出的相关答案
在 Linux 内核 6.17.3 这一版本中,如果你在make menuconfig
或make xconfig
里 看不到 “EFI-based Framebuffer Support” 选项(CONFIG_FB_EFI),这是正常的现象 —— 从 内核6.x
开始,Framebuffer
与EFI
的支持方式发生了较大变化。
- 内核逐步弃用老旧的 fbdev 驱动(如 efifb、uvesafb)。
- DRM(Direct Rendering Manager) 体系成为主流。
- EFI framebuffer 功能被整合进 simpledrm 驱动 中,而不再独立显示 CONFIG_FB_EFI。
最终我的解决方案是手动修改.config
文件,设置了下面这些参数
1 | CONFIG_FB=y |
下面给一串代码,包括下载,解压和编译的过程
注意下面跑代码的时候可能会出现很多缺包,版本不匹配的问题。你直接将代码复制粘贴给GPT就可以解决。这不是问题的重点,所以自行ask gpt就成
1 | 下载 |
自制shell,模拟一次运行过程
编写一个shell.c
文件,这个代码会作为一个启动程序,当我们启动linux会直接启动这个shell脚本。
1 |
|
将c文件编译成一个可执行文件,同时将其设置为static,取消动态链接。
1 | 先直接编译 |
解释为什么要用cpio打包
在 Linux 启动过程中,内核会加载一个临时根文件系统(initramfs 或 initrd),它通常是一个 cpio 打包的归档文件。
cpio 是一种打包工具,常用于制作 Linux 的 initramfs 等文件系统镜像,因为内核能直接识别并解压它。
1
2
3
4 cpio -H newc -o
-o:表示 “copy out”,即创建打包文件;
-H newc:指定输出格式为 newc(一种常用于 initramfs 的新 ASCII 格式,支持大文件与设备号);
cpio 会根据输入的文件名列表(这里是 "init")把对应文件打包输出到标准输出。
构建一个完整的linux发行版
首先,一个完整的linux需要一个内核,一个shell,一个bootloader,一个根文件系统。
busybox
BusyBox 是一个把众多常用 Linux 命令集成到单一可执行文件中的轻量级工具集合,被称为 “嵌入式 Linux 的瑞士军刀”。
从网站中下载出busybox然后解压,执行一些编译操作。具体内容请直接看视频。这里只说几个具体的指令make menuconfig
打开配置菜单并关闭tc
选项
然后就将解压后的内容安装到一个文件夹下备用。make install CONFIG_PREFIX=you_dir
构建一个根文件系统
1 | sudo dd if=/dev/zero of=/linux.img bs=1M count=512 #构建一个文件,内容全为0,共有512MB |
要对这个两个分区进行格式化,首先先使用losetup
把他们模拟成磁盘
losetup 是用于管理环回设备(loop device)的命令。
环回设备允许你把一个普通文件(例如镜像文件 linux.img)当作一个块设备使用,就像一块真正的磁盘一样,这样你就可以对它进行挂载、分区操作等losetup -f -P linux.img
-f表示自动查找空闲的 loop 设备
-P会告诉 losetup 在建立环回设备时自动扫描镜像中的分区表,并为每个分区创建对应的设备节点。
执行后,会生成一个loop设备。
1 | 查看设备 |
使用grub-install配置引导分区
执行下面的命令把grub安装到EFI分区中。
1 | grub-install --target=x86_64-efi --efi-directory=$(realpath mnt) --bootloader-id=GRUB --removable --recheck |
配置grub.cfg
修改grub.cfg并复制一份到boot/grub下,避免因不同硬件的原因导致的引导失败。
1 | 修改grub.cfg |
然后配置数据分区
主要是这几个内容。
- 将busybox移动进去
- 把bzImage移动进去
- 设置对应的grub.cfg(与引导分区的grub不一样)
- 添加对应的init文件
前两个步骤无需多言,稍微注意一点,在mnt
中新建一个boot
文件夹,然后将bzImage移动到这个boot文件夹下,busybox直接放在mnt目录下即可。
然后在boot中新建一个grub目录,然后创建grub.cfg
文件
1 | menuentry "xiaohe_linux" { |
uuid和part_uuid都是通过blkid
来获取的,可以很直观的看到。
接着在boot目录下创建一个init文件,内容如下
1 | !/bin/sh |
事后别忘了给init添加执行权限,即
chmod +x init
然后在mnt
目录下创建出sys,proc,dev目录,用来再后面启动时进行装载。
以上,完成这些步骤后,基本就算构建好了一个可运行的最小linux开发版本。
启动一次
退出mnt目录,然后将这个磁盘卸载并脱机
1 | cd ../ # 回到原本的目录 |
接着应该就可以看到正常的界面展示了
将虚拟磁盘装载到U盘上
1 | 这里你需要判断一下你插入的U盘是什么名字,因为dd指令会把u盘格式化,别格式化错了文件 |
然后就可以直接插在电脑上当作正常启动盘来使用了。
我在这里还遇到了一个问题
目前还没能解决,因为我也才刚刚实现。