【Linux内核】如何编译并运行一个Linux内核

1.下载Linux内核源码

首先需要下载Linux内核源码。

wget https://www.kernel.org/pub/linux/kernel/v4.x/linux-4.19.3.tar.gz

下载Busybox源码,BusyBox 是一个集成多种常用 Linux 工具的软件集合,它将许多标准的 Unix 工具(如 ls、cp、mv、sh 等)集成到一个小型的可执行文件中。通常用于嵌入式系统或需要轻量级环境的场景,例如在构建最小化的 Linux 根文件系统时。

在嵌入式设备或轻量级环境中,BusyBox 可以替代完整的 GNU 工具链,节省空间。

wget https://busybox.net/downloads/busybox-1.37.0.tar.bz2

2.编译内核

首先创建一个目录,用来放编译的相关文件。

mkdir kernel
cd kernel

然后进行解压。

tar -zxvf linux-4.19.3.tar.gz
cd linux-4.19.3.tar.gz

配置硬件架构

配置硬件架构,最终是使用QEMU来运行,因此直接将ARCH设置为x86,减少交叉编译所需要的时间。(如果目标架构与编译机器的架构相同(例如,都是 x86 或 x86_64),则不需要进行交叉编译。交叉编译是指在一个架构上编译出适用于另一个架构的代码,通常需要额外的工具链(如交叉编译器)。)

export ARCH=x86

配置config

配置board config,同样是配置为x86架构的。make x86_64_defconfig 是一个非常重要的命令,它的作用是为特定的硬件架构生成默认的内核配置文件(.config)

生成的 .config 文件是一个文本文件,包含了内核编译所需的配置选项。它定义了哪些内核功能、模块和驱动程序将被编译。例如:是否启用特定的文件系统支持(如 ext4、NTFS)、是否编译特定的硬件驱动程序(如网络驱动、GPU 驱动)

make  x86_64_defconfig

配置Linux内核

提供了一个基于文本菜单的交互式界面,允许用户自定义内核的编译选项。

make menuconfig 的核心作用是让用户能够自定义 Linux 内核的配置。它通过一个图形化的菜单界面(基于 ncurses 库),让用户可以轻松地启用、禁用或修改内核的功能、模块和驱动程序的编译选项。

make menuconfig

其中具体需要配置的选项如下所示。

支持ramdisk驱动,选中下面的配置,启用内核对初始 RAM 磁盘(Initial RAM Disk,简称 initrd 或 ramdisk)的支持。ramdisk 是一种基于内存的虚拟块设备,它将内存的一部分分配出来,模拟成一个磁盘设备,用于存储临时文件系统或其他数据。

ramdisk在系统启动时,ramdisk 可以被用作初始根文件系统initramfs)。它允许系统在启动过程中加载必要的驱动程序和工具,以便完成后续的启动过程。

这里有几个参数需要设置一下:
Kernel log buffer size:设置内核日志缓冲区的大小,影响内核可以存储的日志信息量。选项中的数字(16 => 64KB, 17 => 128KB)表示不同的日志缓冲区大小配置。

CPU kernel log buffer size contribution:为每个 CPU 设置内核日志缓冲区的贡献大小,影响每个 CPU 可以存储的日志信息量。

Temporary per-CPU NMI log buffer size:设置每个 CPU 的临时不可屏蔽中断(NMI)日志缓冲区大小。

Control Group support:启用控制组(cgroups)支持,允许对系统资源进行细粒度控制和管理。
Namespaces support:启用命名空间支持,提供进程隔离的机制,如 PID、网络、IPC 等命名空间。
Kernel->user space relay support (formerly relayfs):提供内核到用户空间的中继支持,允许用户空间程序与内核空间进行更高效的通信。

Initial RAM filesystem and RAM disk (initramfs/initrd) support:启用初始 RAM 文件系统和 RAM 磁盘(initramfs/initrd)的支持,允许系统在启动时从内存中的文件系统加载必要的驱动和工具。
在这里插入图片描述
配置设备驱动,特别是块设备(Block devices)的驱动。块设备通常指的是存储设备,如硬盘、固态硬盘、USB 存储设备等,它们能够以块为单位存储和检索数据。

在这里插入图片描述

开始编译内核

通过命令指定核心数,一般根据虚拟机的大小进行设置。N代表具体核心数。

make -j4

然后等待编译即可。

在这里插入图片描述
此时内核镜像的位置为:linux-4.9.299/arch/x86/boot/bzImage

3.编译busybox

