嵌入式Linux内核启动过程详解(第二阶段:C语言部分)

目录

概述

1 启动内核第二阶段流程图

2 嵌入式Linux内核启动分析(C语言部分)

2.1 start_kernel()函数

2.2 rest_init()函数

2.3 kernel_init()函数

2.4 kernel_init_freeable()函数


概述

本文主要介绍linux内核启动(内核版本: linux4.1.15)第二部分的相关内容,第一部分主要是运行在汇编语言代码,其为C语言内核部分的运行创造环境。本文以start_kernel为起始函数,介绍其内部实现的功能,并对该函数内部调用的重要接口做了详细的介绍。

源代码下载地址:

【免费】NXP官方原版Uboot和Linux资源-CSDN文库

1 启动内核第二阶段流程图

第二阶段主要完成初始化内核启动的全部工作,包括外围硬件的启动,创建第一个工作进程:init进程、初始化控制台、加载rootfs文件系统等。该阶段的执行流程如下:

                                                             流程图一

                                                                 流程图二

2 嵌入式Linux内核启动分析(C语言部分)

第二阶段是以执行main.c文件中的start_kernel()函数开始的,下面分析start_kernel()调用函数所实现的功能。

该文件在内核中的位置:init/main.c

2.1 start_kernel()函数

在执行 arch/arm/kernel/head-common.S文件中的__mmap_switched函数之后,内核跳到C语言部分运行。在软件项目中,一个项目的入口文件为main.c,对Linux内核也不例外,该文件位于:

/init/main.c

打开该文件,在代码:492行,找到这个函数。下面分段阅读函数实现的功能

代码 501 行: 初始化 lockdep 是死锁检测模块 ,作用是跟踪每个锁的自身状态和各个锁之间的依赖关系,经过规则验证来保证依赖的关系正确。

代码 502 行: 设置任务栈结束魔术数 , 用于栈溢出检测

代码 503 行: 启动SMP 有关(多核处理器),设置处理器 ID。

代码 504行: 初始化和debug相关的代码

代码 509 行: 栈溢出检测初始化

代码 511 行: cgroup 初始化, cgroup 用于控制 Linux 系统资源

代码 513 行: 关闭当前 CPU 中断

代码 514 行:boot中断disable标志量配置为true,此时boot相关的中断也不会开启

代码 520 行: 跟 CPU 有关的初始化

代码 521 行:页地址相关的初始化

代码 523 行:架构相关的初始化,此函数会解析传递进来的ATAGS 或者设备树(DTB)文件。会根据设备树里面的 model 和 compatible 这两个属性值来查找Linux 是否支持这个单板。此函数也会获取设备树中 chosen 节点下的 bootargs 属性值来得到命令行参数,也就是 uboot 中的 bootargs 环境变量的值,获取到的命令行参数会保存到command_line 中。

代码 524 行:内存有关的初始化

代码 525 行:存储命令行参数

代码 526 行:如果只是 SMP(多核 CPU)的话,此函数用于获取 CPU 核心数量, CPU 数量保存在变量

代码 527 行: 在 SMP 系统中有用,设置每个 CPU 的 per-cpu 数据

代码 528 行:准备 SMP 系统下的数据,以填充CPU的寄存器

代码 530行:建立系统内存页区(zone)链表

代码 531行:处理用于热插拔 CPU 的页

代码 534行:解析命令行中的 console 参数

代码 549行:设置 log 使用的缓冲区

代码 550行:构建 PID 哈希表, Linux 中每个进程都有一个 ID, 这个 ID 叫做 PID。通过构建哈希表可以快速搜索进程 信息结构体。

代码 551行:预先初始化 vfs(虚拟文件系统)的目录项和索引节点缓存

代码 552行:定义内核异常列表

代码 553行:完成对系统保留中断向量的初始化

代码 554行:内存管理初始化

代码 561行:初始化调度器,主要是初始化一些结构体

代码 566行:关闭优先级抢占

代码 567行:检查中断是否关闭,如果没有的话就关闭中断

