前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >系统启动流程-armV7

系统启动流程-armV7

作者头像
哆哆jarvis
发布于 2022-08-23 06:17:38
发布于 2022-08-23 06:17:38
1.1K0
举报
  • 内核复位后在裸机上运行的代码,即在不使用操作系统的情况下运行的代码。这是首次启动芯片或系统时经常遇到的情况。
  • bootloader如何加载和运行Linux内核。

从裸机启动

芯片复位后,将在异常向量表中复位向量的位置开始执行。复位操作的代码必须做以下事情:

  • 在多核系统中,使非主核进入睡眠状态
  • 初始化异常向量。
  • 初始化内存系统,包括MMU。
  • 初始化核心模式堆栈和寄存器。
  • 初始化任何关键的 I/O 设备。
  • 执行NEON 或VFP 的任何必要初始化。
  • 启用中断。
  • 更改核心模式或状态。
  • 处理安全世界所需的任何设置(参见第 21 章)。
  • 调用main() 应用程序。

GNU 汇编器中的 _start 指令告诉链接器将代码定位在特定地址,并可用于将代码放置在向量表中。初始向量表将位于非易失性存储器中,并且可以包含跳转到自我指令(除了复位向量),因为此时预计不会出现异常。通常,复位向量包含指向 ROM 中引导代码的分支。

ROM 可以别名为异常向量的地址。然后,ROM 写入一些将 RAM 映射到地址 0 的内存重映射外设,并将真正的异常向量表复制到 RAM 中。这意味着处理重新映射的引导代码部分必须与位置无关,因为只能使用 PC 相对寻址。

下一步是设置缓存、MMU 和分支预测器。

MMU TLB 必须无效。分支目标预测器硬件可能不必显式失效,但必须由引导代码启用。此时可以安全地启用分支预测;这将提高性能。

在此之后,您可以创建一些翻译表,如示例 13-4 的示例代码所示。变量 ttb_address 用于表示要用于初始转换表的地址。这必须是一个 16KB 的内存区域(其起始地址与 16KB 边界对齐),此代码可以向其中写入 L1 转换表。

接下来的步骤将取决于系统的确切性质。例如,可能需要对将保存未初始化 C 变量的内存进行零初始化,将其他变量的初始值从 ROM 映像复制到 RAM,并设置应用程序堆栈和堆空间。可能还需要初始化 C 库函数、调用顶级构造函数(用于 C++ 代码)和其他标准嵌入式 C 初始化。

Booting Linux

如果选择了 HIVECS(称为高向量),那么了解内核从复位中出来并在异常基地址 0x00000000 或 0xFFFF0000 处执行其第一条指令会发生什么是很有用的,直到出现 Linux 命令提示符为止。

当内核存在于内存中时,基于 ARM 处理器的系统上的序列类似于台式计算机上可能发生的序列。但是,引导加载过程可能非常不同,因为基于 ARM 处理器的手机或更深入的嵌入式设备可能缺少硬盘驱动器或类似 PC 的 BIOS。

通常,当您打开系统电源时会发生硬件特定的引导代码从闪存或 ROM 运行。此代码初始化系统,包括任何必要的硬件外围代码,然后启动引导加载程序(例如 U-Boot)。这会初始化主内存并将压缩的 Linux 内核映像复制到主内存中(从闪存设备、板上的内存、MMC、主机 PC 或其他地方)。引导加载程序将某些初始化参数传递给内核。然后,Linux 内核会自行解压并初始化其数据结构和运行的用户进程,然后再启动命令 shell 环境。让我们更详细地看看这些过程中的每一个。

Reset handler

通常有少量特定于系统的引导监控代码,用于配置内存控制器并执行其他系统外围设备初始化。它在内存中设置堆栈,通常将自身从 ROM 复制到 RAM,然后更改硬件内存映射,以便 RAM 映射到异常向量地址,而不是 ROM。本质上,此代码独立于要在板上运行的操作系统并执行类似于 PC BIOS 的功能。当它完成执行后,它将调用一个 Linux 引导加载程序,例如 U-Boot。

Bootloader

Linux 需要执行一定数量的代码才能完成重置,以初始化系统。这将执行内核启动所需的基本任务:

  • 初始化内存系统和外围设备。
  • 将内核映像加载到内存中的适当位置(也可能是初始 RAM 磁盘)。
  • 生成要传递给内核的引导参数(包括机器类型)。
  • 为内核设置控制台(视频或串行)。
  • 进入内核。

不同引导加载程序所采取的具体步骤有所不同,因此有关详细信息,请参阅您要使用的引导加载程序的文档。U-Boot 是一个广泛使用的示例,但其他可能的引导加载程序包括 Apex、Blob、Bootldr 和 Redboot。