cd kernel
tar -jxvf busybox-1.37.0.tar.bz2
cd busybox-1.37.0/

busybox比较简单,只用选一个,支持静态编译就行。BusyBox 可以编译为静态二进制文件,不依赖外部库,适合在没有动态库支持的环境中运行。

make menuconfig

在这里插入图片描述

make -j4
make install

编译并安装完成busybox后,会在busybox目录下多一个_install的目录,busybox就已经编译完成。

4.创建rootfs根文件系统

补充目录结构

接下来通过busybox启动一个Linux系统,也就是需要一个根文件系统,也就是我们需要对busybox生成的目录进行补充。

进入到busybox的目录

cd _install

mkdir -p etc/init.d mnt tmp sys dev proc 

这个命令使用 mkdir 创建一系列目录,-p 选项确保即使上级目录不存在时,命令也能正确执行,自动创建所有必要的上级目录。

etc/init.d:这个目录通常用于存放系统启动时需要执行的初始化脚本。
mnt:挂载点目录,用于挂载文件系统,如 USB 设备、网络文件系统等。
tmp:临时文件目录,用于存放系统运行过程中产生的临时文件。
sys:系统文件目录,用于存放与内核交互的文件,如设备文件、驱动信息等。
dev:设备文件目录,用于存放设备节点,如 /dev/ttyS0(串口设备)。
proc:进程文件系统目录,用于存放虚拟文件系统 proc 的挂载点,proc 文件系统提供了一种机制来获取内核和进程信息。

创建文件系统表fstab

/etc/fstab 文件是 Linux 系统中的一个配置文件,用于存储文件系统的静态信息,包括挂载点、文件系统类型、挂载选项等。

vim etc/fstab
proc	/proc	proc	defaults	0	0
tmpfs	/tmp	tmpfs	defaults	0	0
sysfs	/sys	sysfs	defaults	0	0

创建启动脚本rcS

vim etc/init.d/rcS

echo -e "Welcome to tinyLinux"
/bin/mount -a
mount  -o  remount,rw  /
mkdir -p /dev/pts
mount -t devpts devpts /dev/pts
echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s

/bin/mount -a 命令会挂载 /etc/fstab 文件中定义的所有文件系统,-a 选项表示挂载所有文件系统。

然后,脚本使用 mount -o remount,rw / 命令重新挂载根文件系统(/)为读写模式。这通常是在系统启动时将只读的根文件系统切换为读写模式,以便系统可以对文件系统进行修改。

mkdir -p /dev/pts 创建 /dev/pts 目录,该目录用于存放伪终端设备文件。

紧接着,脚本通过 mount -t devpts devpts /dev/pts 命令挂载 devpts 文件系统/dev/pts 目录。devpts 是一个特殊的文件系统,用于支持伪终端(pseudo-terminals),它允许用户通过终端模拟器与系统进行交互。

然后,echo /sbin/mdev > /proc/sys/kernel/hotplug 命令将 /sbin/mdev 写入 /proc/sys/kernel/hotplug 文件,这通常是用来指定 udev 或 mdev 这类设备管理器的启动脚本。

mdev -s 命令启动 mdev 设备管理器,它会扫描 /dev 目录并根据需要创建设备文件。mdev 是一个轻量级的设备管理器,常用于嵌入式系统或资源受限的环境。

通过这些步骤,rcS 脚本确保了系统启动时文件系统被正确挂载,设备节点被创建,并且设备管理器正常运行,从而为系统的后续操作提供了基础。

chmod 755 rcS 添加权限。

创建初始化程序配置文件inittab

该文件用于定义系统启动时的初始化进程和行为。inittab 文件是 System V init 系统的配置文件,用于告诉 init 进程(系统的第一个进程,PID 为 1)在系统启动、运行和关闭时应该执行哪些任务。

vim etc/inittab

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

::sysinit: 是一个运行级别(runlevel),sysinit 表示系统初始化阶段。/etc/init.d/rcS 是在系统初始化阶段需要执行的脚本文件。这个脚本就是上面那个,通常包含启动系统所需的各种服务和任务。

::respawn: 表示如果进程退出,init 将自动重启该进程。/bin/sh 是需要重启的 shell 进程。这确保了 shell 始终运行,即使它意外退出。

::askfirst: 表示在执行指定的命令前,init 会提示用户确认。/bin/sh 是需要用户确认的命令。这可以用于在执行某些关键操作前确保用户同意。