代码 570行:IDR 初始化, IDR 是 Linux 内核的整数管理机制,也就是将一个整数 ID 与一个指针关联起来。

代码 574行: 跟踪调试相关初始化

代码 576行: 上下文跟踪调试相关初始化

代码 577行:基数树相关数据结构初始化

代码 579行:初始中断相关初始化,主要是注册 irq_desc 结构体变量,因为 Linux 内核使用 irq_desc 来描述一个中断。

代码 580行:中断初始化

代码 581行:tick 初始化

代码 583行:初始化定时器

代码 584行:初始化高精度定时器

代码 585行:软中断初始化

代码 587行:初始化系统时间

代码 594行: 使能中断

代码 603行:控制台初始化

代码 608行: 如果定义了宏 CONFIG_LOCKDEP,那么此函数打印一些信息

代码 615行:锁自测

代码 628行: kmemleak 初始化, kmemleak 用于检查内存泄漏

代码 629行:启动CPU 内存页配置

代码 634行: 测定 BogoMIPS 值,可以通过 BogoMIPS 来判断 CPU 的性能,BogoMIPS 设置越大,说明 CPU 性能越好。

代码 635行:PID 位图初始化

代码 636行:生成 anon_vma slab 缓存

代码 647行:为对象的赋予资格(凭证)

代码 648行:初始化一些结构体以使用 fork 函数

代码 649行:给各种资源管理结构分配缓存

代码 650行:初始化缓冲缓存

代码 651行:初始化密钥

代码 652行:安全相关初始化

代码 654行:为 VFS 创建缓存

代码 655行:初始化信号

代码 657行:页回写初始化

代码 660行:初始化 cpuset, cpuset 是将 CPU 和内存资源以逻辑性和层次性集成的一种机制,是 cgroup 使用的子系统之一

代码 661行:初始化 cgroup

代码 662行:进程状态初始化

代码 665行: 检查写缓冲一致性

代码 678行: 调用rest_init() 函数,系统正常启动起来了

2.2 rest_init()函数

代码 387行: 调用函数 rcu_scheduler_starting,启动 RCU 锁调度器

代码 394行: 调用函数 kernel_thread 创建 kernel_init 进程,也就是 init 内核进程。 init 进程的 PID 为 1。 init 进程一开始是内核进程(也就是运行在内核态),后面 init 进程会在根文件系统中查找名为“init”这个程序,这个“init”程序处于用户态,通过运行这个“init”程序, init 进程就会实现从内核态到用户态的转变。

代码 396行:调用函数 kernel_thread 创建 kthreadd 内核进程,此内核进程的 PID 为 2。 kthreadd 进程负责所有内核进程的调度和管理。

代码 409行: 调用函数 cpu_startup_entry 来进入 idle 进程, cpu_startup_entry 会调用 cpu_idle_loop, cpu_idle_loop 是个 while 循环,也就是 idle 进程代码。

2.3 kernel_init()函数

代码 932行: kernel_init_freeable 函数用于完成 init 进程的一些其他初始化工作

代码 943行: 如果存在“/init”程序的话就通过函数 run_init_process 来运行此程序。

代码 946行: 如果 ramdisk_execute_command 为空的话就看 execute_command 是否为空,反正不管如何一定要在根文件系统中找到一个可运行的 init 程序。 execute_command 的值是通过uboot 传递,在 bootargs 中使用“init=xxxx”就可以了,比如“init=/linuxrc”表示根文件系统中的 linuxrc 就是要执行的用户空间 init 程序。

代码 963~966 行,如果 ramdisk_execute_command 和 execute_command 都为空,那么就依次查找“/sbin/init”、“/etc/init”、“/bin/init”和“/bin/sh”,这四个相当于备用 init 程序,如果这四个也不存在,那么 Linux 启动失败!

2.4 kernel_init_freeable()函数

代码 1002行: do_basic_setup 函数用于完成 Linux 下设备驱动初始化工作!非常重要。do_basic_setup 会调用 driver_init 函数完成 Linux 下驱动模型子系统的初始化

