macos qemu


原文链接: macos qemu

brew install qemu

安装编译工具macOS Mojave(10.14.3)

$ brew install arm-linux-gnueabihf-binutils

bison on macOS is too old

$ brew install bison
$ export PATH="/usr/local/opt/bison/bin:$PATH"

安装 crosstool-ng 构建GCC编译环境

$ brew install crosstool-ng

$ export CT_NG_VER=$(brew list --versions crosstool-ng | tr ' ' '\n' | tail -1)

$ export CT_NG_VER_SHORT=${CT_NGVER%*}

安装的 crosstool-ng 的脚本文件缺少执行权限,导致无法执行,我们需要手工增加执行权限

$ chmod +x "$(brew --cellar crosstool-ng)/${CT_NG_VER}/lib/crosstool-ng-${CT_NG_VER_SHORT}/scripts/crosstool-NG.sh"

默认情况下,macOS的文件系统不区分大小写,我们需要手工创建一个区分大小写的分区

$ hdiutil create -volname "ClockworkOS" -type SPARSE -fs 'Case-sensitive Journaled HFS+' -size 30g ClockworkOS.dmg

$ hdiutil attach ClockworkOS.dmg.sparseimage -mountpoint /Volumes/ClockworkOS

$ cd /Volumes/ClockworkOS

$ mkdir arm-cortexa9_neon-linux

$ cd arm-cortexa9_neon-linux

$ ct-ng list-samples

变更x-tools存储目录

$ export HOME=/Volumes/ClockworkOS

$ ct-ng arm-cortexa9_neon-linux-gnueabihf

修复BUG Build failed in step 'Installing m4 for build'

$ brew uninstall --ignore-dependencies binutils
$ brew install binutils

安装依赖工具

$ brew install automake

$ brew uninstall --ignore-dependencies gawk
$ brew install gawk

目前编译gettext-0.19.8.1的时候写死依赖automake-1.15,但是最新的已经是automake-1.16,我们通过手工编译安装automake-1.15规避这个问题

$ wget http://ftp.gnu.org/gnu/automake/automake-1.15.tar.gz

也可从本站下载 wget https://www.mobibrw.com/wp-content/uploads/2019/03/automake-1.15.tar.gz

$ tar xvf automake-1.15.tar.gz

$ cd automake-1.15

$ bash configure

$ make && make install

$ cd ..

修改文件打开数量限制,修正错误 “extra-module.mk:11: *** Too many open files.”

$ ulimit -n 2048

'scm_new_port_table_entry' was not declared in this scope

$ sed -i "" "s/CT_GDB_CROSS_EXTRA_CONFIG_ARRAY=.*/CT_GDB_CROSS_EXTRA_CONFIG_ARRAY=\"--with-guile=no\"/g" .config

$ export PATH="/usr/local/bin:$PATH"

$ ct-ng build -j8

编译 u-boot
$ cd /Volumes/ClockworkOS

下载u-boot代码

$ git clone https://github.com/qemu/u-boot.git

$ cd u-boot

$ git checkout v2019.01 -b v2019.01

$ export PATH="/Volumes/ClockworkOS/x-tools/arm-cortexa9_neon-linux-gnueabihf/bin:$PATH"

$ export CROSS_COMPILE=arm-cortexa9_neon-linux-gnueabihf-

$ make clean

R16又名A33 ,R16-J 代表包含Jazelle DBX

$ make vexpress_ca9x4_defconfig

fix Undefined symbols for architecture x86_64: "_PyArg_ParseTuple"

$ export HOSTLDFLAGS="-lpython -dynamclib"

$ brew install gnu-sed

fix ./tools/../lib/bch.c:66:10: fatal error: 'endian.h' file not found

$ gsed -i "s/#include /#include \n#elif defined(APPLE)\n#include \n#include /g" lib/bch.c

$ gsed -i "s/#define cpu_to_be32 htobe32/#if defined(APPLE)\n#define cpu_to_be32 OSSwapHostToBigInt32\n#else\n#define cpu_to_be32 htobe32\n#endif/g" lib/bch.c

$ gsed -i "s/#if !defined(DragonFly) && !defined(FreeBSD)/#if !defined(DragonFly) && !defined(FreeBSD) && !defined(APPLE)/g" lib/bch.c

无视最后的失败提示,只要u-boot这个文件生成即可