当引导加载程序启动时,它通常不存在于主存储器中。它必须首先分配堆栈并初始化核心(例如使其缓存无效)并将其自身安装到主内存。它还必须为全局数据和 malloc() 使用分配空间,并将异常向量条目复制到适当的位置。

Initialize memory system

这在很大程度上是一块板或系统特定的代码。Linux 内核不负责系统中 RAM 的配置。它显示了物理内存布局,但没有其他关于内存系统的知识。在许多系统中,可用 RAM 及其位置是固定的,并且引导加载程序任务很简单。在其他系统中,必须编写代码来发现系统中可用的 RAM 量。

Kernel images

构建过程中的内核映像通常以 zImage 格式压缩(可引导内核映像的常规名称)。它的头代码包含一个魔术字,用于验证解压的完整性,加上开始和结束地址。内核代码与位置无关,可以位于内存中的任何位置。按照惯例,它被放置在距离物理 RAM 基数 0x8000 的偏移处。这为放置在 0x100 偏移处的参数块提供了空间(用于转换表等)。

许多系统需要一个初始 RAM 磁盘 (initrd),因为这可以让您拥有一个可用的根文件系统,而无需设置其他驱动程序。引导加载程序可以将初始 ramdisk 映像放入内存,并使用 ATAG_INITRD2(描述压缩 RAM 磁盘映像的物理位置的标签)和 ATAG_RAMDISK 将其位置传递给内核。

引导加载程序通常会在目标中设置一个串行端口,使内核串行驱动程序能够检测该端口并将其用于控制台。在某些系统中,可以将另一个输出设备(例如视频驱动程序)用作控制台。内核命令行参数console=可以用来传递信息。

Kernel parameters using ATAGs

从历史上看,传递给内核的参数是以标记列表的形式,放置在物理 RAM 中,寄存器 R2 保存列表的地址。标签头包含两个 32 位无符号整数,第一个给出标签的字大小,第二个提供标签值(指示标签的类型)。有关可以传递的参数的完整列表,请参阅相应的文档。示例包括描述物理内存映射的 ATAG_MEM 和描述压缩 ramdisk 映像所在位置的 ATAG_INITRD2。引导加载程序还必须提供 ARM Linux 机器类型号 (MACH_TYPE)。这可以是硬编码的值,或者引导代码可以检查可用的硬件并相应地分配一个值。

有一种更灵活或更通用的方法可以使用扁平设备树 (FDT) 传递此信息。

Kernel parameters using Flattened Device Trees

为 PowerPC 内核引入了 Linux 设备树或 FDT 支持,作为 32 位和 64 位内核合并的一部分,通过使用适用于所有 PowerPC 平台、服务器、台式机和嵌入式的开放固件接口来标准化固件接口 . 它已成为 PowerPC、Micro Blaze 和 SPARC 架构的 Linux 内核中使用的配置方法。

设备树是描述硬件配置的数据结构。它包括有关处理器、内存大小和组、中断配置和外围设备的信息。数据结构被组织成一棵树,有一个名为 / 的根节点。除根节点外,每个节点都有一个父节点。每个节点都有一个名称,并且可以有任意数量的子节点。节点还可以包含具有任意数据的命名属性值,它们以键值对表示。

Kernel entry

内核执行必须从处于固定状态的内核开始。bootloader通过直接跳转到它的第一条指令(arch/arm/boot/compressed/head.S中的开始标签)来调用内核映像。必须禁用 MMU 和数据缓存。内核必须处于超级用户模式,并设置 CPSR寄存器的 I 和 F 位(禁用 IRQ 和 FIQ)。R0 必须包含 0,R1 是 MACH_TYPE 值,R2 是标记参数列表的地址。

内核工作的第一步是解压缩它。这是独立于架构的。保存从bootloader传递的参数并启用缓存和MMU。在调用arch/arm/boot/compressed/misc.c 中的decompress_kernel() 之前,会检查解压后的图像是否会覆盖压缩后的图像,清除缓存然后再次禁用。然后支到 arch/arm/kernel/head.S 中的内核启动入口点。

Platform-specific actions

首先使用__lookup_processor_type()检查内核类型,该函数返回一个码,指定它在哪个内核上运行。然后使用函数__lookup_machine_type()来查找机器类型。然后定义一组基本的转换表,映射内核代码。然后初始化缓存和MMU并设置其他控制寄存器。数据段被复制到 RAM 并调用start_kernel()。

Kernel start-up code

