【内核学习】001编译和运行

compile the kernel

clone和compile在容器中(虚拟机)操作

1
2
3
4
docker run --privileged -d -it --name angel -v `pwd`:/root/code -w /root/code ghcr.io/cybrid-systems/dev
docker exec -it --detach-keys="ctrl-z,z" angel /bin/zsh
git config --global user.name $your_name
git config --global user.email $your_email

clone code

1
2
git clone https://github.com/torvalds/linux.git
cd linux

compile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 1. 生成默认配置
make defconfig

# 2. 启用调试选项
./scripts/config --enable DEBUG_KERNEL
./scripts/config --enable DEBUG_INFO
./scripts/config --enable KGDB
./scripts/config --enable FTRACE
./scripts/config --set-val DEBUG_INFO_DWARF4 y

# 3. 自动处理依赖关系
make olddefconfig

# 4. 可选:检查配置
grep -E "DEBUG_KERNEL|DEBUG_INFO|KGDB|FTRACE" .config

# 5. 编译内核
make CC=clang -j$(nproc)
bear -- make CC=clang LLVM=1 -j$(nproc)
make CC=clang binrpm-pkg LOCALVERSION=-debug -j$(nproc)
  • binrpm-pkg: Builds binary RPMs (kernel image, modules, headers). Use rpm-pkg for both binary and source RPMs.
  • LOCALVERSION=-debug: Appends a custom suffix (e.g., "-debug") to the kernel version for identification in GRUB.
1
2
3
dpkg -i kernel-*.deb
update-grub
reboot

在 Ubuntu 系统上,你可以通过 GRUB 引导菜单 在开机时手动选择要启动的内核(包括你刚编译安装的新内核,如带 -debug 后缀的那个)。这是最简单、最安全的临时/测试方式,不需要修改配置文件。

