当前位置: 首页 > news >正文

linux 启动流程?

linux 启动流程

CPU 上电后最先执行的启动代码,通常确实是放在 arch 目录下对应架构的启动文件里。这是因为启动代码强相关于 CPU 架构和硬件细节,不同架构差异非常大。


具体说明

1. 为什么启动代码放在 arch 目录?

  • 启动代码要设置 CPU 状态(如寄存器、MMU、异常向量表等)。
  • 各架构 CPU 启动流程不一样,汇编语言代码也差别大。
  • 所以放在 arch/架构名/boot/ 或类似目录,便于管理。

2. 以常见架构为例

架构启动代码位置示例说明
x86arch/x86/boot/包含 real mode 到 protected mode 切换等代码
ARMarch/arm/boot/包含内核入口汇编、initrd搬移等代码
ARM64arch/arm64/kernel/head.S64位 ARM 启动汇编代码
MIPSarch/mips/kernel/MIPS 启动相关代码

3. 启动流程简述

  • CPU 上电后,会跳转到一个固定的物理地址(Reset Vector)。
  • 该地址对应的代码就是架构相关的启动代码,一般就是 arch/.../boot/... 里的汇编。
  • 启动代码初始化最基本的硬件,设置内存和CPU状态。
  • 然后跳转进入 C 语言编写的内核入口函数 start_kernel()

总结

  • CPU 上电后的第一段执行代码一定是架构相关的启动代码,放在 arch 目录下。
  • 这是因为启动时的硬件初始化和上下文设置紧密依赖 CPU 架构。
  • 通用内核代码则放在 kernel/mm/fs/ 等目录。

核心原因是内核启动前后环境差异巨大,必须用汇编代码做早期硬件和处理器环境初始化,才能安全可靠地进入 start_kernel

Linux 内核源码里的 arch/ 目录是 不同 CPU 架构相关代码的汇总目录


具体解释

1. Linux 内核支持多种 CPU 架构

  • 比如 x86、ARM、MIPS、PowerPC、RISC-V 等。
  • 每种架构底层硬件接口和启动流程差别很大。
  • 因此,内核源码会根据架构分目录管理。

2. arch/ 目录的作用

  • arch/ 目录下每个子目录对应一个 CPU 架构,比如:
arch/├── x86/      # x86 架构相关代码├── arm/      # 32位 ARM 架构代码├── arm64/    # 64位 ARM 架构代码├── mips/     # MIPS 架构代码├── riscv/    # RISC-V 架构代码...
  • 每个目录里包含启动汇编、CPU相关驱动、体系结构专属的调度、内存管理、异常处理等代码。
  • 其他跟架构无关的内核通用代码则在 kernel/mm/fs/ 等目录。

详细解释

1. CPU 上电后环境非常“原始”

  • CPU 刚上电时,只处于物理地址模式,没有开启分页(虚拟内存)
  • 寄存器值不确定
  • 堆栈、内存布局未初始化
  • 特权级和CPU模式尚未设置

此时无法直接跳转执行复杂的C代码,因为C代码依赖于正确的栈、数据段和运行环境。


2. 汇编入口(_start)做的事情

汇编代码位于内核最开始的入口,做以下关键工作:

  • 设置 CPU 特权级(例如切换到内核态)
  • 配置段寄存器、堆栈指针
  • 设置分页机制(启用虚拟内存)
  • 清理未初始化的BSS段
  • 设置全局指针、数据指针等CPU寄存器
  • 关闭中断或做其他硬件相关初始化

这些操作都只能用汇编完成,因为C环境尚未准备好。


3. start_kernel 的前提

start_kernel() 是用 C 语言写的,它假设运行环境已经稳定

  • 栈已初始化
  • 全局变量可以正常访问
  • CPU 处于正确模式
  • 内存管理子系统已部分就绪

换句话说,start_kernel 是“内核的真正入口”,但不是“CPU的入口”。


4. 总结

阶段作用为什么不能直接跳到 start_kernel
CPU 上电 → _start 汇编初始化 CPU 寄存器、栈、分页、特权级需要底层硬件初始化,C代码依赖这些,直接跳C会崩溃
_startstart_kernel进入内核 C 语言环境,启动内核子系统需要完整运行环境,汇编做的准备工作必须先完成

简单比喻

汇编入口相当于“内核启动的引导员”,负责把环境布置好;
start_kernel 是“内核真正的司机”,环境准备好了才上车启动。