代码 1005行: 打开设备“/dev/console”,在 Linux 中一切皆为文件!因此“/dev/console”也是一个文件,此文件为控制台设备。每个文件都有一个文件描述符,此处打开的“/dev/console”文件描述符为 0,作为标准输入(0)。

代码 1008 和 1009 行: sys_dup 函数将标准输入(0)的文件描述符复制了 2 次,一个作为标准输出(1),一个作为标准错误(2)。这样标准输入、输出、错误都是/dev/console 了。 console 通过uboot 的 bootargs 环境变量设置,“console=ttymxc0,115200”表示将/dev/ttymxc0 设置为 console,也就是 I.MX6U 的串口 1。当然,也可以设置其他的设备为 console,比如虚拟控制台 tty1,设置 tty1 为 console 就可以在 LCD 屏幕上看到系统的提示信息。

代码 1020 行:调用函数 prepare_namespace 来挂载根文件系统。 根文件系统也是由命令行参数指定的,就是 uboot 的 bootargs 环境变量。比如“root=/dev/mmcblk1p2 rootwait rw”就表示根文件系统在/dev/mmcblk1p2 中,也就是 EMMC 的分区 2 中。

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

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

相关文章

FPGA学习_时序分析

文章目录 前言一、组合逻辑与时序逻辑二、建立时间和保持时间三、建立时间和保持时间 前言 心中有电路,下笔自然神!!! 一、组合逻辑与时序逻辑 组合逻辑:没有时钟控制的数字电路,代码里的判断逻辑都是组…

先进电机技术 —— 何为轴电压?

一、特定场景举例 长线驱动指的是在电动机与变频器之间存在较长的连接电缆,尤其是在大型工业应用中,电机可能远离变频器几十米甚至上百米。这种情况下,变频器通过长线向电动机传输功率时,可能会加剧电机轴电压和轴电流的产生&…

《明日边缘2》AI制作电影宣传片

《明日边缘2》AI制作电影宣传片 In the dawn of a new war, the cycle of death and rebirth begins. 在新战争的曙光中,生死轮回的循环悄然开启。 Each repetition brings a new horror, but also a chance for redemption. 每一次循环都带来新的恐怖,却…

第六十二回 宋江兵打大名城 关胜议取梁山泊-飞桨ONNX推理部署初探

石秀和卢俊义在城内走投无路,又被抓住。梁中书把他两个人押入死牢。蔡福把他俩关在一处,好酒好菜照顾着,没让两人吃苦。 第二天就接到城外梁山泊的帖子,说大军已经来到,要替天行道,让他放人,并…

jupyter notebook使用教程

首先是打开jupyter notebook 下载安装好之后,直接在命令行中输入‘jupyter notebook’即可跳转到对应页面 还可以进入想要打开的文件夹,然后再文件夹中打开中断,执行‘jupyter notebook’命令,就能够打开对应文件界面的jupyter …

2024年超声波清洗机品牌哪家好?实力担当超声波清洗机大集合

随着佩戴眼镜人群越来越多,眼镜清洗的需求也是越来越大了!也许有人佩戴了十几年眼镜都不知道超声波清洗机是要清洗的,也许有人一开始就注重眼镜的清洗。其实眼镜清洗是一件很简单的事情,可以用超声波清洗机来清洗眼镜。目前超声波…

短视频矩阵系统---php7.40版本升级自研

短视频矩阵系统---php7.40版本升级自研 1.部署及搭建 相对于其他系统,该系统得开发及部署难度主要在各平台官方应用权限的申请上,据小编了解,目前抖音短视频平台部分权限内侧名额已满,巧妇难为无米之炊,在做相关程序…

在SAP S4 OP中使用SAP API Hub 的API

参考资料:https://blog.51cto.com/u_11984354/4907646 NO.21-SAP S4 HANA Cloud API接口测试(1)-CSDN博客

基于springboot的“漫画之家”系统

目录 背景 技术简介 系统简介 界面浏览 背景 随着科技的不断进步,计算机已经变成了人们日常生活和工作不可或缺的工具。在这样的环境下,互联网技术被广泛运用于各个领域,以提升工作和生活的效率,推动了网络信息技术的迅猛发展…

