Linux内核分析之基础知识-0

韩乔落

前言

推荐学习顺序: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+wsl2Mac的配置和Linux大同小异。qemuwindwos的安装包,也可以使用windowsqemu,即WSL2+WINDOWS。这一部分内容可以参考我之前写的Pwn_kernel的内核模块开发部分。需要注意的是WindwosqemuLinuxqemu在启动命令上是有些不同的,linux的一些指令和功能特性是Windows不支持的。也可以选择在wsl2中编译qemu。建议使用Linuxqemu,功能更为完善强大。

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)"
# zsh-syntax-highlighting
git clone https://github.com/zsh-users/zsh-syntax-highlighting.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting
# zsh-autosuggestions
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
# 基本C库开发包
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

# Python相关(QEMU构建系统需要)
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
# SDL支持(图形界面)
sudo apt install libsdl2-dev libsdl2-image-dev

# GTK支持
sudo apt install libgtk-3-dev

# VNC支持
sudo apt install libvncserver-dev

# Spice支持(高级图形)
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
# KVM支持
sudo apt install libvirt-dev

# USB支持
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

# RDMA支持
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
# ARM EABI 工具链
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
# ARM EABIHF 工具链
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
# AArch64 工具链
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
# RISC-V 64位工具链
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
# 需要安装这几个库,riscv32库还需手动安装
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

# 下面的库除了mips和ppc可能会用到,其他架构我们暂且用不到。
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
# ...... 还有很多其他的库可以通过 apt search 查看,这里就不列举了

由于是做相关项目,我们将相关的交叉编译工具链单独放在了项目文件夹里。大家可以通过绝对路径来引用,当然你也可以将其添加到你的环境变量上。我们使用的是glibcelf,也就是使用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

# Python相关(QEMU构建系统需要)
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
# 兼容 version 5 (可选)
# sudo ln -s /usr/lib/x86_64-linux-gnu/libncurses.so.6.4 /usr/lib/x86_64-linux-gnu/libncurses.so.5
# sudo ln -s /usr/lib/x86_64-linux-gnu/libtinfo.so.6.4 /usr/lib/x86_64-linux-gnu/libtinfo.so.5

sudo apt install -y devscripts config-package-dev debhelper-compat golang

# 音频相关 jackd2 -> choose NO
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

# 安装 VDE 网络支持
sudo apt install -y libvdeplug-dev

# SDL支持(图形界面)
sudo apt install libsdl2-dev libsdl2-image-dev -y

# GTK支持
sudo apt install libgtk-3-dev -y

# VNC支持
sudo apt install libvncserver-dev -y

# Spice支持(高级图形)
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

# KVM支持
sudo apt install libvirt-dev -y

# USB支持
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

# RDMA支持
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
# virt-make-fs 工具(可选)
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
# ......还有很多其他的库可以通过 apt search 查看,这里就不列举了

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 defconfig

# 编译
make bzImage -j$(nproc)

# 安装模块 (可选)
sudo make modules_install

# 安装内核 (可选)
sudo make install

清华源

  1. 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. 保存并重新编译

1
make bzImage -j$(nproc)
  1. make bzImage -j4

注意事项:

注意 gcc 版本问题,4.*一般用 gcc-55.*一般用 gcc-7

gcc多版本共存请参考这里

  1. 编译成功后

我们一般主要关注于如下的文件

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.binvmlinux
  • 路径: arch/mips/boot/vmlinux.bin
  • 说明: MIPS架构通常使用vmlinux.bin,某些情况下也会有压缩版本

PowerPC

  • 镜像名: zImageuImage
  • 路径: arch/powerpc/boot/zImage
  • 说明: PowerPC使用zImage(压缩镜像)或uImage(U-Boot格式)

ARM32

  • 镜像名: zImageuImage
  • 路径: arch/arm/boot/zImage
  • 说明: 32位ARM使用压缩的zImage格式

SPARC

  • 镜像名: zImagevmlinux
  • 路径: arch/sparc/boot/zImage

Alpha

  • 镜像名: vmlinux
  • 路径: vmlinux

查看所有可用的镜像目标

你可以通过以下命令查看特定架构支持的所有镜像格式:

1
2
3
4
5
# 查看当前架构支持的镜像目标
make help | grep -A 10 "Architecture specific targets"

# 或者查看make的所有目标
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
# RISC-V
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

# x86_64
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

# ARM64
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

# ARM
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

# MIPS
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 
➜ busybox-1.36.1 mkdir -p ./build/x86_64

# 选择 Settings -> Build Options -> Build static binary
# 然后配置安装目录
➜ busybox-1.36.1 make menuconfig

# 编译
➜ busybox-1.36.1 make -j$(nproc)

# 安装
➜ busybox-1.36.1 make install

image-20250716170229338

如果你的内核版本大于6.8.0编译可能会报错:https://lists.busybox.net/pipermail/busybox-cvs/2024-January/041752.html

只需要把tc.c移除或者禁用即可。

1
2
3
make menuconfig
# 然后在菜单中:
# Networking Utilities -> tc (traffic control utility) [取消选择]

或者使用 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
# 下载QEMU源码后
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编译

  1. 查看可用的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.
  1. 使用QEMU ARM64配置作为基础
1
➜  buildroot-2025.02.4 make qemu_aarch64_virt_defconfig
  1. 运行配置界面进行定制
1
2
3
4
5
6
➜  buildroot-2025.02.4 make menuconfig
# 根据需要定制即可
kernel->
# 编译Linux kernel 5.15.185 6.12.33 两个版本。
filesystem->
# 打开cpio支持
  1. 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