$ make ARCH=arm -j8

$ cd /Volumes/ClockworkOS

下载u-boot代码

$ git clone https://github.com/qemu/u-boot.git

$ cd u-boot

$ git checkout v2019.01 -b v2019.01

$ export PATH="/Volumes/ClockworkOS/x-tools/arm-cortexa9_neon-linux-gnueabihf/bin:$PATH"

$ export CROSS_COMPILE=arm-cortexa9_neon-linux-gnueabihf-

$ make clean

R16又名A33 ,R16-J 代表包含Jazelle DBX

$ make vexpress_ca9x4_defconfig

fix Undefined symbols for architecture x86_64: "_PyArg_ParseTuple"

$ export HOSTLDFLAGS="-lpython -dynamclib"

$ brew install gnu-sed

fix ./tools/../lib/bch.c:66:10: fatal error: 'endian.h' file not found

$ gsed -i "s/#include /#include \n#elif defined(APPLE)\n#include \n#include /g" lib/bch.c

$ gsed -i "s/#define cpu_to_be32 htobe32/#if defined(APPLE)\n#define cpu_to_be32 OSSwapHostToBigInt32\n#else\n#define cpu_to_be32 htobe32\n#endif/g" lib/bch.c

$ gsed -i "s/#if !defined(DragonFly) && !defined(FreeBSD)/#if !defined(DragonFly) && !defined(FreeBSD) && !defined(APPLE)/g" lib/bch.c

无视最后的失败提示,只要u-boot这个文件生成即可

$ make ARCH=arm -j8

编译 Linux 内核
$ cd /Volumes/ClockworkOS

$ brew install aria2

$ aria2c -c https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.14.2.tar.xz

也可本站下载 wget https://www.mobibrw.com/wp-content/uploads/2019/03/linux-4.14.2.tar.xz

$ tar xvf linux-4.14.2.tar.xz

$ cd linux-4.14.2

$ export PATH="/Volumes/ClockworkOS/x-tools/arm-cortexa9_neon-linux-gnueabihf/bin:$PATH"

for mkimage

$ export PATH="/Volumes/ClockworkOS/u-boot/tools:$PATH"

或者 brew install u-boot-tools

elf.h

$ brew install libelf

$ echo "
#include
#define R_386_NONE 0
#define R_386_32 1
#define R_386_PC32 2
#define R_ARM_NONE 0
#define R_ARM_PC24 1
#define R_ARM_ABS32 2
#define R_MIPS_NONE 0
#define R_MIPS_16 1
#define R_MIPS_32 2
#define R_MIPS_REL32 3
#define R_MIPS_26 4
#define R_MIPS_HI16 5
#define R_MIPS_LO16 6
#define EF_ARM_EABIMASK 0xFF000000
#define EF_ARM_EABI_VERSION(flags) ((flags) & EF_ARM_EABIMASK)" > /usr/local/include/elf.h

xargs: illegal option -- r

$ brew install findutils

$ export PATH="/usr/local/opt/findutils/libexec/gnubin:$PATH"

stat: illegal option -- c

$ ln -s /usr/local/bin/gstat /usr/local/bin/stat

$ export PATH="/usr/local/bin:$PATH"

$ export CROSS_COMPILE=arm-cortexa9_neon-linux-gnueabihf-

$ export ARCH=arm

$ make vexpress_defconfig

$ make -j8

$ mkimage -A arm -O linux -T kernel -C none -a 0x40008000 -e 0x40008000 -n "Linux kernel" -d arch/arm/boot/zImage uImage

$ cd /Volumes/ClockworkOS

$ brew install aria2

$ aria2c -c https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.14.2.tar.xz

也可本站下载 wget https://www.mobibrw.com/wp-content/uploads/2019/03/linux-4.14.2.tar.xz

$ tar xvf linux-4.14.2.tar.xz

$ cd linux-4.14.2

$ export PATH="/Volumes/ClockworkOS/x-tools/arm-cortexa9_neon-linux-gnueabihf/bin:$PATH"

for mkimage

$ export PATH="/Volumes/ClockworkOS/u-boot/tools:$PATH"

或者 brew install u-boot-tools

elf.h

$ brew install libelf

