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.pswp.cn/diannao/94031.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/94031.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

《Kubernetes部署篇:基于Kylin V10+ARM64架构CPU使用containerd部署K8S 1.33.3集群(多主多从)》

总结:整理不易,如果对你有帮助,可否点赞关注一下? 更多详细内容请参考:企业级K8s集群运维实战 一、架构图 如下图所示: 二、环境信息 基于x86_64+aarch64架构使用containerd部署K8S 1.33.3集群资源合集(三主多从) 2、部署规划 云平台 主机名 K8S版本 系统版本 CPU架构…

Docker 镜像打包为 ZIP 文件便于分享和转发

网上找到的记录一下方便下次看步骤详解1. 将镜像导出为 TAR 文件Docker 提供了 docker save 命令,可以将镜像导出为 .tar 文件。使用以下命令:docker save -o dify.tar dify说明:docker save:导出镜像为文件。-o dify.tar&#xf…

一对一交友小程序 / APP 系统架构分析

一对一交友小程序 / APP 系统架构分析一、引言在数字化社交的大背景下,一对一交友小程序和 APP 为人们拓展社交圈提供了便捷途径。合理且高效的系统架构是保障此类应用稳定运行、提升用户体验的基石。本文将深入剖析一对一交友小程序 / APP 的系统架构,涵…

Anthropic最新研究Persona vector人格向量

今天本来就想更一期强化学习,但是突然看了Anthropic的persona vector,所以又来写这一篇,因为我觉得这个很有价值以往我们玩LLM比较怕的事就事他乱说话作为概率模型,它能说对,它也能乱编,乱编轻症就是所谓的…

Spring AI集成Elasticsearch向量检索时filter过滤失效问题排查与解决方案

使用vectorStore.similaritySearch遇到问题 最近需要做一个功能,用到了es做向量数据库。在使用vectorStore.similaritySearch查询的时候,发现filterExpression中加的条件并没有完全生效,导致查询出来的数据不准确,出现了不符合me…

安灯系统(Andon System)

安灯系统是源自丰田生产系统(TPS)的一种可视化生产管理工具,其名称"Andon"来自日语的"提灯",原指用于报警的灯笼,现已成为制造业现场管理的核心工具之一。一、安灯系统的定义安灯系统是一种实时监控生产异常的可视化管理…

MyBatis与MySQL

