Linux 启动过程流程图--ARM版

以下是ARM版本Linux启动过程的超详细树状图,涵盖硬件上电到应用程序交互的全流程,并包含关键函数调用链及源码位置,适用于系统开发与调试场景:

ARM Linux启动全流程(含函数调用链)

ARM Linux启动流程(函数级调用链)
│
├─── **1. 硬件上电与Boot ROM阶段**
│   │
│   ├─── 硬件复位与初始化
│   │   ├─── CPU进入Reset异常向量(ARM异常向量表基址0x0或0xffff0000)
│   │   │   └─── 汇编代码:arch/arm/kernel/entry-armv.S:reset_handler
│   │   │
│   │   ├─── 关闭Cache和MMU
│   │   │   ├─── 汇编指令:MCR p15,0,r0,c7,c5,0 ( invalidate icache)
│   │   │   └─── 汇编指令:MRC p15,0,r0,c1,c0,0; BIC r0,r0,#1 ( disable MMU)
│   │   │
│   │   └─── 初始化栈空间(SP指针)
│   │       └─── 汇编代码:设置SVC模式栈,arch/arm/kernel/entry-armv.S
│   │
│   └─── Boot ROM固件(厂商固化,如ARM Trusted Firmware)
│       ├─── 加载Boot Loader到RAM
│       │   ├─── 从启动设备(eMMC/SD卡)读取U-Boot镜像
│       │   └─── 复制镜像到指定内存地址(如0x80000000)
│       │
│       └─── 跳转执行Boot Loader
│           └─── 汇编指令:BX BootLoader入口地址
│
├─── **2. 引导加载程序阶段(以U-Boot为例)**
│   │
│   ├─── Stage 1:汇编初始化(arch/arm/cpu/armv7/start.S)
│   │   ├─── 异常向量表初始化
│   │   │   └─── 定义Reset、Undefined、IRQ等异常处理入口
│   │   │
│   │   ├─── 内存控制器初始化
│   │   │   ├─── 配置DDR时序:arch/arm/cpu/armv7/mx6/sdram.c:mx6_sdram_initialize
│   │   │   └─── 初始化MMU页表(临时)
│   │   │
│   │   ├─── 串口初始化
│   │   │   ├─── 配置UART控制器:drivers/serial/serial.c:serial_initialize
│   │   │   └─── 设置波特率、数据位等参数
│   │   │
│   │   └─── 加载Stage 2到RAM
│   │       ├─── 从Flash/SD卡读取U-Boot第二阶段镜像
│   │       └─── 跳转执行:ldr pc, =stage2_entry
│   │
│   ├─── Stage 2:C代码初始化(lib_arm/board.c:start_armboot)
│   │   ├─── 硬件设备初始化
│   │   │   ├─── 初始化NAND/SD卡:drivers/mtd/nand/nand_base.c:nand_init
│   │   │   ├─── 初始化USB:drivers/usb/usb_main.c:usb_init
│   │   │   └─── 初始化网络:drivers/net/eth.c:eth_initialize
│   │   │
│   │   ├─── 设备树解析
│   │   │   ├─── 读取.dtb文件:drivers/of/fdt.c:fdt_init
│   │   │   └─── 验证设备树:drivers/of/fdt.c:fdt_validate
│   │   │
│   │   ├─── 加载Linux内核
│   │   │   ├─── 从存储设备读取内核镜像:common/cmd_load.c:do_load
│   │   │   └─── 解压缩内核(如zImage):lib/decompress.c:decompress
│   │   │
│   │   ├─── 传递启动参数
│   │   │   ├─── 构建cmdline:board/arm/yourboard/yourboard.c:setup_args
│   │   │   └─── 设置启动参数地址:arch/arm/lib/bootm.c:do_bootm_linux
│   │   │
│   │   └─── 跳转启动内核
│   │       └─── 汇编调用:arm/linux/bootm.c:bootm_linux
│   │
│   └─── 关键函数调用链
│       ├─── start_armboot()
│       │   ├─── board_init()
│       │   ├─── device_tree_init()
│       │   ├─── load_kernel_image()
│       │   └─── bootm_linux()
│
├─── **3. 内核初始化阶段(kernel_init)**
│   │
│   ├─── 内核解压缩与架构初始化(arch/arm/kernel/head.S)
│   │   ├─── 解压缩内核镜像(如zImage)
│   │   │   └─── 汇编解压缩代码:arch/arm/boot/compressed/head.S
│   │   │
│   │   ├─── ARM架构初始化
│   │   │   ├─── 配置页表:arch/arm/mm/proc-v7.S:create_page_tables
│   │   │   ├─── 启用MMU:arch/arm/mm/proc-v7.S:enable_mmu
│   │   │   ├─── 初始化GIC中断控制器:drivers/interrupts/gic.c:gic_init
│   │   │   └─── 多核启动:arch/arm/kernel/smp.c:smp_init
│   │   │
│   │   └─── 跳转到C语言入口:start_kernel()
│   │       └─── 定义于init/main.c:start_kernel
│   │
│   ├─── 内核C语言初始化(init/main.c:start_kernel)
│   │   ├─── 调度器初始化:sched_init()
│   │   │   └─── kernel/sched/core.c:sched_init
│   │   │
│   │   ├─── 内存管理初始化:mm_init()
│   │   │   ├─── 伙伴系统初始化:mm/page_alloc.c:page_alloc_init
│   │   │   ├─── slab分配器初始化:mm/slab.c:kmem_cache_init
│   │   │   └─── 高端内存映射:mm/highmem.c:highmem_init
│   │   │
│   │   ├─── 设备模型初始化:device_tree_init()
│   │   │   ├─── 解析设备树:drivers/of/fdt.c:of_platform_default_populate
│   │   │   ├─── 注册平台总线:drivers/base/platform.c:platform_bus_init
│   │   │   └─── 匹配设备与驱动:drivers/base/dd.c:driver_probe_device
│   │   │
│   │   ├─── 驱动子系统初始化:drivers_init()
│   │   │   ├─── 初始化PCI/USB总线:drivers/pci/pci.c:pci_subsystem_init
│   │   │   ├─── 注册字符设备驱动:drivers/char/char_dev.c:register_chrdev
│   │   │   └─── 初始化块设备:drivers/block/genhd.c:block_device_init
│   │   │
│   │   ├─── 文件系统初始化:filesystem_init()
│   │   │   ├─── 注册ext4文件系统:fs/ext4/ext4_init
│   │   │   ├─── 挂载rootfs:fs/namespace.c:mount_root
│   │   │   │   ├─── 解析root=参数:fs/cmdline.c:parse_cmdline
│   │   │   │   └─── 调用具体文件系统mount函数
│   │   │   └─── 初始化tmpfs:fs/tmpfs/inode.c:tmpfs_init
│   │   │
│   │   ├─── 网络子系统初始化:net_init()
│   │   │   ├─── 初始化TCP/IP协议栈:net/ipv4/af_inet.c:inet_init
│   │   │   ├─── 注册网络设备:drivers/net/ethernet/ethernet.c:register_netdevice
│   │   │   └─── 配置DHCP:net/ipv4/dhcpcd.c:dhcpcd_init
│   │   │
│   │   └─── 启动init进程:kernel_thread(init_post, NULL, CLONE_FS)
│   │       └─── init_post()定义于init/main.c
│   │
│   └─── 设备驱动加载流程(以GPIO驱动为例)
│       ├─── 设备树匹配:of_device_match_table
│       │   └─── drivers/gpio/gpiolib-of.c:of_gpiochip_add
│       │
│       ├─── 驱动注册:platform_driver_register()
│       │   └─── drivers/base/platform.c:platform_driver_register
│       │
│       ├─── 设备探测:driver_probe_device()
│       │   └─── drivers/base/dd.c:driver_probe_device
│       │
│       └─── 硬件操作函数:gpio_request(), gpio_set_value()
│           ├─── drivers/gpio/gpiolib.c:gpio_request
│           └─── drivers/gpio/gpiolib.c:gpio_set_value
│
├─── **4. 用户空间启动阶段(systemd流程)**
│   │
│   ├─── init进程启动(PID=1,init/main.c:init_post)
│   │   ├─── 解析启动参数,确定init程序(如/systemd)
│   │   ├─── 挂载系统文件系统:
│   │   │   ├─── mount -t proc proc /proc
│   │   │   ├─── mount -t sysfs sysfs /sys
│   │   │   └─── mount -t devtmpfs devtmpfs /dev
│   │   │
│   │   └─── 执行init程序:do_execve()
│   │       └─── 系统调用:kernel/sys.c:sys_execve
│   │
│   ├─── systemd主流程(src/core/main.c:main)
│   │   ├─── 解析命令行参数:parse_arguments()
│   │   ├─── 初始化日志系统:log_init()
│   │   ├─── 加载单元配置:load_unit_files()
│   │   │   ├─── 解析.target文件:src/core/unit.c:unit_load
│   │   │   └─── 构建依赖图:src/core/dependency.c:resolve_dependencies
│   │   │
│   │   ├─── 启动基本系统服务:
│   │   │   ├─── systemd-udevd.service:src/udev/udevd.c:main
│   │   │   ├─── systemd-journald.service:src/journal/journald.c:main
│   │   │   └─── systemd-networkd.service:src/network/networkd.c:main
│   │   │
│   │   ├─── 激活默认目标(如multi-user.target)
│   │   │   ├─── 解析.target依赖:src/core/unit.c:unit_activate
│   │   │   ├─── 并行启动服务:src/core/job.c:job_execute
│   │   │   └─── 等待服务就绪:src/core/manager.c:manager_wait_for_dependencies
│   │   │
│   │   └─── 启动登录服务:
│   │       ├─── getty@.service:src/login/getty.c:main
│   │       └─── lightdm.service(图形界面):src/lightdm/lightdm.c:main
│   │
│   └─── 函数调用链示例(启动网络服务)
│       ├─── systemd_main()
│       │   ├─── manager_load_unit()
│       │   ├─── unit_activate()
│       │   ├─── job_queue()
│       │   └─── exec_service() → 调用networkctl启动网络
│
└─── **5. 应用程序与系统交互(函数级)**│├─── 终端交互(Shell命令执行)│   ├─── 用户输入命令(如ls)│   │   └─── shell解析:bash/src/eval.c:eval_command│   ││   ├─── 执行程序:fork() + execve()│   │   ├─── fork系统调用:kernel/fork.c:do_fork│   │   └─── execve系统调用:kernel/exec.c:do_execve│   ││   └─── 程序运行:libc函数 → 系统调用│       ├─── printf() → write() → sys_write│       └─── open() → sys_open(定义于arch/arm/kernel/sys_arm.c)│├─── 设备访问流程(以串口为例)│   ├─── 打开设备:fd = open("/dev/ttyAMA0", O_RDWR)│   │   └─── 系统调用:fs/open.c:do_sys_open│   ││   ├─── 配置参数:ioctl(fd, TCSETS, &termios)│   │   └─── 驱动处理:drivers/tty/serial/8250/8250.c:serial8250_ioctl│   ││   └─── 读写数据:read(fd, buf, len) / write(fd, buf, len)│       ├─── 系统调用:fs/read_write.c:vfs_read/vfs_write│       └─── 驱动处理:drivers/tty/serial/8250/8250.c:serial8250_read/serial8250_write│├─── 网络应用交互(Socket编程)│   ├─── 创建Socket:sock = socket(AF_INET, SOCK_STREAM, 0)│   │   └─── 系统调用:net/socket.c:sys_socket│   ││   ├─── 绑定地址:bind(sock, &addr, len)│   │   └─── 系统调用:net/ipv4/af_inet.c:inet_bind│   ││   ├─── 监听连接:listen(sock, backlog)│   │   └─── 系统调用:net/core/sock.c:sys_listen│   ││   └─── 数据收发:send(sock, data, len, 0) / recv(...)│       ├─── 系统调用:net/core/sock.c:sys_sendto/sys_recvfrom│       └─── 协议处理:net/ipv4/tcp.c:tcp_sendmsg/tcp_recvmsg│└─── 系统调用在内核中的处理(以ARM为例)├─── 用户态陷入内核:SWI指令或SVC指令(ARMv8)│   └─── 异常向量:arch/arm/kernel/entry-armv.S:svc_entry│├─── 系统调用分发:│   ├─── 解析SWI号:arch/arm/kernel/call-sysv.S:sys_call│   └─── 查找系统调用表:arch/arm/kernel/sys_arm.c:sys_call_table│└─── 具体系统调用处理:├─── 如sys_open:fs/open.c:do_sys_open└─── 如sys_write:fs/read_write.c:sys_write