$ echo "
#include
#define R_386_NONE 0
#define R_386_32 1
#define R_386_PC32 2
#define R_ARM_NONE 0
#define R_ARM_PC24 1
#define R_ARM_ABS32 2
#define R_MIPS_NONE 0
#define R_MIPS_16 1
#define R_MIPS_32 2
#define R_MIPS_REL32 3
#define R_MIPS_26 4
#define R_MIPS_HI16 5
#define R_MIPS_LO16 6
#define EF_ARM_EABIMASK 0xFF000000
#define EF_ARM_EABI_VERSION(flags) ((flags) & EF_ARM_EABIMASK)" > /usr/local/include/elf.h

xargs: illegal option -- r

$ brew install findutils

$ export PATH="/usr/local/opt/findutils/libexec/gnubin:$PATH"

stat: illegal option -- c

$ ln -s /usr/local/bin/gstat /usr/local/bin/stat

$ export PATH="/usr/local/bin:$PATH"

$ export CROSS_COMPILE=arm-cortexa9_neon-linux-gnueabihf-

$ export ARCH=arm

$ make vexpress_defconfig

$ make -j8

$ mkimage -A arm -O linux -T kernel -C none -a 0x40008000 -e 0x40008000 -n "Linux kernel" -d arch/arm/boot/zImage uImage

$ cd /Volumes/ClockworkOS

$ brew install aria2

官方给出的这个地址下不到,只能用镜像地址 http://106.185.33.196/clockworkos_v0.3.img.bz2

$ aria2c -c http://clockworkpi.k15.net/clockworkos_v0.3.img.bz2

$ rm -rf clockworkos_v0.3.img

$ bzip2 -d -k -vvvv clockworkos_v0.3.img.bz2

替换镜像中的内核文件

$ hdiutil attach clockworkos_v0.3.img -mountpoint /Volumes/clockworkos_v0.3

$ echo y | cp -i /Volumes/ClockworkOS/linux-4.14.2/uImage /Volumes/clockworkos_v0.3/uImage

$ hdiutil detach /Volumes/clockworkos_v0.3

$ brew install qemu

$ qemu-img convert -f raw -O qcow2 clockworkos_v0.3.img clockworkos_v0.3.qcow2

$ cd /Volumes/ClockworkOS

$ brew install aria2

官方给出的这个地址下不到,只能用镜像地址 http://106.185.33.196/clockworkos_v0.3.img.bz2

$ aria2c -c http://clockworkpi.k15.net/clockworkos_v0.3.img.bz2

$ rm -rf clockworkos_v0.3.img

$ bzip2 -d -k -vvvv clockworkos_v0.3.img.bz2

替换镜像中的内核文件

$ hdiutil attach clockworkos_v0.3.img -mountpoint /Volumes/clockworkos_v0.3

$ echo y | cp -i /Volumes/ClockworkOS/linux-4.14.2/uImage /Volumes/clockworkos_v0.3/uImage

$ hdiutil detach /Volumes/clockworkos_v0.3

$ brew install qemu

$ qemu-img convert -f raw -O qcow2 clockworkos_v0.3.img clockworkos_v0.3.qcow2

手工编译 qemu
$ cd /Volumes/ClockworkOS

$ git clone https://github.com/qemu/qemu.git

$ cd qemu

从 qemu v2.1.0-rc1 开始,内存需要被映射到0x60000000开始的地址,更低的地址被映射为只读闪存,我们需要取消这种映射行为,否则执行的时候会报告错误

$ sed -i "" "s/[VE_NORFLASHALIAS] = 0/[VE_NORFLASHALIAS] = -1/g" hw/arm/vexpress.c

$ bash configure

$ make -j8

$ cd ..

list supported machine qemu-system-arm -machine help

$ /Volumes/ClockworkOS/qemu/arm-softmmu/qemu-system-arm -M vexpress-a9 -m 1024M -kernel /Volumes/ClockworkOS/u-boot/u-boot -serial mon:stdio -nographic -sd clockworkos_v0.3.qcow2 -net nic,model=lan9118 -net user

$ cd /Volumes/ClockworkOS

$ git clone https://github.com/qemu/qemu.git

$ cd qemu

从 qemu v2.1.0-rc1 开始,内存需要被映射到0x60000000开始的地址,更低的地址被映射为只读闪存,我们需要取消这种映射行为,否则执行的时候会报告错误

$ sed -i "" "s/[VE_NORFLASHALIAS] = 0/[VE_NORFLASHALIAS] = -1/g" hw/arm/vexpress.c