# From https://www.kernel.org/pub/linux/kernel/v6.x/sha256sums.asc
sha256 c0a575630f2603a20bb0641f8df8f955e46c9d7ac1fae8b54b21316e6b52a254 linux-6.12.33.tar.xz
sha256 0d79ff359635e9f009f1e330deed5f3aefd8c452b80660bffdc504b877797719 linux-6.6.93.tar.xz
sha256 bc3c45faf6f5f0450666c75fa9dad9bc7c0cf7c7cba0dbd94e5cfdc58229c116 linux-6.1.141.tar.xz
# From https://www.kernel.org/pub/linux/kernel/v5.x/sha256sums.asc
sha256 3d03eb798910f32929f7fda5a56e4bb1a121f10bde320d6f3063639c009313dc linux-5.15.185.tar.xz
sha256 07c852940dc2dc03fe84f7fcf697648d7cba11c62d20504380492ba07aa46bb6 linux-5.10.238.tar.xz
sha256 c879d0ba817aaa0fde318d58d7e1f141d9c29bd8569a96b73159ebc448077b99 linux-5.4.294.tar.xz
# Locally computed
sha256 fb0edc3c18e47d2b6974cb0880a0afb5c3fa08f50ee87dfdf24349405ea5f8ae linux-cip-5.10.162-cip24.tar.gz
sha256 b5539243f187e3d478d76d44ae13aab83952c94b885ad889df6fa9997e16a441 linux-cip-5.10.162-cip24-rt10.tar.gz

# Licenses hashes
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

  1. 首先在busybox文件夹创建一些系统文件:
1
mkdir -p lib tmp proc sys dev etc/init.d
  1. (可选)然后编写一个内核模块(感兴趣看内核开发部分,或者可以从Pwn_kernel的内核模块开发部分简单了解),将其放在/lib/目录中。

  2. 编写一个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 # 0 代表 root权限, 普权限设置为1000
poweroff -f
  1. 打包文件系统:
1
find . | cpio -o -H newc > ../rootfs.cpio
  1. 将编译好的/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 # 开启gdb调试,默认1234端口,用于调试内核

windwos pwsh 启动脚本。

1
2
3
4
5
6
7
8
9
qemu-system-x86_64.exe `
-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 # 开启gdb调试,默认1234端口,用于调试内核

可以使用-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=<网络标识>

关键参数说明

  1. -netdev user
    启用用户模式网络栈(无需 root 权限),支持端口转发。

  2. id=<网络标识>
    自定义网络设备标识(如 net0),用于关联后续 -device

  3. hostfwd=<规则>

    端口转发规则,格式:

    1
    协议:宿主机IP:宿主机端口-虚拟机IP:虚拟机端口
    • 协议:tcpudp
    • IP 省略时默认绑定 0.0.0.0(any)
  4. -device <网卡驱动>
    指定虚拟网卡类型(如 virtio-net-pci)。

调试工具

multiarch-gdbserver-static:调试内部程序用的静态编译的gdbserver

image-20250717185418550

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 内核的基础。通过学习启动流程,你将:

  1. 理解系统底层工作原理 - 从硬件加电到用户空间进程的完整过程
  2. 掌握架构特定知识 - x86_64 和 ARM64 的底层差异与共性
  3. 提升调试能力 - 能够诊断早期启动问题
  4. 为内核开发打下基础 - 无论是驱动开发还是内核开发

本书的组织结构

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
/* arch/x86/include/uapi/asm/bootparam.h */
struct boot_params {
struct setup_header hdr; // 0x000: 启动头部
struct screen_info screen_info; // 0x020: 屏幕信息
struct apm_bios_info apm_bios_info; // 0x040: APM 信息
u8 _pad2[4]; // 0x054
struct sys_desc_table sys_desc_table; // 0x058: 系统描述表
struct olpc_ofw_header olpc_ofw_header; // 0x070: OLPC 信息
u32 ext_ramdisk_image; // 0x080: 扩展 ramdisk 指针
u32 ext_ramdisk_size; // 0x084: 扩展 ramdisk 大小
u32 ext_cmd_line_ptr; // 0x088: 扩展命令行指针
u8 _pad3[116]; // 0x08c: 保留
struct e820_entry e820_map[E820_MAX_ENTRIES_ZEROPAGE]; // 0x0d0: E820 内存映射
u8 _pad4[48]; // 0x1e0: 保留
struct edd_info eddbuf[EDDMAXNR]; // 0x1e8: EDD 信息
u8 _pad5[276]; // 0x2d0: 保留
struct efi_info efi_info; // 0x3c0: EFI 信息
u32 alt_mem_k; // 0x3e0: 备用内存 (KB)
u32 scratch; // 0x3e4: 临时存储
u8 e820_entries; // 0x3e8: e820 条目数
u8 eddbuf_entries; // 0x3e9: EDD 条目数
u8 _pad6[6]; // 0x3ea: 保留
struct setup_data hdr_setup_data; // 0x3f0: setup_data 链表
char cmdline[COMMAND_LINE_SIZE]; // 0x400: 命令行参数
}; // 总大小 4096 字节

ARM64: 设备树 (Device Tree)

1
2
3
4
5
6
7
8
9
10
11
12
13
/* drivers/of/fdt.c */
struct fdt_header {
u32 magic; // 0xd00dfeed
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+ ┼ 系统完全可用

现在让我们开始详细探索内核启动的各个阶段。

  • Title: Linux内核分析之基础知识-0
  • Author: 韩乔落
  • Created at : 2025-07-16 16:19:43
  • Updated at : 2026-01-19 13:40:31
  • Link: https://jelasin.github.io/2025/07/16/Linux内核分析之基础知识-0/
  • License: This work is licensed under CC BY-NC-SA 4.0.
Comments