ARM64 Linux 6.10内核启动流程2-rootfs 怎么挂上

§1.1 rootfs 怎么挂上

平台:QEMU virt + ARM64。当前命令:

bash 复制代码
qemu-system-aarch64 \
  -M virt \
  -cpu cortex-a57 \
  -m 1024 \
  -kernel linux-6.10/arch/arm64/boot/Image \
  -initrd initramfs.cpio.gz \
  -nographic \
  -append "console=ttyAMA0 nokaslr" \
  -s -S

0. 这条命令和根有关的部分

QEMU 和根的关系
-initrd initramfs.cpio.gz cpio initramfs ,解进已经存在的内存 /。不是 root=/dev/ram,不是 Root_RAM0
-append "console=ttyAMA0 nokaslr" 没有 root=saved_root_name 为空
包里的 /init busybox 脚本,最后 exec /bin/sh。有它就不会进 prepare_namespace
sh 复制代码
#!/bin/busybox sh
/bin/busybox --install -s /bin
mount -t proc proc /proc
mount -t sysfs sys /sys
exec /bin/sh

1. 在 main.c 里和挂根相关的挂钩

内核一开始 没有磁盘 /。先有一个空的内存根,再决定要不要切成真根。

复制代码
start_kernel
  vfs_caches_init → mnt_init
       init_rootfs()              // do_mounts.c:tmpfs 还是 ramfs
       init_mount_tree()          // 空的 "/" 挂上          【会走】

kernel_init → kernel_init_freeable
  populate_rootfs(initramfs.c)  // 异步把 cpio 解进 "/"
  wait_for_initramfs()            // 等解压完;不是 do_mounts 入口
  console_on_rootfs()
  if (init_eaccess("/init") != 0)
      prepare_namespace()         // do_mounts.c 主戏      【本套不走】
  kernel_execve("/init" 或 /sbin/init)

wait_for_initramfs()init/initramfs.c,只等 cpio 铺完。

do_mounts.c 读挂真根,入口是 prepare_namespace() ,不是 wait_for_initramfs


2. 核心抽象(读 prepare_namespace 盯这三句)

  1. / 可以换 :启动用空 rootfs 当容器;真根先挂到 /root,再 MS_MOVE + chroot 换成 /。这是挂载命名空间,不是驱动总线。
  2. 根由 cmdline 策略选定root= / rootfstype= / ro/rw / rootdelay / rootwait。硬件只是被查表。
  3. 挂根是消费者:块设备由 probe 异步造出;挂之前必须等「这一波 probe」结束。

3. 路 A ------ 你现在:initramfs 铺进空根(不切根)

复制代码
空的内存 /(init_rootfs + init_mount_tree)
    → rootfs_initcall(populate_rootfs)
        unpack_to_rootfs(cpio)          // init/initramfs.c
    → wait_for_initramfs()
    → init_eaccess("/init") 成功
    → 跳过 prepare_namespace / mount_root
    → kernel_execve("/init") → exec /bin/sh

/ 从头到尾就是那块内存盘:先空,再被 initramfs.cpio.gz 填上 busybox。没有第二块盘。

不是 Root_RAM0 那个是 root=/dev/ramparse_root_device() 返回的老式 ramdisk 块设备。你没有 root=,也进不了 parse_root_device


4. 路 B ------ BSP 常卡:prepare_namespace 切真根

仅当 没有可 exec 的 /init 时:

c 复制代码
ramdisk_execute_command = NULL;
prepare_namespace();

流水线:

复制代码
rootdelay                         给慢速 USB/MMC 多等几秒
  → wait_for_device_probe()       等已经触发的 probe / deferred / async
  → md_run_setup()
  → parse_root_device(root=)      填 ROOT_DEV;找不到则为 0
  → initrd_load()                 老式块设备 initrd;cpio 路径通常 false
  → rootwait                      ROOT_DEV==0 时轮询设备出现
  → mount_root(saved_root_name)   真根挂到 /root(还不是 /)
  → devtmpfs_mount
  → MS_MOVE + chroot              「/」换身份

mount_root()ROOT_DEV 分发:NFS / CIFS / mtd·ubi / 普通块设备。

块设备:mknod /dev/rootdo_mount_root(..., "/root")

源 = root= 那个设备;目标 = 空 rootfs 里的 /root;fstype = rootfstype= 或逐个试。

之后 MS_MOVE 才把这棵子树变成 /

你这条命令 没有 root=、有 /init,整段 B 不执行。

以后真板要复现:加盘 + root=/dev/vda,并且让 /init 不存在(或 rdinit= 指到无效路径)。

和 probe 的关系(栅栏,不是本条主模型)

wait_for_device_probe()drivers/base/dd.c)只保证「已经排队/正在跑的 probe」结束,不管以后还会不会有新设备。

  1. flush_work(deferred_probe_work) --- -EPROBE_DEFER 那一轮
  2. wait_event(probe_waitqueue, probe_count==0) --- PID 1 睡在这里,schedule()wait.h
  3. async_synchronize_full() --- 异步 probe

叫醒:driver_probe_device() 里每次 probe 结束 probe_count-- + wake_up_all

设备和驱动谁后上总线,谁触发这次 probe(device_adddriver_register)。匹配算法属 §1.2。


5. 按你这条命令:会走 / 不走

步骤 走?
init_rootfs / 空 /
populate_rootfs 解 cpio
wait_for_initramfs
prepare_namespace / mount_root / parse_root_device 不走
execve("/init")exec /bin/sh

gdb:断 prepare_namespace / mount_root 不该命中。看根相关断 populate_rootfsunpack_to_rootfskernel_execve


相关推荐
2301_815091011 小时前
TCP 并发服务器模型:4 种 IO 模型完整梳理
服务器·网络·tcp/ip
捷瑞电子工坊1 小时前
Ubuntu 终端指令速查手册(持续更新)
linux·ubuntu·教程·开发工具·命令行·速查手册·终端指令
雯宝1 小时前
6. USB 转串口驱动
linux
斑马1391 小时前
Linux软件编程学习笔记(十二)——TCP并发服务器模型
java·服务器·网络
rest10241 小时前
对jemalloc的理解
linux
小小尚@1 小时前
WebGIS/ECharts 地图开发|MapLand 在线行政区划边界一键下载 GeoJSON 工具
前端·javascript·echarts
发光的沙子2 小时前
嵌入式系统架构师----Ubuntu如何安装不在列表内的软件?
linux·运维·ubuntu
C+ 安口木2 小时前
Alibaba Cloud Linux 3 服务器环境搭建实战记录
linux·运维·服务器
聚搜云——JuSouClouD2 小时前
杭州腾讯云代理商:腾讯云2核4G服务器够用吗?网站、API和开发测试怎么选
服务器·云计算·腾讯云