$ bash configure

$ make -j8

$ cd ..

list supported machine qemu-system-arm -machine help

$ /Volumes/ClockworkOS/qemu/arm-softmmu/qemu-system-arm -M vexpress-a9 -m 1024M -kernel /Volumes/ClockworkOS/u-boot/u-boot -serial mon:stdio -nographic -sd clockworkos_v0.3.qcow2 -net nic,model=lan9118 -net user

可惜到这一步了,还是没办法成功运行系统。
可惜到这一步了,还是没办法成功运行系统。

参考链接


本文主要介绍在 MacOS 上使用 qemu 搭建 Linux Kernel 的开发环境。(在开始之前需要注意的是,本文中的 Linux 开发环境是一个远程服务器,而 qemu 被安装在本地的 MacOS 上。通常并不需要这样折腾,直接将 qemu 安装在 Linux 中更加方便,而且 qemu 是可以
-nographic 无图形界面运行的。)

1. 为什么需要 qemu?

qemu 是一个硬件虚拟化程序( hypervisor that performs hardware virtualization),与传统的 VMware / VirtualBox 之类的虚拟机不同,它可以通过 binary translation 模拟各种硬件平台(比如在 x86 机器上模拟 ARM 处理器)。而 VirtualBox 等更多是通过虚拟化来进行资源隔离,以便在其上运行多个 guest os。

基于 qemu 的硬件模拟能力,我们可以轻松搭建指定硬件平台的运行实验环境。

qemu 与 VirtualBox 另一个不同点在于,在 VirtualBox 上必须安装一个完整的操作系统套件,而通过 qemu 我们可以通过参数直接启动到一个裸的 Linux Kernel,连 bootloader 都不需要关心。在此之外,按需配置相关工具套件与启动好的 Kernel 一起工作即可。

qemu 提供的这种高度可定制化的『白盒』能力,使得我们可以按需构建快速、轻量级的开发环境,提供流畅的开发体验。

2. 环境准备

首先,为了进行内核开发,需要一个现成的 Linux 操作系统环境。可以是一个通过 ssh 工作的远程 Linux Server,或者也可以在 MacOS 上通过 VirtualBox (或者使用 qemu 也可以)安装一个虚拟机用于开发。VirtualBox 的安装和 Linux Guest OS 的安装配置此处略过不提。

接下来,安装 qemu。在 MacOS 上可以使用 Homebrew 包管理工具进行安装(本文使用的 qemu 版本为 2.9.0_2):

brew install qemu

安装完成后,可以看到系统中有很多个 qemu-system- 开头的命令,用于模拟各种硬件平台,比如 qemu-system-x86_64 。运行其中一个命令来验证安装是否成功:

qemu-system-x86_64

上述命令会启动一个类似 VirtualBox 虚拟机启动时的窗口。当然,由于我们没有指定任何设备,最终会提示找不到可启动设备。

3. 编译内核

按需编译内核,此处只进行简单说明(基于内核 v4.13)。

3.1 内核编译配置

可以先执行 make help 可以查看 make 支持哪些 target。

通常先进行内核编译配置:

make menuconfig

会启动一个基于文本的配置界面进行各种选项、模块、驱动等配置。或者也可以直接使用目标平台默认的配置,如针对 x86_64 平台(后续平台相关的地方均以 x86_64 为例进行说明)可以使用:

make x86_64_defconfig

配置完成后相应的配置项会保存在 .config 文件中。下一次执行 make menuconfig 时可以 load 这份配置文件,在此基础上进行修改。

3.2 编译内核和模块

我们构建一个压缩过的内核镜像:

make bzImage

编译成功后,bzImage 文件将出现在 arch/x86_64/boot/bzImage。记住文件路径或者拷贝到一个方便的路径,便于后续启动时使用。
接下来,编译在配置阶段选择的内核模块:

make modules

编译好的内核模块 *.ko 文件存在于模块对应的源码目录中。

4. 启动内核

编译好内核以后,我们就可以使用 qemu 启动内核了。只需要使用 -kernel 参数告诉 qemu 内核文件的位置即可:

qemu-system-x86_64 \    -m 512M \  # 指定内存大小    -smp 4\  # 指定虚拟的 CPU 数量    -kernel ./bzImage  # 指定内核文件路径