关键技术点与源码映射

1. ARM启动阶段的函数调用核心
  • 异常向量处理:ARMv7的Reset异常处理在arch/arm/kernel/entry-armv.S中,通过reset_handler函数完成底层初始化。
  • U-Boot Stage1:汇编代码位于arch/arm/cpu/armv7/start.S,核心函数start_armboot是Stage2的入口。
  • 内核架构初始化arch/arm/kernel/head.S中的__create_page_tables__enable_mmu是MMU启用的关键函数。
2. 设备驱动加载的函数链
  • 设备树解析drivers/of/fdt.c中的of_platform_default_populate会遍历设备树节点,为每个节点匹配驱动。
  • 驱动注册与探测platform_driver_register注册驱动时,会调用driver_probe_device,该函数会触发驱动的probe函数(如gpiochip_probe)。
3. systemd启动的关键函数
  • 单元加载src/core/unit.c中的unit_load负责解析.service.target文件,构建依赖关系。
  • 并行启动src/core/job.c中的job_execute实现服务的并行启动,通过fork()exec()执行具体服务程序。
4. 系统调用在ARM上的实现
  • 异常机制:ARM通过SWI(ARMv7)或SVC(ARMv8)指令从用户态陷入内核,异常处理入口在arch/arm/kernel/entry-armv.S
  • 调用表映射:系统调用号通过arch/arm/kernel/sys_arm.c中的sys_call_table映射到具体处理函数,如sys_open对应do_sys_open

