前言 推荐学习顺序:1. 基础知识 → 2. 进程管理 → 3. 内存管理 → 4. 进程间通信 → 5. 文件系统 → 6. 设备驱动 → 7. 网络协议栈 → 8. 虚拟化 。
环境搭建
项目地址:linux_kernel_research
工具链: 通过网盘分享的文件:LKR_TOOL.tgz 链接: https://pan.baidu.com/s/1SCRsg9bSmILlvNN2moxXXw?pwd=s274 提取码: s274 –来自百度网盘超级会员v6的分享
交叉编译工具链下载 toolchains-bootlin musl-cc 裸机编译工具链可以自行寻找。
大家可以使用ubuntu 24.04或者windows+wsl2,Mac的配置和Linux大同小异。qemu有windwos的安装包,也可以使用windows的qemu,即WSL2+WINDOWS。这一部分内容可以参考我之前写的Pwn_kernel的内核模块开发部分。需要注意的是Windwos的qemu和Linux的qemu在启动命令上是有些不同的,linux的一些指令和功能特性是Windows不支持的。也可以选择在wsl2中编译qemu。建议使用Linux的qemu,功能更为完善强大。
1 2 3 sudo apt update sudo apt install build-essential -y sudo apt install gdb gdb-multiarch -y
windows 1 2 3 choco install git msys2 cmake make ninja -y git lfs install choco install visualstudio2022community --package-parameters "--add Microsoft.VisualStudio.Workload.NativeDesktop" -y
**msys2->clang64 / msys2->ucrt64**。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 pacman -Syu pacman -S base-devel wget curl coreutils binutils pacman -S mingw-w64-clang-x86_64-toolchain \ mingw-w64-clang-x86_64-clang \ mingw-w64-clang-x86_64-llvm pacman -S mingw-w64-clang-x86_64-cmake \ mingw-w64-clang-x86_64-ninja pacman -S mingw-w64-clang-x86_64-clang-tools-extra \ mingw-w64-clang-x86_64-bear gcc --version g++ --version clang --version cmake --version
包前缀对照表
环境
完整前缀
缩写提示
MINGW64
mingw-w64-x86_64-
x86_64
UCRT64
mingw-w64-ucrt-x86_64-
ucrt64
CLANG64
mingw-w64-clang-x86_64-
clang64
zsh-omz 安装 1 2 3 4 5 6 7 8 9 10 11 12 13 sudo apt-get install zsh -y chsh -s $(which zsh) sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh) " git clone https://github.com/zsh-users/zsh-syntax-highlighting.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom} /plugins/zsh-syntax-highlighting git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-~/.oh-my-zsh/custom} /plugins/zsh-autosuggestions vim ~/.zshrc plugins=(git z zsh-syntax-highlighting zsh-autosuggestions) source ~/.zshrc
Linux内核编译所需的库 1 2 3 4 5 6 7 8 9 10 11 sudo apt install gcc make bc bison flex libssl-dev libelf-dev sudo apt install libncurses5-dev libncursesw5-dev sudo apt install zlib1g-dev liblz4-dev liblzma-dev libzstd-dev sudo apt install dwarves rsync kmod cpio initramfs-tools-core
Busybox编译所需的库 1 2 3 4 5 sudo apt install libc6-dev sudo apt install libc6-dev-i386 lib32gcc-s1 lib32stdc++6
Qemu编译所需的库 QEMU编译核心依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 sudo apt install -y gcc make cmake ninja-build pkg-config sudo apt install -y python3 python3-pip python3-dev python3-venv sudo apt install -y libc6-dev-i386 libglib2.0-dev libpixman-1-dev libmount-dev libunistring-dev libp11-kit-dev sudo apt install zlib1g-dev libglib2.0-dev libpixman-1-dev libslirp-dev sudo apt install -y \ liburing-dev \ libnfs-dev
图形和显示支持
1 2 3 4 5 6 7 8 9 10 11 sudo apt install libsdl2-dev libsdl2-image-dev sudo apt install libgtk-3-dev sudo apt install libvncserver-dev sudo apt install libspice-server-dev libspice-protocol-dev
网络和存储支持
1 2 3 4 5 6 7 8 9 10 11 sudo apt install libcap-ng-dev libattr1-dev sudo apt install libaio-dev libcap-dev libiscsi-dev sudo apt install liblzo2-dev libsnappy-dev libbz2-dev liblzma-dev libzstd-dev sudo apt install libgcrypt20-dev libgnutls28-dev
音频支持
1 sudo apt install libasound2-dev libpulse-dev
虚拟化和硬件加速
1 2 3 4 5 6 7 8 sudo apt install libvirt-dev sudo apt install libusb-1.0-0-dev libusbredirparser-dev sudo apt install libcacard-dev
可选高级功能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 sudo apt install valgrind sudo apt install texinfo sudo apt install libcurl4-gnutls-dev libssh-dev sudo apt install librdmacm-dev libibverbs-dev sudo apt install libseccomp-dev
Buildroot编译需要的库 1 2 3 sudo apt install -y git make gcc g++ unzip patch bc libncurses5-dev \ libssl-dev libelf-dev bison flex rsync cpio python3 python3-pip \ file wget
交叉编译工具链安装 ARM EABI 交叉编译工具链
ARM EABI(Embedded Application Binary Interface)主要用于较老的ARM处理器:
1 2 3 4 sudo apt update sudo apt install gcc-arm-linux-gnueabi g++-arm-linux-gnueabi sudo apt install libc6-dev-armel-cross
ARM EABIHF 交叉编译工具链
ARM EABIHF(Hard Float)支持硬件浮点运算,适用于ARMv7架构:
1 2 3 sudo apt install gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf sudo apt install libc6-dev-armhf-cross
AArch64 交叉编译工具链
AArch64是ARM的64位架构:
1 2 3 sudo apt install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu sudo apt install libc6-dev-arm64-cross
RISC-V 交叉编译工具链
ubuntu缺乏riscv-32位相关的包,我们需要从官网进行下载编译。
1 2 3 sudo apt install gcc-riscv64-linux-gnu g++-riscv64-linux-gnu sudo apt install libc6-dev-riscv64-cross
其他工具链安装
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 sudo apt install gcc-arm-linux-gnueabi g++-arm-linux-gnueabi -y sudo apt install gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf -y sudo apt install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu -y sudo apt install gcc-riscv64-linux-gnu g++-riscv64-linux-gnu -y sudo apt install gcc-x86-64-linux-gnu g++-x86-64-linux-gnu -y sudo apt install gcc-i686-linux-gnu g++-i686-linux-gnu -y sudo apt install gcc-mipsel-linux-gnu g++-mipsel-linux-gnu -y sudo apt install gcc-mips64el-linux-gnuabi64 g++-mips64el-linux-gnuabi64 -y sudo apt install gcc-mips-linux-gnu g++-mips-linux-gnu -y sudo apt install gcc-mips64-linux-gnuabi64 g++-mips64-linux-gnuabi64 -y sudo apt install gcc-powerpc-linux-gnu g++-powerpc-linux-gnu -y sudo apt install gcc-powerpc64-linux-gnu g++-powerpc64-linux-gnu -y sudo apt install gcc-alpha-linux-gnu g++-alpha-linux-gnu -y sudo apt install gcc-s390x-linux-gnu g++-s390x-linux-gnu -y sudo apt install gcc-sparc64-linux-gnu g++-sparc64-linux-gnu -y sudo apt install gcc-arc-linux-gnu g++-arc-linux-gnu -y sudo apt install gcc-m68k-linux-gnu g++-m68k-linux-gnu -y
由于是做相关项目,我们将相关的交叉编译工具链单独放在了项目文件夹里。大家可以通过绝对路径来引用,当然你也可以将其添加到你的环境变量上。我们使用的是glibc和elf,也就是使用glibc库和裸机编译。
我们现在暂时用不到裸机编译工具链none, unknow-elf版本,所以可以不下载。
toolchains-bootlin 下面是aarch64工具链的区别对比,其他架构也大同小异。
主要区别对比
特性
aarch64-none-linux-gnu
aarch64-none-elf-gnu
aarch64-linux-gnu
目标环境
Linux用户空间
裸机/固件
Linux用户空间
系统调用
支持Linux系统调用
无系统调用
支持Linux系统调用
标准库
glibc
newlib或无
glibc
内存管理
虚拟内存
物理内存
虚拟内存
启动方式
操作系统加载
直接启动
操作系统加载
我们学习Linux内核用到的架构只有常用的 RISCV-64,ARM64,x86_64三种64位架构。
完整的一键安装命令 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 sudo apt update && sudo apt install -y \ build-essential \ gcc make bc bison flex \ libssl-dev libelf-dev \ libncurses5-dev libncursesw5-dev \ zlib1g-dev liblz4-dev liblzma-dev libzstd-dev \ dwarves rsync kmod cpio initramfs-tools-core \ libc6-dev git curl wget sudo apt update && sudo apt install -y \ build-essential \ gcc make cmake ninja-build pkg-config \ python3 python3-pip python3-dev python3-venv \ zlib1g-dev libglib2.0-dev libpixman-1-dev \ libsdl2-dev libsdl2-image-dev \ libgtk-3-dev libvncserver-dev \ libspice-server-dev libspice-protocol-dev \ libcap-ng-dev libattr1-dev \ libaio-dev libcap-dev libiscsi-dev \ liblzo2-dev libsnappy-dev libbz2-dev liblzma-dev libzstd-dev \ libgcrypt20-dev libgnutls28-dev \ libasound2-dev libpulse-dev \ libvirt-dev \ libusb-1.0-0-dev libusbredirparser-dev \ libcacard-dev \ texinfo \ libcurl4-gnutls-dev libssh-dev \ libseccomp-dev sudo apt install -y git make gcc g++ clang unzip patch bc libncurses5-dev \ libssl-dev libelf-dev bison flex rsync cpio python3 python3-pip \ file wget bear sudo apt install gcc make cmake ninja-build pkg-config -y sudo apt install python3 python3-pip python3-dev python3-venv -y sudo apt install zlib1g-dev libglib2.0-dev libpixman-1-dev libslirp-dev -y sudo apt install -y liburing-dev libnfs-dev sudo apt install -y genisoimage sudo apt install -y libc6-dev-i386 libglib2.0-dev libpixman-1-dev \ libmount-dev libunistring-dev libp11-kit-dev sudo apt install -y libdw-dev sudo apt install libncurses-dev libtinfo-dev sudo apt install -y devscripts config-package-dev debhelper-compat golang sudo apt install -y jackd2 libjack-jackd2-dev libpipewire-0.3-dev pipewire-jack sudo apt install -y libvirglrenderer-dev libepoxy-dev libgbm-dev sudo apt install -y libvte-dev sudo apt install -y libvdeplug-dev sudo apt install libsdl2-dev libsdl2-image-dev -y sudo apt install libgtk-3-dev -y sudo apt install libvncserver-dev -y sudo apt install libspice-server-dev libspice-protocol-dev -y sudo apt install libcap-ng-dev libattr1-dev -y sudo apt install libaio-dev libcap-dev libiscsi-dev -y sudo apt install liblzo2-dev libsnappy-dev libbz2-dev liblzma-dev libzstd-dev -y sudo apt install libgcrypt20-dev libgnutls28-dev -y sudo apt install libasound2-dev libpulse-dev -y sudo apt install libvirt-dev -y sudo apt install libusb-1.0-0-dev libusbredirparser-dev -y sudo apt install libcacard-dev -y sudo apt install valgrind -y sudo apt install texinfo -y sudo apt install libcurl4-gnutls-dev libssh-dev -y sudo apt install librdmacm-dev libibverbs-dev -y sudo apt install libseccomp-dev -y sudo apt update && sudo apt install -y linux-headers-generic linux-libc-dev sudo apt install libguestfs-tools sudo apt install gcc-arm-linux-gnueabi g++-arm-linux-gnueabi -y sudo apt install gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf -y sudo apt install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu -y sudo apt install gcc-riscv64-linux-gnu g++-riscv64-linux-gnu -y sudo apt install gcc-x86-64-linux-gnu g++-x86-64-linux-gnu -y sudo apt install gcc-i686-linux-gnu g++-i686-linux-gnu -y sudo apt install gcc-mipsel-linux-gnu g++-mipsel-linux-gnu -y sudo apt install gcc-mips64el-linux-gnuabi64 g++-mips64el-linux-gnuabi64 -y sudo apt install gcc-mips-linux-gnu g++-mips-linux-gnu -y sudo apt install gcc-mips64-linux-gnuabi64 g++-mips64-linux-gnuabi64 -y sudo apt install gcc-powerpc-linux-gnu g++-powerpc-linux-gnu -y sudo apt install gcc-powerpc64-linux-gnu g++-powerpc64-linux-gnu -y sudo apt install gcc-alpha-linux-gnu g++-alpha-linux-gnu -y sudo apt install gcc-s390x-linux-gnu g++-s390x-linux-gnu -y sudo apt install gcc-sparc64-linux-gnu g++-sparc64-linux-gnu -y sudo apt install gcc-arc-linux-gnu g++-arc-linux-gnu -y sudo apt install gcc-m68k-linux-gnu g++-m68k-linux-gnu -y sudo apt update && sudo apt autoremove && sudo apt full-upgrade -y
编译步骤提示 Linux内核编译: Linux内核下载:
1 2 3 4 wget https://www.kernel.org/pub/linux/kernel/v5.x/linux-5.15.188.tar.gz tar -xvf linux-5.15.188.tar.gz wget https://www.kernel.org/pub/linux/kernel/v6.x/linux-6.12.38.tar.gz tar -xvf linux-6.12.38.tar.gz
1 2 3 4 5 6 7 8 9 10 11 make menuconfig make bzImage -j$(nproc ) sudo make modules_install sudo make install
清华源
make menuconfig
这里我们主要关注调试方面的选项,依次进入到 Kernel hacking -> Compile-time checks and compiler options,然后勾选如下选项Compile the kernel with debug info,以便于调试。不过似乎现在是默认开启的。如果要使用 kgdb 调试内核,则需要选中 KGDB: kernel debugger,并选中 KGDB 下的所有选项。
报错处理:
【1】
问题概述:
make[1]: *** No rule to make target 'debian/canonical-certs.pem', needed by 'certs/x509_certificate_list'. Stop.
解决方法:
编辑 .config 文件,搜索debian/canonical-certs.pem并把这个字符串删掉。
删除前:
CONFIG_SYSTEM_TRUSTED_KEYS=”debian/canonical-certs.pem”
删除后
CONFIG_SYSTEM_TRUSTED_KEYS=””
【2】
问题概述:
make[2]: *** No rule to make target 'net/netfilter/xt_TCPMSS.o', needed by 'net/netfilter/built-in.a'. Stop.
解决方法:
Makefile 中的 xt_TCPMSS.c 是大写的,而源文件名 (xt_tcpmss.c) 是小写的。这是一个大小写不匹配的问题。
【3】
1 2 3 4 5 /usr/bin/ld: scripts/dtc/dtc-parser.tab.o:(.bss+0x10): multiple definition of `yylloc'; scripts/dtc/dtc-lexer.lex.o:(.bss+0x0): first defined here collect2: error: ld returned 1 exit status make[2]: *** [scripts/Makefile.host:100: scripts/dtc/dtc] Error 1 make[1]: *** [scripts/Makefile.build:403: scripts/dtc] Error 2 make: *** [Makefile:555: scripts] Error 2
1 2 3 4 5 修改scripts/dtc目录下的dtc-lexer.lex.c_shipped文件中找到 YYLTYPE yyloc这一行,在640行,在之前面加上extern 保存退出, make 编译 正常编译
验证源文件名
你可以先检查一下实际的源文件名:
1 ls net/netfilter/xt_*tcpmss*
这应该会显示实际的文件名是 xt_tcpmss.c(小写)。
1. 找到并编辑 Makefile
1 vim net/netfilter/Makefile
2. 找到第157行左右的内容
寻找类似这样的行:
1 obj-$(CONFIG_NETFILTER_XT_TARGET_TCPMSS) += xt_TCPMSS.o
3. 将大写的 TCPMSS 改为小写的 tcpmss
修改为:
1 obj-$(CONFIG_NETFILTER_XT_TARGET_TCPMSS) += xt_tcpmss.o
4. 保存并重新编译
make bzImage -j4
注意事项:
注意 gcc 版本问题,4.*一般用 gcc-5,5.*一般用 gcc-7。
gcc多版本共存请参考这里
编译成功后
我们一般主要关注于如下的文件
RISC-V64
镜像名 : Image
路径 : arch/riscv/boot/Image
说明 : 与ARM64一样,RISC-V也使用未压缩的Image格式
x86_64
镜像名 : bzImage
路径 : arch/x86/boot/bzImage
说明 : “big zImage”的缩写,实际上是压缩的内核镜像
ARM64
镜像名 : Image
路径 : arch/arm64/boot/Image
说明 : 未压缩的内核镜像
MIPS
镜像名 : vmlinux.bin 或 vmlinux
路径 : arch/mips/boot/vmlinux.bin
说明 : MIPS架构通常使用vmlinux.bin,某些情况下也会有压缩版本
PowerPC
镜像名 : zImage 或 uImage
路径 : arch/powerpc/boot/zImage
说明 : PowerPC使用zImage(压缩镜像)或uImage(U-Boot格式)
ARM32
镜像名 : zImage 或 uImage
路径 : arch/arm/boot/zImage
说明 : 32位ARM使用压缩的zImage格式
SPARC
镜像名 : zImage 或 vmlinux
路径 : arch/sparc/boot/zImage
Alpha
查看所有可用的镜像目标
你可以通过以下命令查看特定架构支持的所有镜像格式:
1 2 3 4 5 make help | grep -A 10 "Architecture specific targets" make help
镜像格式说明
Image : 未压缩的内核镜像,主要用于ARM64和RISC-V
zImage : 压缩的内核镜像,自解压,常用于ARM32、PowerPC等
bzImage : “big zImage”,x86架构的压缩内核镜像
uImage : U-Boot格式的内核镜像,包含加载地址等信息
vmlinux : 未压缩的ELF格式内核镜像,主要用于调试
实际编译示例
对于不同架构,你可以明确指定要编译的镜像类型:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 make ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- -j$(nproc ) menuconfig scripts/config -e BLK_DEV_INITRD scripts/config -e DEVTMPFS scripts/config -e DEVTMPFS_MOUNT scripts/config -e TMPFS scripts/config -e SYSFS scripts/config -e PROC_FS scripts/config -e VIRTIO scripts/config -e VIRTIO_MMIO scripts/config -e NET scripts/config -e VIRTIO_NET scripts/config -e VIRTIO_CONSOLE scripts/config -e VIRTIO_BLK scripts/config -e SERIAL_8250 scripts/config -e SERIAL_8250_CONSOLE scripts/config -d VIRTIO_MMIO_CMDLINE_DEVICES make ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- -j$(nproc ) Image make ARCH=x86_64 CROSS_COMPILE=x86_64-linux-gnu- -j$(nproc ) menuconfig make ARCH=x86_64 CROSS_COMPILE=x86_64-linux-gnu- -j$(nproc ) bzImage make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j$(nproc ) defconfig make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j$(nproc ) menuconfig make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j$(nproc ) olddefconfig scripts/config -e BLK_DEV_INITRD scripts/config -e RD_GZIP scripts/config -e DEVTMPFS scripts/config -e DEVTMPFS_MOUNT scripts/config -e TMPFS scripts/config -e SYSFS scripts/config -e PROC_FS scripts/config -e SERIAL_AMBA_PL011 scripts/config -e SERIAL_AMBA_PL011_CONSOLE scripts/config -e VIRTIO scripts/config -e VIRTIO_MMIO scripts/config -e VIRTIO_MMIO_CMDLINE_DEVICES scripts/config -e NET scripts/config -e VIRTIO_NET make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j$(nproc ) Image dtbs make ARCH=arm CROSS_COMPILE=arm-buildroot-linux-gnueabihf- -j$(nproc ) vexpress_defconfig scripts/config -e BLK_DEV_INITRD -e DEVTMPFS -e DEVTMPFS_MOUNT -e TMPFS -e SERIAL_AMBA_PL011 -e ARM_APPENDED_DTB -e USE_OF -e ARM_ATAG_DTB_COMPAT -e ARM_ATAG_DTB_COMPAT_CMDLINE_FROM_BOOTLOADER -e SMP -e ARM_GIC -e CACHE_L2X0 -e AMBA -e ARM_TIMER_SP804 make ARCH=arm CROSS_COMPILE=arm-buildroot-linux-gnueabihf- -j$(nproc ) menuconfig make ARCH=arm CROSS_COMPILE=arm-buildroot-linux-gnueabihf- -j$(nproc ) zImage dtbs make ARCH=mips CROSS_COMPILE=mips-linux-gnu- menuconfig make ARCH=mips CROSS_COMPILE=mips-linux-gnu- vmlinux.bin
Busybox编译: Busybox下载:
1 2 wget https://busybox.net/downloads/busybox-1.36.1.tar.bz2 tar -jxvf busybox-1.36.1.tar.bz2
1 2 3 4 5 6 7 8 9 10 11 12 ➜ busybox-1.36.1 mkdir -p ./build/x86_64 ➜ busybox-1.36.1 make menuconfig ➜ busybox-1.36.1 make -j$(nproc ) ➜ busybox-1.36.1 make install
如果你的内核版本大于6.8.0编译可能会报错:https://lists.busybox.net/pipermail/busybox-cvs/2024-January/041752.html
只需要把tc.c移除或者禁用即可。
或者使用 patch 。
交叉编译只需要修改Cross complier prefix的值即可,比如aarch64-linux-gnu-。
Qemu 编译: QEMU编译步骤
1 2 3 4 5 6 7 8 9 10 11 12 13 wget https://download.qemu.org/qemu-10.0.2.tar.xz tar -xvf qemu-10.0.2.tar.xz cd qemu-10.0.2./configure --enable-kvm --enable-gtk --enable-spice --enable-usb-redir --enable-slirp make -j$(nproc ) sudo make install
注意事项
不同版本的QEMU可能对依赖库的要求略有不同
可以通过 ./configure --help 查看具体的编译选项
如果只需要特定架构支持,可以使用 --target-list 参数减少编译时间
某些功能需要相应的内核模块支持(如KVM需要加载kvm模块)
这些库足以支持QEMU的完整功能编译,包括各种虚拟化特性、图形界面、网络和存储支持等。
Buildroot 编译: 1 2 wget https://buildroot.org/downloads/buildroot-2025.02.4.tar.gz tar -xvf buildroot-2025.02.4.tar.gz
ARM64 Linux编译
查看可用的ARM64相关配置
1 2 3 4 5 6 7 ➜ buildroot-2025.02.4 make list-defconfigs | grep aarch64 make: Warning: File '/mnt/d/DM/linux_kernel_research/buildroot-2025.02.4/output/.br2-external.mk' has modification time 0.47 s in the future aarch64_efi_defconfig - Build for aarch64_efi qemu_aarch64_ebbr_defconfig - Build for qemu_aarch64_ebbr qemu_aarch64_sbsa_defconfig - Build for qemu_aarch64_sbsa qemu_aarch64_virt_defconfig - Build for qemu_aarch64_virt make: warning: Clock skew detected. Your build may be incomplete.
使用QEMU ARM64配置作为基础
1 ➜ buildroot-2025.02.4 make qemu_aarch64_virt_defconfig
运行配置界面进行定制
1 2 3 4 5 6 ➜ buildroot-2025.02.4 make menuconfig kernel-> filesystem->
make 即可,输出目录在output/images/
错误处理:
【1】
报错:
➜ buildroot-2025.02.4 make -j$(nproc) ERROR: No hash found for linux-5.15.18.tar.xz make: *** [package/pkg-generic.mk:179: /mnt/d/DM/linux_kernel_research/buildroot-2025.02.4/output/build/linux-headers-5.15.18/.stamp_downloaded] Error 1
成因:
没有对应sha256值用来校验。
解决方案:
第一种方法:添加对应值上去。
第二种方法:使用官方有的版本。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ➜ buildroot-2025.02.4 cat ./linux/linux.hash sha256 c0a575630f2603a20bb0641f8df8f955e46c9d7ac1fae8b54b21316e6b52a254 linux-6.12.33.tar.xz sha256 0d79ff359635e9f009f1e330deed5f3aefd8c452b80660bffdc504b877797719 linux-6.6.93.tar.xz sha256 bc3c45faf6f5f0450666c75fa9dad9bc7c0cf7c7cba0dbd94e5cfdc58229c116 linux-6.1.141.tar.xz sha256 3d03eb798910f32929f7fda5a56e4bb1a121f10bde320d6f3063639c009313dc linux-5.15.185.tar.xz sha256 07c852940dc2dc03fe84f7fcf697648d7cba11c62d20504380492ba07aa46bb6 linux-5.10.238.tar.xz sha256 c879d0ba817aaa0fde318d58d7e1f141d9c29bd8569a96b73159ebc448077b99 linux-5.4.294.tar.xz sha256 fb0edc3c18e47d2b6974cb0880a0afb5c3fa08f50ee87dfdf24349405ea5f8ae linux-cip-5.10.162-cip24.tar.gz sha256 b5539243f187e3d478d76d44ae13aab83952c94b885ad889df6fa9997e16a441 linux-cip-5.10.162-cip24-rt10.tar.gz sha256 fb5a425bd3b3cd6071a3a9aff9909a859e7c1158d54d32e07658398cd67eb6a0 COPYING sha256 f6b78c087c3ebdf0f3c13415070dd480a3f35d8fc76f3d02180a407c1c812f79 LICENSES/preferred/GPL-2.0 sha256 8e378ab93586eb55135d3bc119cce787f7324f48394777d00c34fa3d0be3303f LICENSES/exceptions/Linux-syscall-note
Qemu 调试 Linux Kernel 我们使用 Linux 上的 Qemu。如果你使用 Windwos 的 Qemu 注意修改启动参数。
x86_64
首先在busybox文件夹创建一些系统文件:
1 mkdir -p lib tmp proc sys dev etc/init.d
(可选)然后编写一个内核模块(感兴趣看内核开发部分,或者可以从Pwn_kernel的内核模块开发部分简单了解),将其放在/lib/目录中。
编写一个init脚本,放在根目录即可。
1 2 3 4 5 6 7 8 9 10 11 #!/bin/sh echo "INIT SCRIPT" mount -t proc none /proc mount -t sysfs none /sys mount -t devtmpfs none /dev mount -t debugfs none /sys/kernel/debug mount -t tmpfs none /tmp insmod /lib/ko_test.ko echo -e "Boot took $(cut -d' ' -f1 /proc/uptime) seconds" setsid /bin/cttyhack setuidgid 0 /bin/sh poweroff -f
打包文件系统:
1 find . | cpio -o -H newc > ../rootfs.cpio
将编译好的/kernel/arch/x86/boot/bzImage复制到rootfs.img 同级目录。之后便可以启动Qemu。
Linux启动脚本:
1 2 3 4 5 6 7 8 9 10 #!/bin/sh qemu-system-x86_64 \ -m 64M \ -nographic \ -kernel ./bzImage \ -initrd ./rootfs.cpio \ -append "init=/init root=/dev/ram rw console=ttyS0 oops=panic panic=1 kaslr" \ -smp cores=2,threads=2 \ -cpu kvm64 \ -s
windwos pwsh 启动脚本。
1 2 3 4 5 6 7 8 9 qemu-system-x86_64 .exe ` -m 64 M ` -nographic ` -kernel .\bzImage ` -initrd .\rootfs.cpio ` -append "init=/init root=/dev/ram rw console=ttyS0 oops=panic panic=1 kaslr" ` -smp cores=2 ,threads=2 ` -cpu kvm64 ` -s
可以使用-append "init=/init"参数指定启动脚本,不指定则默认使用根目录下的init。我们这里养成良好习惯显示指定init脚本。
如果要调试用户态程序可以使用qemu的端口转发功能。假如我们在qemu内使用gdbserver监听了1337端口。
1 2 3 qemu-system-x86_64 \ -netdev user,id =net0,hostfwd=tcp::10001-:1337 \ -device virtio-net-pci,netdev=net0
这样我们可以从宿主机10001端口访问qemu内部的1337调试端口。
基本命令格式
1 2 3 qemu-system-x86_64 \ -netdev user,id =<网络标识>,hostfwd=<协议>:<宿主机IP>:<宿主机端口>-<虚拟机IP>:<虚拟机端口> \ -device <网卡驱动>,netdev=<网络标识>
关键参数说明
-netdev user 启用用户模式网络栈(无需 root 权限),支持端口转发。
id=<网络标识> 自定义网络设备标识(如 net0),用于关联后续 -device。
hostfwd=<规则>
端口转发规则,格式:
1 协议:宿主机IP:宿主机端口-虚拟机IP:虚拟机端口
协议:tcp 或 udp
IP 省略时默认绑定 0.0.0.0(any)
-device <网卡驱动> 指定虚拟网卡类型(如 virtio-net-pci)。
调试工具
multiarch-gdbserver-static :调试内部程序用的静态编译的gdbserver。
ARM64
Linux 启动脚本:
1 2 3 4 5 6 7 8 9 qemu-system-aarch64 \ -M virt \ -cpu cortex-a53 \ -m 512 \ -nographic \ -kernel ./Image \ -initrd ./rootfs.cpio \ -append "console=ttyAMA0 rdinit=/init quiet" \ -s
RISC-V64
Linux 启动脚本
1 2 3 4 5 6 7 8 9 qemu-system-riscv64 \ -machine virt \ -cpu rv64 \ -m 512 \ -nographic \ -kernel ./Image \ -initrd ./rootfs.cpio \ -append "console=ttyS0 rdinit=/init quiet" \ -s
Linux 内核启动概述
本书基于 Linux 6.12.38 源码,详细讲解 x86_64 和 ARM64 架构的内核启动流程
为什么学习内核启动流程? 理解内核启动流程是深入掌握 Linux 内核的基础。通过学习启动流程,你将:
理解系统底层工作原理 - 从硬件加电到用户空间进程的完整过程
掌握架构特定知识 - x86_64 和 ARM64 的底层差异与共性
提升调试能力 - 能够诊断早期启动问题
为内核开发打下基础 - 无论是驱动开发还是内核开发
本书的组织结构 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 ┌─────────────────────────────────────────────────────────────────┐ │ 内核启动流程全景 │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ 第一阶段:固件引导 │ │ ├── x86: BIOS POST / UEFI 固件 │ │ └── ARM64: UEFI / ATF / U-Boot │ │ │ │ 第二阶段:引导程序 │ │ ├── x86: GRUB / systemd-boot │ │ └── ARM64: GRUB / U-Boot │ │ │ │ 第三阶段:内核引导代码 │ │ ├── x86: header.S → main.c → head_64.S │ │ └── ARM64: head.S (primary_entry) │ │ │ │ 第四阶段:内核解压与初始化 │ │ ├── 解压内核 (compressed/) │ │ └── startup_64 / __primary_switch │ │ │ │ 第五阶段:C语言初始化 │ │ ├── head64.c / setup.c (架构特定) │ │ └── start_kernel() (通用入口) │ │ │ │ 第六阶段:子系统初始化 │ │ ├── 内存管理、调度器、中断系统 │ │ └── initcall 机制 │ │ │ │ 第七阶段:用户空间启动 │ │ ├── kernel_init() → do_initcalls() │ │ └── 执行 /sbin/init 或用户指定的 init │ │ │ └─────────────────────────────────────────────────────────────────┘
内核启动阶段划分 按执行模式划分
阶段
x86_64
ARM64
代码位置
实模式/EL3
BIOS POST
EL3 (Secure)
固件
16位/EL2
Bootloader
ATF/EFI
arch/x86/boot/
32位/EL1
Protected Mode
EL1
compressed/head_64.S
64位/EL1
Long Mode
EL1
kernel/head64.c
按代码类型划分 1 2 3 4 5 6 7 8 9 10 11 12 ┌───────────────────────────────────────────────────────────────┐ │ 代码类型演进 │ ├───────────────────────────────────────────────────────────────┤ │ │ │ ┌──────────┐ ┌──────────────┐ ┌──────────────────┐ │ │ │ 汇编代码 │ → │ 混合代码 │ → │ 纯 C 代码 │ │ │ │ (早期) │ │ (解压阶段) │ │ (主初始化) │ │ │ └──────────┘ └──────────────┘ └──────────────────┘ │ │ │ │ 无库函数支持 有限库函数 完整内核基础设施 │ │ │ └───────────────────────────────────────────────────────────────┘
关键源码位置 x86_64 启动路径 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 arch/x86/ ├── boot/ │ ├── header.S # 引导头部 (0xAA55 签名, PE 头) │ ├── main.c # 实模式初始化 │ ├── pm.c # 保护模式切换 │ ├── video.c # 视频初始化 │ ├── memory.c # 内存检测 │ └── compressed/ │ ├── head_64.S # 32→64位转换, 解压入口 │ ├── misc.c # 解压核心逻辑 │ ├── efi.c # EFI Stub 支持 │ └── pgtable_64.c # 早期页表设置 └── kernel/ ├── head64.c # 64位内核入口 ├── setup.c # 架构初始化 ├── e820.c # 内存映射处理 └── acpi.c # ACPI 初始化
ARM64 启动路径 1 2 3 4 5 6 7 8 9 10 11 arch/arm64/ ├── kernel/ │ ├── head.S # 内核入口 (primary_entry) │ ├── setup.c # 架构初始化 │ ├── cpu_ops.c # CPU 操作 │ └── smp.c # SMP 启动 ├── mm/ │ ├── mmu.c # MMU 初始化 │ └── proc.S # CPU 特定初始化 └── boot/ └── efi-header.S # EFI PE 头
通用初始化 1 2 3 4 5 6 7 8 9 10 11 12 init/ ├── main.c # start_kernel(), rest_init() ├── do_mounts.c # 根文件系统挂载 └── initramfs.c # initramfs 处理 kernel/ ├── sched/ │ └── core.c # 调度器初始化 ├── irq/ │ └── irqdesc.c # 中断描述符 └── time/ └── timekeeping.c # 时间子系统
启动相关的关键数据结构 x86: boot_params 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 struct boot_params { struct setup_header hdr ; struct screen_info screen_info ; struct apm_bios_info apm_bios_info ; u8 _pad2[4 ]; struct sys_desc_table sys_desc_table ; struct olpc_ofw_header olpc_ofw_header ; u32 ext_ramdisk_image; u32 ext_ramdisk_size; u32 ext_cmd_line_ptr; u8 _pad3[116 ]; struct e820_entry e820_map [E820_MAX_ENTRIES_ZEROPAGE ]; u8 _pad4[48 ]; struct edd_info eddbuf [EDDMAXNR ]; u8 _pad5[276 ]; struct efi_info efi_info ; u32 alt_mem_k; u32 scratch; u8 e820_entries; u8 eddbuf_entries; u8 _pad6[6 ]; struct setup_data hdr_setup_data ; char cmdline[COMMAND_LINE_SIZE]; };
ARM64: 设备树 (Device Tree) 1 2 3 4 5 6 7 8 9 10 11 12 13 struct fdt_header { u32 magic; u32 totalsize; u32 off_dt_struct; u32 off_dt_strings; u32 off_mem_rsvmap; u32 version; u32 last_comp_version; u32 boot_cpuid_phys; u32 size_dt_strings; u32 size_dt_struct; };
内存布局变化 x86_64 内存布局演变 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 实模式 (16-bit): ┌─────────────────────────────────────┐ │ 0x00000000 - 0x000003FF IVT │ │ 0x00000400 - 0x000004FF BDA │ │ 0x00007C00 - 0x00007DFF MBR/Boot │ │ 0x00090000 - 0x00090FFF boot_params│ │ 0x000A0000 - 0x000BFFFF Video RAM │ │ 0x000C0000 - 0x000C7FFF Video BIOS │ │ 0x000F0000 - 0x000FFFFF System BIOS│ └─────────────────────────────────────┘ 总寻址空间: 1MB (20位地址线) 保护模式 (32-bit): ┌─────────────────────────────────────────────┐ │ 0x00000000 - 0xffffffff (4GB 可寻址空间) │ │ │ │ 分段寻址 + 分页寻址 (可选) │ └─────────────────────────────────────────────┘ 长模式 (64-bit): ┌──────────────────────────────────────────────────────────┐ │ 用户空间: │ │ 0x0000000000000000 - 0x00007fffffffffff (128 TB) │ │ │ │ 内核空间: │ │ 0xffff800000000000 - 0xffff87ffffffffff (64 TB) │ │ 直接映射区 │ │ │ │ 0xffff880000000000 - 0xffffc7ffffffffff (64 TB) │ │ vmalloc/ioremap 空间 │ │ │ │ 0xffffffff80000000 - 0xffffffffffffffff (2 GB) │ │ 内核代码/数据 │ └──────────────────────────────────────────────────────────┘ 48位虚拟地址 (支持到 57位)
ARM64 内存布局 (48位 VA) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 TTBR0_EL1 (用户空间): ┌─────────────────────────────────────────────────┐ │ 0x0000_0000_0000_0000 - │ │ 0x0000_ffff_ffff_ffff │ │ 用户虚拟地址空间 (256 TB) │ └─────────────────────────────────────────────────┘ TTBR1_EL1 (内核空间): ┌─────────────────────────────────────────────────┐ │ 0xffff_0000_0000_0000 - │ │ 0xffff_ffff_ffff_ffff │ │ 内核虚拟地址空间 (256 TB) │ │ │ │ 包括: │ │ - 直接映射物理内存 │ │ - vmalloc 空间 │ │ - vmemmap (struct page 映射) │ │ - PCI I/O 空间 │ │ - 内核代码/数据 │ └─────────────────────────────────────────────────┘
启动时间线 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 时间轴 (从加电开始): 0ms ┼ 上电, BIOS/UEFI 固件启动 │ - 硬件自检 (POST) │ - 内存检测 │ - 设备枚举 │ 500ms ┼ 引导程序加载 (GRUB/U-Boot) │ - 加载内核镜像 │ - 加载 initrd │ - 传递启动参数 │ 800ms ┼ 内核引导代码执行 │ - header.S / head.S │ - 模式切换 (Real → Protected → Long) │ 1000ms ┼ 内核解压 │ - decompress_kernel() │ 1200ms ┼ 早期内核初始化 │ - startup_64() / __primary_switch() │ - 页表设置 │ - BSS 清零 │ 1500ms ┼ start_kernel() 执行 │ - setup_arch() │ - trap_init() │ - mm_init() │ - sched_init() │ - init_IRQ() │ - console_init() │ 2000ms ┼ initcall 执行 │ - core_initcall │ - postcore_initcall │ - arch_initcall │ - subsys_initcall │ - fs_initcall │ - device_initcall │ - late_initcall │ 3000ms ┼ 用户空间启动 │ - kernel_init() │ - 执行 /sbin/init │ - systemd/SysVinit 启动 │ 5000ms+ ┼ 系统完全可用
现在让我们开始详细探索内核启动的各个阶段。