上述命令假设编译好的 bzImage 内核文件就存放在当前目录下。因为之前编译好的内核文件是在 VirtualBox 的虚拟机中(或者在远程服务器上),而 qemu 在本地 MacOS 上,可以通过 VirtualBox 的 share folder 来共享目录,或者使用 NFS 共享,甚至简单使用 rsync 来在两者之间同步文件。后续关于文件同步与共享不再赘述。

不出意外的话,就可以在启动窗口中看到内核的启动日志了。在内核启动的最后,会出现一条 panic 日志:

Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0, 0)

从日志内容可以看出,内核启动到一定阶段后尝试加载根文件系统,但我们没有指定任何磁盘设备,所以无法挂载根文件系统。而且上一节中编译出来的内核模块现在也没有用上,内核模块也需要存放到文件系统中供内核需要的时候进行加载。

所以,接下来需要制作一个磁盘镜像文件供内核作为根文件系统加载。

5. 制作磁盘镜像

如上一节所述,需要制作一个磁盘镜像文件作为根文件系统供内核加载,同时也用于存放编译好的内核模块,以及后续所需的各种配套工具程序。

5.1 创建磁盘镜像文件

使用 qemu-img 创建一个 512M 的磁盘镜像文件:

qemu-img create -f raw disk.raw 512M

现在 disk.raw 文件就相当于一块磁盘,为了在里面存储文件,需要先进行格式化,创建文件系统。比如在 Linux 系统中使用 ext4 文件系统进行格式化:

mkfs -t ext4 ./disk.raw

5.2 挂载磁盘镜像文件

格式化完成之后,可以在 Linux 系统中以 loop 方式将磁盘镜像文件挂载到一个目录上,这样就可以操作磁盘镜像文件中的内容了。
下面的命令将磁盘镜像文件挂载到 img 目录上:

sudo mount -o loop ./disk.raw ./img

5.3 安装内核模块

现在可以将之前编译好的内核模块安装到磁盘镜像中了。命令如下:

sudo make modules_install \ # 安装内核模块INSTALL_MOD_PATH=./img  # 指定安装路径

执行完成后即可在 ./img/lib/modules/ 下看到安装好的内核模块。

5.4 使用磁盘镜像文件作为根文件系统

准备好磁盘镜像文件后,使用下面的命令再次启动 qemu:

qemu-system-x86_64 \    -m 512M \    -smp 4\    -kernel ./bzImage \    -drive format=raw,file=./disk.raw \  # 指定文件作为磁盘    -append "root=/dev/sda"  # 内核启动参数,指定根文件系统所在设备

这一次,内核不再报根文件系统找不到了。但是报了另一个错误:

Kernel panic - not syncing: No working init found. Try passing init= option to Kernel. See Linux Documentation/admin-guide/init.rst for guidance.

这说明内核启动已经接近完成了,准备启动 1 号进程,也就是 init 进程。但我们的启动参数里面没有指定 init 选项,而且磁盘镜像中也没有相应的 init 程序。因此,接下来需要准备一个 init 程序供内核启动。

6. 准备 init 程序

常用的 init 程序有下面几种:

  • sysv init:传统 Linux 系统中最常用的 init 程序
  • systemd:目前最流行的 init 程序,很多主流发行版都已经切换到 systemd。systemd 针对 sysv init 启动速度慢、无法并行以及管控能力弱等问题进行了重新设计。参见 Rethinking PID 1
  • busybox init:通知用在嵌入式等小型系统中。除了 init 程序外,busybox 还包含了很多常用的命令工具,比如 lscat 等。busybox 非常轻量级,可以编译出完全独立无依赖的 busybox 套件。

这里选用 busybox 作为 init 程序及其它命令工具的提供者。

6.1 编译 busybox

下载 busybox 的源码到 Linux 系统中,准备进行编译,这里使用的 busybox 版本为 1.27.2。

busybox 的编译流程与内核很像,这里我们基于默认配置进行编译。首先,执行如下命令让默认配置生效:

make defconfig

接下来,在默认配置的基础上进行定制:

make menuconfig

这里有一个重要的配置,因为 busybox 将被用作 init 程序,而且我们的磁盘镜像中没有任何其它库,所以 busybox 需要被静态编译成一个独立、无依赖的可执行文件,以免运行时发生链接错误。配置路径如下:

Busybox Settings --->       --- Build Options       [*] Build BusyBox as a static binary (no shared libs)