典型ARM平台启动差异(函数级)

平台关键函数差异
树莓派(RPi)额外固件层函数:bootcode.bin调用start.elf中的initialize_platform(),再加载U-Boot。
ARM64(AArch64)启动流程使用arch/arm64/kernel/head.S,MMU配置函数为__enable_mmu,支持4级页表。
嵌入式设备可能自定义启动函数,如直接从NOR Flash加载内核,使用load_elf_image()替代U-Boot的do_bootm

通过以上树状图,可清晰看到从硬件上电到应用程序的每一层函数调用关系,尤其适合系统开发人员调试启动问题、优化启动时间或开发定制化启动流程。如需进一步分析某模块的函数调用细节(如GIC中断初始化、USB驱动探测流程),可提供具体方向进行深入展开。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/912834.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/912834.shtml

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

相关文章

NVMe高速传输之摆脱XDMA设计6之系统架构设计

结合目前应用需求,以及前面基础分析,确定IP应具有如下特色: (1) 通用性 前端数据采集系统基于 FPGA 开发。 一方面, 设备类型多, 使用的 FPGA型号各不相同, 需要实现的设计能够在多种…

Mac homebrew 安装教程

下载github安装包 https://github.com/Homebrew/brew/releases/tag/4.5.8 下载安装后 打开 安全里面允许安装,就可以直接使用了