::ctrlaltdel: 表示当用户按下 Ctrl+Alt+Del 组合键时触发的动作。/bin/umount -a -r 是要执行的命令,用于卸载所有文件系统并重新启动系统。-a 选项表示卸载所有文件系统,-r 选项表示重新启动。

chmod 755 inittab

给文件添加可执行权限。

创建设备文件节点

tty 设备通常用于表示终端设备,tty1 表示第一个伪终端。
null 设备通常用于丢弃所有写入其中的数据,而从该设备读取则会返回 EOF(文件结束标志)。

在 dev 目录下创建了三个设备文件:console、null 和 tty1。这些设备文件分别用于访问系统控制台、提供一个数据黑洞以及访问第一个伪终端。这些设备文件是用户空间程序与系统内核交互的重要接口,使得用户可以通过这些文件与系统进行通信。

cd dev
mknod console c 5 1
mknod null c 1 3
mknod tty1 c 4 1

5.镜像制作

在kernel目录下执行操作:

# 先创建一个空的镜像并格式化为ext4
dd if=/dev/zero of=./rootfs.ext4 bs=1M count=32
mkfs.ext4 rootfs.ext4
# 创建一个空目录fs
mkdir fs
# 挂载到fs,并复制启动文件
mount -o loop rootfs.ext4 ./fs
cp -rf ./_install/* ./fs
#卸载镜像文件
umount ./fs
# 使用gzip压缩
gzip --best -c rootfs.ext4 > rootfs.img.gz
dd if=/dev/zero of=./rootfs.ext4 bs=1M count=32
mkfs.ext4 rootfs.ext4

dd if=/dev/zero of=./rootfs.ext4 bs=1M count=32:这个命令创建一个大小为 32MB 的空文件(镜像),名为 rootfs.ext4。dd 命令从 /dev/zero读取数据,以 1MB 的块大小写入 rootfs.ext4 文件,总共写入 32 次。

mkfs.ext4 rootfs.ext4:这个命令将 rootfs.ext4 文件格式化为 ext4 文件系统,使其可以被 Linux 系统识别和使用。

mkdir fs

创建一个名为 fs 的空目录,用于挂载镜像文件。

mount -o loop rootfs.ext4 ./fs:这个命令将 rootfs.ext4 镜像文件挂载到 fs 目录。

cp -rf ./_install/* ./fs:这个命令将 _install 目录下的所有文件递归地复制到挂载的 fs 目录中。这些文件通常包括 BusyBox 工具、系统启动脚本等。

umount ./fs

卸载 fs 目录,即从文件系统中卸载 rootfs.ext4 镜像文件。这是在对镜像文件进行修改后必须执行的步骤,以确保所有更改都已保存。

gzip --best -c rootfs.ext4 > rootfs.img.gz

使用 gziprootfs.ext4 镜像文件进行压缩,并将压缩后的数据输出到 rootfs.img.gz 文件中。–best 选项指定使用最高的压缩级别,-c 选项指定输出到标准输出,然后通过重定向 > 将其写入文件。

这里我们来说明一下挂载和镜像文件的关系。

挂载的定义:挂载是一种将存储设备(包括镜像文件)连接到正在运行的操作系统的方法,使其可以像本地存储设备一样被访问和使用。挂载过程涉及将文件系统的根目录指定为系统中的一个目录(称为挂载点),这样文件系统中的文件和目录就可以通过这个挂载点访问了。

挂载的过程可以这样理解:
创建挂载点:首先,在操作系统中创建一个空目录,这个目录将作为文件系统的访问入口。
执行挂载命令:使用挂载命令(如 mount)将镜像文件或存储设备挂载到创建的挂载点上。
访问文件系统:一旦挂载成功,就可以通过挂载点访问文件系统中的文件和目录,就像访问本地文件系统一样。

镜像文件包含了一个文件系统,当镜像文件被挂载时,它所包含的文件系统就变得可访问。挂载过程使得镜像文件中的数据可以被操作系统读取和写入,就像它是一个本地存储设备一样。

可以这么理解在卸载之后,您不再能通过该挂载点访问镜像文件中的文件系统,但镜像文件本身仍然存在,并且包含了您在挂载期间所做的所有更改。

6.利用qemu运行内核和文件系统

在kernel目录下创建一个目录,然后拷贝bzImage。

mkdir -p img/4.9
cp linux-4.9.299/arch/x86/boot/bzImage img/4.9/

运行命令就可以开始运行内核了。

qemu-system-x86_64 -kernel img/4.9/bzImage -initrd rootfs.img.gz -append "root=/dev/ram init=/linuxrc" -serial file:output.txt
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值