要理解 MyBatis 语法及其与 MySQL 的区别,首先需要明确两者的本质定位:MyBatis 是 Java 的持久层框架(负责 Java 对象与数据库数据的映射),而MySQL 是关系型数据库管理系统(负责数据的存储和 SQL 执行&…

Vulnhub Noob靶机复现(附提权)

一、安装靶机 下载地址:https://download.vulnhub.com/noob/Noob.ova 下载好后使用VM打开配置如下。 二、主机发现 使用nmap扫描确认靶机ip(192.168.29.138) nmap -sn 192.168.29.1/24 三、端口扫描 使用nmap工具扫描全部端口以防遗漏。 nmap -A -p- 192.168.…

文心4.5开源测评:国产大模型的轻量化革命与全栈突破

> 当算力成本成为AI落地的最大拦路虎,一款仅需2.1GB显存、支持32K上下文的轻量级大模型如何撬动产业智能化的大门? ^ - ^ 2025年6月30日,百度正式开源文心大模型4.5系列,以**10款全维度模型矩阵**(0.3B至424B参数)刷新国产开源模型的技术边界。这不仅是参数规模的跃进…

【自存用】mumu模拟器+mitmproxy配置

一、 安装证书 下载mitmproxy进行安装。cmd 输入 mitmdump产生证书在C:\Users\账号名.mitmproxy找到mitmproxy-ca.p12,双击进入证书导入向导,一直点下一页,直到选择证书存储的地方选择【受信任的根证书颁发机构】,后面的继续点【是】或【完成…

Java中的字符串 - String 类

在C语言中若要表示字符串只能使用字符数组或者字符指针,Java语言则专门提供了 String 类,在面向对象编程中具有重要地位。在开发和校招笔试中,字符串也是常客。 目录 一、字符串的构造 二、常用方法 2.1 字符串的拼接 2.2 字符串之间的比…

[网安工具] Web 漏洞扫描工具 —— AWVS · 使用手册

🌟想了解其它网安工具?看看这个:[网安工具] 网络安全工具管理 —— 工具仓库 管理手册 Acunetix | Web Application Security ScannerAcunetix is an end-to-end web security scanner that offers a 360 view of an organization’s securi…

丑数-优先队列/三指针/动态规划

丑数 Solution 核心思路&#xff1a; 注意的几个点&#xff1a; 1.优先队列改变排序&#xff1a; priority_queue<int,vector<int>,greater<int>> q;2.用来判断是否访问过&#xff0c;可以用unordered_set 注意set的插入用的是insert而不是push unorder…

FPGA(或者数字电路)中组合逻辑和时序逻辑是怎么划分的

1.组合逻辑 在FPGA中&#xff0c;组合逻辑是哪些没有触发器作为存储单元的电路 LUT查找表就是组合逻辑电路&#xff0c;无时钟信号参与。 加法器&#xff0c;逻辑门&#xff0c;多路选择器&#xff0c;译码器2.时序逻辑电路 输出依赖于当前输入&#xff0c;还依赖于过去 触发器…

【音视频】WebRTC 中的RTP、RTCP、SDP、Candidate

一、RTP 1.1 RTP协议介绍 在 WebRTC 中&#xff0c;RTP&#xff08;Real-time Transport Protocol&#xff0c;实时传输协议&#xff09;是音视频媒体数据传输的核心协议&#xff0c;负责实时数据的封装、传输与解封装&#xff0c;为实时交互提供时序、同步、分片重组等关键能…

accept函数及示例

这次我们介绍 accept 函数&#xff0c;它是 TCP 服务器用来接受客户端连接请求的核心系统调用。1. 函数介绍 accept 是一个 Linux 系统调用&#xff0c;专门用于TCP 服务器&#xff08;使用 SOCK_STREAM 套接字&#xff09;。它的主要功能是从监听套接字&#xff08;通过 liste…

【Java】在一个前台界面中动态展示多个数据表的字段及数据

企业的生产环境中&#xff0c;如果不允许直接操作数据表中的数据&#xff0c;则需要开发一个前台界面&#xff0c;在必要时实现对多个数据表中数据的增删改查&#xff0c; 此时就需要后端将Oracle表字段及数据查询返回前端动态展示…… 一、Oracle特定元数据查询 使用JDBC获取O…

MySQL(174)如何理解MySQL的多版本并发控制(MVCC)?

MySQL的多版本并发控制&#xff08;MVCC, Multi-Version Concurrency Control&#xff09;是一种用于实现高并发性的机制&#xff0c;它允许多个事务同时读取和写入数据&#xff0c;而不会相互阻塞。MVCC主要在InnoDB存储引擎中实现&#xff0c;通过维护数据的多个版本来实现一…

Docker--将非root用户添加docker用户组,解决频繁sudo执行输入密码的问题

一、为什么要有docker用户组&#xff1f; 根本原因&#xff1a; Linux的设备访问权限控制机制 Docker守护进程&#xff08;dockerd&#xff09;运行时会创建一个特殊的Unix套接字文件&#xff0c;如&#xff1a;/var/run/docker.sock。 这个文件就像一个“门”&#xff0c;所有…

C语言---函数的递归与迭代

递归的理解与限制条件 所谓函数递归就是递推加回归的过程&#xff0c;就是函数自己调用自己。递归的思想就是把复杂的问题拆分成与原来那个大问题相似的子问题来求解&#xff0c;大事化小&#xff0c;像剥洋葱一样&#xff0c;最终把问题解决。 递归的限制条件&#xff1a; 一个…