原则上,启动顺序的其余部分在任何架构上都是相同的,但实际上某些功能仍然依赖于硬件。

  • 使用 local_irq_disable() 禁用 IRQ 中断,而 lock_kernel() 用于阻止 FIQ 中断中断内核。它初始化tick control、内存系统和特定于体系结构的子系统,并处理bootloader传递的命令行选项。
  • 设置堆栈并初始化 Linux 调度程序。
  • 设置各种内存区域并分配页面。
  • 设置中断和异常表和处理程序,以及 GIC
  • 系统计时器已设置,此时 IRQ 已启用。进行额外的内存系统初始化,然后使用一个名为 BogoMips 的值来校准核心时钟速度。
  • 设置内核的内部组件,包括文件系统和初始化进程,然后是创建内核线程的线程守护进程。
  • 内核解锁(启用 FIQ)并启动调度程序
  • 调用函数 do_basic_setup() 来初始化驱动程序、sysctl、工作队列和网络套接字。此时,执行到用户模式的切换。

内核虚拟内存映射图

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-02-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 哆哆jarvis 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
赶紧收藏!u-boot代码分析与移植
BootLoader的目标是正确调用内核的执行,由于大部分的BootLoader都依赖于CPU的体系结构。因此大部分的BootLoader都分为两个步骤启动。依赖于CPU体系结构(如设备初始化等)的代码都放在stage1。而stage2一般使用C语言实现,能够实现更加复杂的功能,代码的可移植性也提高。
混说Linux
2022/07/14
7970
赶紧收藏!u-boot代码分析与移植
【Android 系统开发】 Android 系统启动流程简介
转载请注明出处 : http://blog.csdn.net/shulianghan/article/details/38895481
韩曙亮
2023/03/27
6390
Android启动流程——1序言、bootloader引导与Linux启动
前面讲解的很多内容都很抽象,所以本次系列决定"接点地气",准备开始讲解大家熟悉的Activity了,为了让我以及大家更好的理解Activity,我决定本系列的课程主要分为4大流程和2大模块。 4大流程如下:
隔壁老李头
2018/08/30
5.4K0
Android启动流程——1序言、bootloader引导与Linux启动
超详细分析Bootloader(Uboot)到内核的启动流程(万字长文!)
  Bootloader的启动过程可以分为单阶段、多阶段两种。通常多阶段的 Bootloader能提供更为复杂的功能以及更好的可移植性。从固态存储设备上启动的 Bootloader大多都是两阶段的启动过程。第一阶段使用汇编来实现,它完成一些依赖于CPU体系结构的初始化,并调用第二阶段的代码;第二阶段则通常使用C语言来实现,这样可以实现更复杂的功能,而且代码会有更好的可读性和可移植性。   一般而言,这两个阶段完成的功能可以如下分类:
嵌入式与Linux那些事
2021/05/20
13.5K0
超详细分析Bootloader(Uboot)到内核的启动流程(万字长文!)
【嵌入式开发】 Bootloader 详解 ( 代码环境 | ARM 启动流程 | uboot 工作流程 | 架构设计)
博客地址 : http://blog.csdn.net/shulianghan/article/details/42462795
韩曙亮
2023/03/27
4.6K0
【嵌入式开发】 Bootloader 详解 ( 代码环境 | ARM 启动流程 | uboot 工作流程 | 架构设计)
ARM Linux 启动时的自解压过程 | Linux 内核
最近业余时间都在学习 Linux 内核和英语,或者是陪家人玩耍,没有投入太多的时间在文章。
用户8639654
2021/08/26
3K0
分析树莓派3b+上电启动流程
最近在玩树莓派,觉得这个树莓派的启动过程有点意思。所以在收集很多信息之后,个人也进行了一些实验和总结。先看一段原始资料:
bigmagic
2020/03/17
2.3K0
CentOS系统启动流程你懂否
一、Linux内核的组成 相关概念: Linux系统的组成部分:内核+根文件系统 内核:进程管理、内存管理、网络协议栈、文件系统、驱动程序。 IPC(Inter-Process Communication进程间通信):就是指多个进程之间相互通信,交换信息的方法。Linux IPC基本上都是从Unix平台上继承而来的。主要包括最初的Unix IPC,System V IPC以及基于Socket的IPC。另外,Linux也支持POSIX IPC。 运行中的系统环境可分为两层:内核空间、用户空间
小小科
2018/05/04
1.1K0
CentOS系统启动流程你懂否
Android系统启动之bootloader
BIOS: Basic Input/Output System(基本输入输出系统),一般是主板芯片上的一个程序,计算机通电后,第一件事就是读取它。
李小白是一只喵
2020/04/23
2.4K0
Android系统启动之bootloader
Centos6系统启动加载流程
了解一个系统的启动过程,对于一位系统管理员 and 运维是非常重要的。了解系统启动方式对于在系统出现故障时进行有效的故障排除非常重要。当系统启动并在几分钟后知道我们到了登录提示阶段。我们是否试图找出启动序列的所有阶段已经正常通过,以及系统启动期间这些场景背后发生了什么。下面我们就来熟悉一下Centos6系统的启动流程。
后场技术
2020/09/03
1.1K0
Centos6系统启动加载流程
Android系统启动流程
而我们的Android系统启动的过程就是架构图中从下往上运行加载的过程,这里有一张关于Android系统启动过程的总结图(图片来自参考链接gityuan.com),大家可以先看看:
码上积木
2021/01/11
1.7K0
Android系统启动流程
Linux启动流程
启动第一步--加载BIOS  当你打开计算机电源,计算机会首先加载BIOS信息,BIOS信息是如此的重要,以至于计算机必须在最开始就找到它。这是因为BIOS中包含了CPU的相关信息、设备启动顺序信息、硬盘信息、内存信息、时钟信息、PnP特性等等。在此之后,计算机心里就有谱了,知道应该去读取哪个硬件设备了。 启动第二步--读取MBR 众所周知,硬盘上第0磁道第一个扇区被称为MBR,也就是Master Boot Record,即主引导记录,它的大小是512字节,别看地方不大,可里面却存放了预启动信息、分区表信息
233333
2018/03/07
9K0
嵌入式Linux OS启动流程,了解一下!
作用: 确定用于启动的设备; 从启动的设备的位置搬移一小段代码(4k/8k/16k)到RAM中运行,即SPL;
刘盼
2020/03/18
2.1K0
嵌入式Linux OS启动流程,了解一下!
linux aarch64启动不了,引导AArch64 Linux
这篇文章基于Russell King所写的《the ARM booting document》,并与AArch64 Linux kernel的所有公开版本相关。
全栈程序员站长
2022/11/03
5.2K0
ARM64 SMP多核启动(上)- spin-table
一般嵌入式系统使用的都是对称多处理器(Symmetric Multi-Processor, SMP)系统,包含了多个cpu, 这几个cpu都是相同的处理器,如4核Contex-A53。但是在系统 启动阶段他们的地位并不是相同的,其中core0是主cpu(也叫引导处理器),其他core是从cpu(也叫辅处理器),引导cpu负责执行我们的启动加载程序如uboot,以及初始化内核,系统初始化完成之后主core会启动从处理器。
用户7244416
2021/08/06
1.8K0
高通SDX12平台:启动流程梳理
通常我们所说的CPU如高通平台MSM8998、苹果A12, 华为海思平台(麒麟980、990)等,这些我们虽然叫CPU,但并不是只有一个CPU,实际上是一个芯片组,在芯片组内部有很多CPU 协同工作的。不同处理器的子系统有: 图1 X12芯片组
四儿家的小祖宗
2022/11/15
3.5K0
高通SDX12平台:启动流程梳理
ARM-Cortex M核心的启动过程
启动代码是 MCU 复位后执行的第一段代码,主要作用是 初始化堆栈、设置中断向量表、调用系统初始化函数,并最终跳转到 main()。该文件采用 ARM 汇编实现,并按照 Cortex-M 内核启动流程设计。
云深无际
2025/02/05
2700
ARM-Cortex M核心的启动过程
第3阶段——内核启动分析之创建si工程和分析stext启动内核函数(4)
目标: (1)创建Source Insight 工程,方便后面分析如何启动内核的 (2)分析uboot传递参数,链接脚本如何进入stext的  (3) 分析stext函数如何启动内核:  (3.1
诺谦
2018/01/03
1K0
第3阶段——内核启动分析之创建si工程和分析stext启动内核函数(4)
Hypervisor Necromancy;恢复内核保护器(1)
--[ 0 - 简介 直到最近,为了在运行时攻击者破坏整个系统 发现并利用内核漏洞。这使他们能够执行 各种动作;在内核上下文中执行恶意代码, 修改内核数据结构以提升权限,访问受保护的数据, 等已经引入了各种缓解措施来防止此类 动作和管理程序也被使用,除了他们的 为实现这一目标而使用传统的虚拟化支持。在里面 ARM 虚拟化促进了 Android 生态系统 扩展,允许供应商/OEM 实施自己的保护 功能/逻辑。 另一方面,Android 设备已普遍成为主要的 PITA 由于引入的 OEM 和供应商种类繁多,
franket
2022/02/09
3K0
linux内核启动流程(文章最后流程图)
本文以Linux3.14版本源码为例分析其启动流程。各版本启动代码略有不同,但核心流程与思想万变不离其宗。
全栈程序员站长
2022/09/15
1.8K0
相关推荐
赶紧收藏!u-boot代码分析与移植
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档