stm32hal模块驱动(1)hpdl1414驱动

之前一直想用hpdl1414画一块手表,前面pcb测试板画完没空调试,最近刚好空出来时间,遂发下驱动。 这里简单赘述hpdl1414的驱动原理:D0-D6负责数据输入(ascii表后7位),A0,A1负责更改hpdl1414模块显…

从代码学习深度强化学习 - TRPO PyTorch版

文章目录 前言核心工具函数广义优势估计 (Generalized Advantage Estimation, GAE)案例一:TRPO 解决离散动作问题 (CartPole-v1)1. 环境初始化2. 网络结构定义3. TRPO 智能体实现4. 训练与可视化5. 训练主程序与结果案例二:TRPO 解决连续动作问题 (Pendulum-v1)1. 环境与工具…

MySQL 升级到8.4版本的详细指南

本指南详细介绍了将 MySQL 升级到 8.4 版本的完整流程、注意事项和操作方法。 一、升级前准备 (3.1 Before You Begin) 在开始升级之前,必须仔细审阅本节信息并执行所有推荐的操作: 理解升级过程:了解升级期间可能发生的情况。请参阅第 3.4…

leetcode427.建立四叉树

区间x0到x1和区间y0到y1都是左闭右开的 解题基本思路是先判断当前矩阵是不是全0或全1,如果是就直接返回新建的一个节点值(矩阵的统一值,叶子节点),如果不是那就新建一个节点值,非叶并且左上右上左下右下四个方向上递归创建节点 /…

医学+AI教育实践!南医大探索数据挖掘人才培养,清华指导发布AI教育白皮书

教育数字化浪潮正以前所未有的力度重塑高等教育格局。今年4月,为贯彻落实《教育强国建设规划纲要(2024—2035 年)》,教育部等九部门印发《关于加快推进教育数字化的意见》,表明将持续推动“人工智能教育”全方位发展&a…