Java多线程实战-CompletableFuture异步编程优化查询接口响应速度

🏷️个人主页:牵着猫散步的鼠鼠 🏷️系列专栏:Java全栈-专栏 🏷️本系列源码仓库:多线程并发编程学习的多个代码片段(github) 🏷️个人学习笔记,若有缺误,欢迎评论区指正…

C语言——程序拷贝文件

问题如下: 写一个程序拷贝文件: 使用所学文件操作,在当前目录下放一个文件data.txt,写一个程序,将data.txt文件拷贝一份,生成data_copy.txt文件。 基本思路: 打开文件data.txt,读…

SG5032VAN差分晶振X1G004261001100专用于5G通讯设备

差分晶体振荡器(DXO)是目前行业中公认高技术,高要求的一款晶体振荡器,是指输出差分信号使用2种相位彼此完全相反的信号,从而消除了共模噪声,并产生一个更高性能的系统。差分晶振一般为六脚贴片晶振,输出类型分为好几种,LVDS,LV-PE…

力扣面试150 阶乘后的零 数论 找规律 质因数

Problem: 172. 阶乘后的零 思路 👨‍🏫 大佬神解 一个数末尾有多少个 0 ,取决于这个数 有多少个因子 10而 10 可以分解出质因子 2 和 5而在阶乘种,2 的倍数会比 5 的倍数多,换而言之,每一个 5 都会找到一…

Linux初学(八)磁盘管理

一、磁盘管理 1.1 简介 磁盘的工作原理: 添加磁盘对磁盘进行分区格式化磁盘挂载和使用磁盘 磁盘的类型: 固态机械 磁盘的接口类型: IDESTSTSCSI 磁盘工作的原理: 磁盘,特别是硬盘,和内存不同,…

目标检测——PP-YOLO算法解读

PP-YOLO系列,均是基于百度自研PaddlePaddle深度学习框架发布的算法,2020年基于YOLOv3改进发布PP-YOLO,2021年发布PP-YOLOv2和移动端检测算法PP-PicoDet,2022年发布PP-YOLOE和PP-YOLOE-R。由于均是一个系列,所以放一起解…

【JavaEE初阶系列】——带你了解volatile关键字以及wait()和notify()两方法背后的原理

目录 🚩volatile关键字 🎈volatile 不保证原子性 🎈synchronized 也能保证内存可见性 🎈Volatile与Synchronized比较 🚩wait和notify 🎈wait()方法 💻wait(参数)方法 🎈noti…

【单元测试】一文读懂java单元测试

目录 1. 什么是单元测试2. 为什么要单元测试3. 单元测试框架 - JUnit3.1 JUnit 简介3.2 JUnit 内容3.3 JUnit 使用3.3.1 Controller 层单元测试3.3.2 Service 层单元测试3.3.3 Dao 层单元测试3.3.4 异常测试3.3.5 测试套件测多个类3.3.6 idea 中查看单元测试覆盖率3.3.7 JUnit …

第28章 ansible的使用

第28章 ansible的使用 本章主要介绍在 RHEL8 中如何安装 ansible 及 ansible的基本使用。 ◆ ansible 是如何工作的 ◆ 在RHEL8 中安装ansible ◆ 编写 ansible.cfg 和清单文件 ◆ ansible 的基本用法 文章目录 第28章 ansible的使用28.1 安装ansible28.2 编写ansible.cfg和清…

HDFS集群环境配置

环境如下三台服务器: 192.168.32.101 node1192.168.32.102 node2192.168.32.103 node3 一、Hadoop安装包下载,点此官网下载 二、Hadoop HDFS的角色包含: NameNode,主节点管理者DataNode,从节点工作者SecondaryNameN…

React Native: could not connect to development server

问题: 运行模拟器错误:无法连接到开发服务器 原因分析: 1、确认模拟器连接状态,是连接成功的 查看进程的端口占用,也没问题 lsof -i tcp:8081 kill pid2、检查包服务器是否运行正常 连接真机进行调试发现真机是正常…