好的,讲讲 secondary_start_kernel 的作用和背景。


什么是 secondary_start_kernel

  • 它是 Linux 内核在多核(SMP)系统中,非主CPU(Secondary CPU) 启动时的入口函数。
  • 主CPU(CPU0)执行 start_kernel 来启动整个系统和初始化多核环境。
  • 其他CPU启动后,会跳到 secondary_start_kernel,完成自己的初始化流程。

为什么需要 secondary_start_kernel

  • 多核CPU启动时,只有主核(CPU0)从复位向量启动,执行完整的内核启动流程。
  • 其他核处于停顿状态,需要被唤醒,并单独执行一套简化的初始化。
  • 这些核不会执行 start_kernel,而是执行 secondary_start_kernel,完成自己的CPU初始化和进入调度。

secondary_start_kernel 主要做什么?

  • 初始化该CPU的本地数据结构(如CPU寄存器、TSS、IDT等)
  • 设置该CPU的中断和调度环境
  • 把该CPU加入到内核的调度器中,开始运行任务
  • 不重复执行主核完成的系统全局初始化

简单流程示意

主核 (CPU0) 启动 -> 执行 start_kernel -> 初始化系统 -> 唤醒其他核
其他核 (CPU1..N) 启动 -> 执行 secondary_start_kernel -> 初始化本地CPU环境 -> 进入调度循环

位置与调用

  • secondary_start_kernel 通常定义在 init/main.c
  • 各架构启动汇编在唤醒其他CPU时会跳转到这个函数
  • 是 SMP 初始化的关键环节

总结

函数名作用适用CPU
start_kernel主核启动,系统初始化CPU0(主CPU)
secondary_start_kernel非主核启动,局部CPU初始化和进入调度其他CPU(辅助CPU)

好的,下面详细介绍 initrd 在 ARM 和 x86 Linux 内核启动流程中的具体实现细节,帮助你理解它是怎么工作的。


一、initrd 的启动流程核心概念

  • initrd 是内核启动时内存中的一个临时根文件系统映像。
  • 内核启动时先挂载它作为根文件系统,执行初始化工作,之后切换到真实根文件系统。
  • 在启动参数中通过内核命令行参数或 bootloader 传递 initrd 的位置和大小。

二、x86 启动流程中的 initrd

1. Bootloader 阶段

  • Bootloader(如 GRUB)加载内核镜像 vmlinuz 和 initrd 镜像到内存。
  • 将 initrd 起始地址和大小放入内核启动参数(例如内核命令行中的 initrd=0x地址,大小)。
  • 将控制权交给内核。

2. 内核启动汇编阶段

  • arch/x86/boot/header.S 等文件,内核启动汇编代码初始化后,会调用内核的 C 入口 start_kernel()
  • 内核解析启动参数,获得 initrd 地址和大小。