PDF处理控件Spire.PDF系列教程:如何使用C# 拆分 PDF 文件(完整指南)

PDF文件因其高度的跨平台兼容性和安全稳定的格式特点,广泛应用于企业文档管理和电子资料传输中。随着PDF文档页数和内容复杂度的增加,拆分PDF成为优化文档处理流程、提升办公效率的重要需求。通过编程方式实现PDF拆分,不仅能自动化处理海量文…

文心4.5开源模型部署实践

文心4.5开源模型部署实践 使用fastdeploy本地部署 执行命令: python -m fastdeploy.entrypoints.openai.api_server \--model baidu/ERNIE-4.5-21B-A3B-Paddle \--port 8180 \--metrics-port 8181 \--engine-worker-queue-port 8182 \--max-model-len 32768 \--m…

Python迭代器、生成器、闭包和装饰器(三器一包)

return、continue、break区别: return只能用在函数里面,表示从函数中返回,函数体内的后续任何代码都不执行continue只是跳出当前循环,进入下一循环break只是跳出全部循环,如果循环后面还有代码,会进行执行…

【Java】Maven

一.Maven简介 Maven的产生主要是为了解决Java项目中的两个问题: 1.依赖管理: 传统 Java 项目在引入第三方库时,需要手动下载 JAR 包并维护复杂的依赖关系。Maven 提供了统一的依赖管理机制,通过简单的配置即可自动从仓库下载并引…

人脸活体识别3:C/C++实现人脸眨眼 张嘴 点头 摇头识别(可实时检测)

人脸活体识别3:C/C实现人脸眨眼 张嘴 点头 摇头识别(可实时检测) 目录 人脸活体识别3:C/C实现人脸眨眼 张嘴 点头 摇头识别(可实时检测) 1. 前言 2.人脸活体识别方法 (1)基于人脸动作的检测​​ (2)​…

【ABAP】 从无到有 新建一个Webdynpro程序

、新建WDA 可从SE80在web dynpro 组件下 创建 并按例以下操作 2、插入窗口 3、相关功能 3-1、展示消息 DATA:lo_api_controller TYPE REF TO if_wd_controller,lo_message_handler TYPE REF TO if_wd_message_manager.lo_api_controller ? wd_this->wd_get_api( ).lo_mess…

ALV常用设置(更新中一)

之前设置了checkbox,但是触发不了单击事件,且alv自带的复选,鼠标移动单击别处就会自动取消。 **增加多选框到fieldcat,**这一点很重要,然后设置 IF gs_fcat-fieldname sel.gs_fcat-checkbox X. gs_fcat-edit X. …

NumPy 或 PyTorch/TensorFlow 中的张量理解

(2, 2, 3) 形状的 3D 数组(或张量)的结构。 个人理解: 2个2维数组(张量),2维数组(张量)里面有2个1维向量(张量),1维向量(张量&#x…

Linux环境下使用 C++ 与 OpenCV 实现 ONNX 分类模型推理

实验环境:Ubuntu 20.0 推理模型:ONNX分类模型 1. 安装依赖项 首先是需要安装依赖库,如g,cmake等,如果已经安装的话可以忽略 sudo apt install -y g sudo apt install -y cmake sudo apt install -y make sudo apt i…

AJAX 安装使用教程

一、AJAX 简介 AJAX(Asynchronous JavaScript and XML)是一种在无需重新加载整个网页的情况下,能够与服务器交换数据并更新部分网页内容的技术。它不是一种新语言,而是使用现有的标准组合:JavaScript XMLHttpRequest…

【牛客算法】牛客网编程题解:小红拼图

一、题目介绍 1.1. 题目链接 :小红拼图 https://www.nowcoder.com/questionTerminal/08b54686f0d14bd784d9d148c68a268a 1.2 题目介绍 小红正在玩一个拼图游戏,她有一些完全相同的拼图组件: 小红准备用这些组件来拼成一些图案。这些组件可…

买卖股票的最佳时机--js 算法

一、买卖股票的最佳时机 给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。返回你可以从这笔交易中获取的最大利润。…

C#基础(WndProc)

WndProc 是操作系统与你的程序“对话”的通道​​。当用户点击鼠标、按下键盘,或系统事件(如窗口移动)发生时,Windows 会将这些事件打包成“消息”,发送给你的窗口,而 WndProc 就是接收和处理这些消息的函数…