最后,配置完成后执行编译:

make

编译完成后在当前目录下可以看到 busybox 可执行文件,查看大小才 2.5M 左右。整个 busybox 套件只有这一个可执行文件,里面包含了若干工具。比如:

./busybox ls -l./busybox ps

6.2 安装 busybox 到磁盘镜像

编译好 busybox 之后需要将其安装到磁盘镜像中以供使用。执行如下命令进行安装:

make CONFIG_PREFIX=<path_to_disk_img_mount_point> install

CONFIG_PREFIX 用于指定安装路径,需要指定到之前磁盘镜像文件的挂载目录,比如 ./img。进入磁盘镜像挂载目录查看,常见的文件系统结构已经建立起来了。查看 bin 和 sbin 目录下的命令,可以看到都是链接到
bin/busybox 的,busybox 会根据执行时的文件名来执行不同的功能。

6.3 使用 busybox 作为 init 程序

busybox 安装完成之后,使用内核启动参数 init= 来指定 busybox 作为 init 程序,再次尝试启动。

qemu-system-x86_64 \    -m 512M \    -smp 4\    -kernel ./bzImage \    -drive format=raw,file=./disk.raw \    -append "init=/linuxrc root=/dev/sda"

上述命令通过 init=/linuxrc 指定了 init 程序为根目录下的 linuxrc,实际上是一个指向 busybox 的软链接。

这一次内核成功找到了 init 程序并且创建出 init 进程,但是 init 执行过程中出现如下报错:

can't run '/etc/init.d/rcS': No such file or directory can't open /dev/tty3: No such file or directorycan't open /dev/tty4: No such file or directory

看样子,init 程序需要一些配置才能正常运行起来。

6.4 配置 busybox init

参考 busybox 代码中的 文档 可知,init 启动后会扫描 /etc/inittab 配置文件,这个配置文件决定了 init 程序的行为。而 busybox init 在没有
/etc/inittab 文件的情况下也能工作,因为它有默认行为。它的默认行为相当于如下配置:

::sysinit:/etc/init.d/rcS::askfirst:/bin/sh::ctrlaltdel:/sbin/reboot::shutdown:/sbin/swapoff -a::shutdown:/bin/umount -a -r::restart:/sbin/inittty2::askfirst:/bin/shtty3::askfirst:/bin/shtty4::askfirst:/bin/sh

参考文档,我们提供一份 /etc/inittab 配置文件如下:

::sysinit:/etc/init.d/rcS::askfirst:/bin/ash::ctrlaltdel:/sbin/reboot::shutdown:/sbin/swapoff -a::shutdown:/bin/umount -a -r::restart:/sbin/init

并且根据配置,我们创建可执行文件 /etc/init.d/rcS,内容如下(暂时什么事都不做):

#!/bin/sh

配置完成以后再次尝试启动,这次将成功启动,并且出现如下提示:

Please press Enter to activate this console.

按提示按下 Enter 键之后将会启动 shell,进行到我们熟悉的环境,可以执行各种常用命令了。

6.5 挂载 /dev, /proc, /sys 文件系统

查看当前系统环境,会发现当前文件系统结构是不完整的。比如没有 /dev, /proc 以及 /sys 挂载点。这样我们无法通过 /dev 查看系统中的设备,如果执行
df 命令也会因为没有 /proc 挂载点而报错:

df: /proc/mounts: No such file or directory

因此,我们需要手工创建 /dev, /proc, /sys 这三个目录。/dev 目录创建完成后重启系统即可工作,但 /proc 和 /sys 需要执行挂载才可工作,可以将 /proc 和 /sys 的挂载动作放到
/etc/init.d/rcS 中,每次系统启动时自动挂载。修改 /etc/init.d/rcS 内容如下:

#!/bin/shmount -t proc proc /procmount -t sysfs sysfs /sys

重新启动系统查看,可以看到 /dev, /proc, /sys 挂载点都相应有了内容。

7. 小结

本文介绍了通过 qemu 作为模拟器,自己动手编译内核,并从头配置 init 进程,构建出一个最小的可运行系统,可用于验证对内核的改动。
通过这次开发环境搭建,对系统的启动过程有了一个粗略的了解。但这只是迈出了第一步,后续还有长路漫漫。

同步发布:https://hellogc.net/archives/121

`