3. 内核 C 语言初始化阶段(init/do_mounts.c

  • 内核根据启动参数调用 setup_initrd()(2.6 内核及类似版本)。
  • setup_initrd() 负责把 initrd 映像注册为临时块设备(ramdisk),并挂载为根文件系统(initrd rootfs)。
  • 调用 initrd 内部的 /init 程序进行系统初始化。

4. 切换到真实根文件系统

  • 初始化完成后,pivot_root()switch_root() 将根文件系统切换到硬盘或其他设备的文件系统。
  • initrd 被卸载,内核开始正常运行用户空间系统。

三、ARM 启动流程中的 initrd

1. Bootloader 阶段

  • Bootloader(如 U-Boot)将内核镜像(zImage/uImage)和 initrd 加载到内存。

  • U-Boot 通过寄存器(如 r0-r3)传递内核启动参数:

    • r2 寄存器通常保存 initrd 的起始地址。
    • r3 寄存器保存 initrd 大小。
  • 设备树(DTB)也可能携带 initrd 信息。

2. ARM 汇编入口阶段 (arch/arm/boot/bootp/init.S 等)

  • 内核启动汇编代码读取这些参数,做内存搬移(前面你看过的 init.S 代码就是搬移 initrd 的例子)。
  • 将 initrd 拷贝到合适内存区域,确保后续内核使用。

3. 内核 C 入口 (start_kernel)

  • 解析传入的 initrd 地址和大小,调用 setup_initrd()
  • initrd 作为临时根文件系统挂载。
  • 执行 initrd 内部初始化脚本。

4. 切换根文件系统

  • 跟 x86 类似,切换到真实根文件系统,完成启动。

四、内核中与 initrd 相关的关键函数

  • setup_arch():在架构相关初始化时调用,解析启动参数,设置 initrd 信息。
  • setup_initrd():注册并挂载 initrd,准备临时根文件系统。
  • mount_root():挂载根文件系统时优先使用 initrd,后续切换根。
  • pivot_root() / switch_root():实现根文件系统的切换。

五、简要总结流程图

Bootloader 加载内核和 initrd --> 内核启动汇编(解析initrd参数,搬移initrd) --> start_kernel(调用setup_initrd,挂载initrd) --> 执行initrd内的/init程序初始化 --> 切换到真实根文件系统(硬盘/网络文件系统等)

六、相关文件位置(Linux 源码)

功能典型源码路径
ARM 启动汇编arch/arm/boot/bootp/init.S
x86 启动汇编arch/x86/boot/header.S
initrd 处理init/do_mounts.cinit/do_mounts.h
根文件系统挂载fs/namespace.c

当然可以,下面是将你提供的 Linux 启动流程(包括 Bootloader、主核、从核、initrd、根文件系统切换等)融合成的一个 Mermaid 序列图


✅ Mermaid 序列图(Linux 多核启动流程 + initrd 启动)

Bootloader主核(CPU0)其他核(CPU1..N)Linux 内核initrd(临时根文件系统)真实根文件系统上电,跳转内核入口(arch/.../head.S)执行 start_kernel()初始化内核子系统(时钟、中断、内存、调度器等)唤醒其他核(SMP)执行 secondary_start_kernel()初始化 CPU 本地环境,进入 idle/sched 循环解析内核参数,包括 initrd调用 setup_initrd()解压并挂载 initrd执行 initrd 中的 /init 程序完成系统初始化逻辑(例如挂载 dev tmpfs)切换到真实根文件系统(硬盘/网络等)执行 /sbin/init(或 systemd)系统启动完成,进入用户空间Bootloader主核(CPU0)其他核(CPU1..N)Linux 内核initrd(临时根文件系统)真实根文件系统

📌 说明

  • CPU0 是主核,从入口跳入 start_kernel,控制整个启动过程。
  • CPU1..N 是从核,由主核在适当时机唤醒,执行 secondary_start_kernel
  • Bootloader 通常负责将内核、initrd 以及设备树加载到内存,并设置参数。
  • initrd 是临时根文件系统,内核通过参数挂载它,并执行其中的 /init
  • /init 会负责进一步初始化和挂载真实根文件系统(如 ext4、NFS 等)。
  • 最终系统进入真实根文件系统的 /sbin/init,开始正常运行。

http://www.dtcms.com/a/311676.html

相关文章:

  • C++刷题 - 7.27
  • 深度学习-模型初始化与模型构造
  • 元宇宙重构未来交通新图景
  • 对过去一年毕业求职季的简单复盘
  • Gossip 协议
  • 锁相关(AI回答)
  • LeetCode Hot 100:3. 无重复字符的最长子串
  • 学习日志25 python
  • Vue3核心语法基础
  • FFmpeg+javacpp中纯音频播放
  • yolo 、Pytorch (5)IOU
  • 衡石科技实时指标引擎解析:如何实现毫秒级响应万亿级数据的增量计算?
  • 防御综合实验
  • TypeScript03-web项目知识
  • Python正则表达式使用指南:从基础到实战
  • 【C语言】内存函数与数据在内存中的存储
  • 自动驾驶中的传感器技术15——Camera(6)
  • 【数据结构初阶】--排序(二)--直接选择排序,堆排序
  • 内核协议栈源码阅读(三) --- 网桥处理
  • 每日五个pyecharts可视化图表-bars(1)
  • AG32mcu通过寄存器方式操作cpld
  • linux ssh公钥移除办法
  • K8S部署ELK(三):部署Elasticsearch搜索引擎
  • accept函数及示例
  • CMake指令:mark_as_advanced
  • Django 日志配置详解
  • gbase8s 常见表约束介绍
  • 数字化转型驱动中小制造企业的质量管理升级
  • 技术面试知识点详解 - 从电路到编程的全栈面经
  • 【密码学】5. 公钥密码