步骤:开机时选择内核

  1. 重启电脑
    执行 sudo reboot 或正常重启系统。

  2. 进入 GRUB 菜单

    • 在开机过程中(看到紫色/黑色屏幕或厂商 logo 后),立即按住 Shift 键(大多数 BIOS/UEFI 系统适用)。
    • 如果是纯 UEFI 系统且 Shift 不起作用,试试 按住 Esc 键快速连按 Shift
    • 目的是强制显示 GRUB 菜单(默认情况下,如果只有一个内核且超时为 0,它会直接启动而不显示菜单)。
  3. 在 GRUB 菜单中选择内核

    • 你会看到类似这样的主菜单(紫色背景):
      • Ubuntu
      • Advanced options for Ubuntu
      • (可能还有 Windows 或其他系统,如果是双系统)
    • 方向键 ↓ 选中 Advanced options for Ubuntu(Ubuntu 高级选项),按 Enter 进入子菜单。
  4. 在高级选项中挑选内核

    • 子菜单会列出所有已安装的内核版本,例如:
      • Ubuntu, with Linux 6.x.x-debug(你新编译的那个,通常带自定义后缀)
      • Ubuntu, with Linux 6.x.x-generic(旧的或默认的)
      • Ubuntu, with Linux 6.x.x-debug (recovery mode)
    • 方向键 选中你想要的内核(比如新编译的那个),然后按 Enter 启动。
  5. 启动成功后验证
    进入系统后,打开终端运行:

    1
    2
    3
    4
    5
    6
    7
       uname -r
    ```
    输出应该显示你选择的内核版本(例如 `6.x.x-debug`)。

    ### 额外小技巧
    - **临时只下一次启动某个内核**(不改默认):
    在进入系统后运行(替换成你想要的内核名称,从 `/boot/grub/grub.cfg` 中 grep 找):
    sudo grub-reboot "Advanced options for Ubuntu>Ubuntu, with Linux 6.x.x-debug" sudo reboot
    1
    2
    3
    4
      只影响下一次重启,下下次又恢复默认。

    - **如果 GRUB 菜单一直不显示**(超时为 0):
    编辑 `/etc/default/grub`:
    sudo nano /etc/default/grub
    1
    把 `GRUB_TIMEOUT=0` 改成 `GRUB_TIMEOUT=10`(单位:秒),保存后运行:  
    sudo update-grub
    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
      以后开机就会显示菜单 10 秒。

    - **想永久默认新内核**(不再手动选):
    参考之前回复:修改 `/etc/default/grub` 中的 `GRUB_DEFAULT=` 为新内核的完整菜单路径(或编号 0,如果它排第一),然后 `sudo update-grub`。

    这样操作后,你就可以自由测试不同内核了。如果新内核启动失败(比如黑屏、panic),重启再选回旧内核即可,非常安全。需要截图或具体报错也可以继续问!

    ## 使用 BusyBox 创建最小 rootfs 的步骤如下:

    0. gcc 15 fix

    ```bash
    Option 1: Disable the tc Applet (Recommended if You Don't Need It)
    The tc command is for traffic control and may not be essential for your use case. Disabling it avoids the problem without patching code.

    Run make menuconfig (or make config for text-based) in your BusyBox source directory.
    Navigate to Networking Utilities > Disable tc.
    Save and exit.
    Re-run make to build BusyBox.

    Solution: Patch the Detection Script
    Edit scripts/kconfig/lxdialog/check-lxdialog.sh to update the test program for compatibility with modern GCC.

    Open the file:
    nano scripts/kconfig/lxdialog/check-lxdialog.sh (or use your preferred editor).
    Locate the section around lines 49-55 (may vary slightly) that echoes the test code:textecho "#include CURSES_LOC
    main() {}
    EOF
    Change it to:textecho "#include CURSES_LOC
    int main(void) { return 0; }
    EOF
    This adds an explicit int return type and a return statement to satisfy stricter standards.
    Using void for parameters avoids potential implicit declaration issues.

    Save and exit.
    Optionally, clean up:
    make clean
    Retry:
    make menuconfig

    This should now detect ncurses correctly and launch the menuconfig interface.

  6. 下载并编译 BusyBox

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
       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 defconfig
    make menuconfig # 可选:静态编译 Settings → Build static binary (no shared libs)
    # 2. 用 sed 两行命令完成上述两项修改
    sed -i 's/^# CONFIG_STATIC is not set/CONFIG_STATIC=y/' .config
    sed -i 's|CONFIG_PREFIX=.*|CONFIG_PREFIX="./rootfs"|' .config
    # 3. 让 Kbuild 自动补齐依赖(重要!)
    make oldconfig >/dev/null </dev/null
    make -j$(nproc)
    make install

这里回到mac宿主机。

  1. 创建必要的目录结构
1
2
cd rootfs
mkdir -p {etc,dev,proc,sys,tmp,var,usr/bin,usr/sbin,lib,root}
  1. 创建基础设备节点
1
2
3
4
5
6
7
8
cd rootfs/dev

# 创建设备文件
sudo mknod console c 5 1
sudo mknod null c 1 3
sudo mknod zero c 1 5
sudo mknod ttyAMA0 c 204 64
sudo chmod 666 console null zero ttyAMA0
  1. 创建初始化脚本
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
cd rootfs
cat > init << 'EOF'
#!/bin/sh

echo "Starting system..."

# 挂载必要文件系统
mount -t proc proc /proc
mount -t sysfs sysfs /sys
mount -t devtmpfs devtmpfs /dev
mount -t tmpfs tmpfs /tmp

# 设置终端
exec </dev/ttyAMA0 >/dev/ttyAMA0 2>&1

# 设置环境变量
export PATH=/bin:/sbin:/usr/bin:/usr/sbin
export HOME=/root
export USER=root

# 显示系统信息
echo "=== BusyBox Linux ==="
echo "Kernel: $(uname -r)"
echo "System is ready!"

# 启动shell(修复job control)
exec setsid sh -c 'exec sh </dev/ttyAMA0 >/dev/ttyAMA0 2>&1'
EOF
chmod +x init
  1. 创建简单的fstab
1
2
3
4
5
cat > etc/fstab << 'EOF'
proc /proc proc defaults 0 0
sysfs /sys sysfs defaults 0 0
tmpfs /tmp tmpfs defaults 0 0
EOF
  1. 创建rootfs镜像
1
2
3
4
5
6
7
8
9
10
11
12
cd rootfs

# 创建CPIO格式的rootfs(用于initrd)
find . | cpio -H newc -o | gzip > ../rootfs.cpio.gz

# 或者创建ext4文件系统镜像
dd if=/dev/zero of=../rootfs.ext4 bs=1M count=64
mkfs.ext4 ../rootfs.ext4
mkdir -p /mnt/rootfs
sudo mount ../rootfs.ext4 /mnt/rootfs
sudo cp -ra . /mnt/rootfs/
sudo umount /mnt/rootfs
  1. 使用QEMU启动
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    qemu-system-aarch64 \
    -machine virt \
    -cpu cortex-a72 \
    -smp 4 \
    -m 2G \
    -kernel linux/arch/arm64/boot/Image \
    -initrd busybox-1.36.1/rootfs.cpio.gz \
    -append "console=ttyAMA0 rdinit=/init" \
    -nographic \
    -no-reboot