QEMU学习之路(5)— 从0到1构建Linux系统镜像
一、前言
二、linux源码获取
安装编译依赖
sudo apt install -y build-essential libncurses-dev flex bison libssl-dev libelf-dev
1、从Linux官网下载源码
wget https://www.kernel.org/pub/linux/kernel/v6.x/linux-6.14.tar.xz
下好后使用命令解压
tar xvf linux-6.14.tar.xz
2、使用git拉取
git clone --depth 1 https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git -b v6.14 linux-6.14
3、国内镜像源获取
从国外的网站下载内核可能很慢,可以尝试使用国内的镜像源,例如清华大学的开源镜像站
git clone --depth 1 https://mirrors.tuna.tsinghua.edu.cn/git/linux.git -b v6.14 linux-6.14
三、内核构建
源码获取好后可以使用如下命令生成默认配置
make defconfig
然后编译内核
make -j$(nproc)
编译后得到内核镜像文件:arch/x86_64/boot/bzImage
四、构建initramfs
initramfs(Initial RAM File System)是 Linux 系统启动过程中使用的 临时根文件系统,它存储在内存中,用于在内核加载后、挂载真实根文件系统前完成关键初始化任务。
使用如下命令构造目录结构与设备节点
mkdir -p initramfs/{bin,dev,proc,sys}
cd initramfs
sudo mknod dev/console c 5 1
sudo mknod dev/null c 1 3
sudo chown root:root dev/{console,null}
BusyBox 是一个高度优化的 多合一 Unix 工具集,它将数百个常用 Unix 工具(如 ls、cat、grep、mount、ifconfig 等)集成到一个精简的二进制文件中。
下载BusyBox 源码:
wget https://busybox.net/downloads/busybox-1.36.1.tar.bz2
解压
tar -xf busybox-1.36.1.tar.bz2
进入源码目录进行配置
cd busybox-1.36.1
make menuconfig
进入配置界面后,启用以下选项吗,选择静态方式编译busybox,目的是将程序的所有依赖库直接打包进二进制文件,避免了Linux系统运行时依赖动态库。
Settings --->
[*] Build static binary (no shared libs)
编译busybox
make -j$(nproc)
然后部署到initramfs
make install CONFIG_PREFIX=../work/initramfs
在initramfs目录新建init文件,它作为Linux 启动镜像(initramfs)中的 首个用户态进程(PID 1),由内核直接启动,承担着从内核过渡到用户空间的关键桥梁作用,主要任务是为后续系统启动准备必要的运行环境。输入内容如下:
#!/bin/sh
/bin/echo "Hello Linux"
mount -t proc proc /proc
mount -t sysfs sysfs /sys
mount -t devtmpfs devtmpfs /dev
exec /bin/sh
使用chmod +x init
命令添加可执行权限
然后将其打包到initramfs.img镜像文件中。
find . | cpio -H newc -o | gzip > ../initramfs.img
使用如下命令检查打包结果
file ../initramfs.img
五、启动测试
将bzImage拷贝到当前目录
使用如下命令测试启动
qemu-system-x86_64 -kernel bzImage -initrd initramfs.img
启动后显示界面如下:
也可使用如下命令不带图形界面启动
qemu-system-x86_64 -kernel bzImage -initrd initramfs.img -m 1G -nographic -append "earlyprintk=serial,ttyS0 console=ttyS0"
六、制作ISO镜像
ISO文件是一种标准的光盘镜像格式(遵循ISO 9660文件系统规范),通常用于封装完整的可启动操作系统或软件集合。在Linux系统构建中,ISO文件的核心作用是将内核(vmlinuz)、初始内存盘(initramfs.img)和引导程序(如GRUB)等关键组件打包成一个可物理刻录(光盘/USB)或虚拟机加载的独立镜像。
构建boot目录
mkdir -p iso/boot/grub
将前面编译或者构建好的内核镜像文件(bzImage或者Image.gz)、根文件系统镜像文件(initramfs.img)添加到boot目录中
cp ../linux-6.14/arch/x86_64/boot/bzImage iso/boot/vmlinuz
cp ./initramfs.img iso/boot/initramfs.img
新建GRUB配置文件
touch iso/boot/grub/grub.cfg
输入内容如下
menuentry "Custom Linux" {
linux /boot/vmlinuz root=/dev/ram0 rw
initrd iso/boot/initramfs.img
}
安装工具依赖包
sudo apt install mtools xorriso
生成ISO
grub-mkrescue -o custom-linux.iso iso/
验证ISO结构
xorriso -indev custom-linux.iso -ls
使用如下命令启动:
qemu-system-x86_64 -cdrom custom-linux.iso
七、开发驱动
创建hello.c文件,内容如下所示:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("william");
MODULE_DESCRIPTION("Hello module");
MODULE_VERSION("0.1");
static int __init hello_init(void)
{
printk(KERN_INFO "Loading hello module\n");
printk(KERN_INFO "hello world\n");
return 0;
}
static void __exit hello_exit(void)
{
printk(KERN_INFO "exit module\n");
}
module_init(hello_init);
module_exit(hello_exit);
编写Makefile如下所示:
KERNELDIR=/home/william/project/linux/linux-6.14
obj-m := hello.o
all:
make -C ${KERNELDIR} M=${PWD} modules
clean:
make -C ${KERNELDIR} M=${PWD} clean
.PHONY: all clean
编译后将hello.ko
拷贝到initramfs/usr/
文件夹下,重新生成initramfs.img
后启动系统
进入/usr
目录后加载驱动,卸载驱动,可看到如下打印