pre loader简单分析

2023-11-18

ZZ from: http://blog.csdn.net/ly601579033/article/details/48318239

=============================================================

大致的流程图如下:

上电后RESET,ARM核开始执行Boot ROM,具体操作有:(代码固化在ROM中)

1、  初始化内置SRAM堆栈

2、  初始化nand/emmc(手机内置存储)

3、  把nand内存储的Pre-loader导入SRAM中

4、  跳到SRAM中执行Pre-loader

在内置SRAM中执行Pre-loader操作:(到bootloader/preloader下进行操作)<代码都在preloader目录下面>

1、配置c运行环境(寄存器、堆栈、BSS等)    BSS静态内存段(未初始化)、数据段(初始化)、堆段、栈段

2、初始化外部DRAM的timer、时钟、UART、EMI(DRAM防静电干扰)

3、跳到DRAM执行LK(little kernel)<LK代码被调到DRAM中>

具体源码如下:

先执行一个ld链接脚本——显示一部分(在bootable/bootloader/preloader平台的link_descriptor.ld文件)

OUTPUT_ARCH(arm)

ENTRY(_start)                                 //进入_start执行

romBase = 0x00201000;

ramBase = 0x00102180;

MEMORY {

    ram : ORIGIN= ramBase, LENGTH = 0xBA80

    rom : ORIGIN= romBase, LENGTH = 0x1F000

}

_start在init.s中位置,在ld里面定义c运行环境 (c运行环境(寄存器、堆栈、BSS等)地址)在这里被初始化

.globl _start

_start:

b resethandler

… … …

resethandler:                                       //进行reset操作,并disable irq

    LDR r6,=bldr_args_addr

    STR r4, [r6]

MOV r0, #0

… … … …                

LDR r0, =bldr_args_addr   //跳转操作,bldr_args_addr地址在之前有定义

B   main

进入main.c文件执行main操作

void main(u32 *arg){

   mtk_uart_init(UART_SRC_CLK_FRQ, CFG_LOG_BAUDRATE);

   bldr_pre_process();                  //外部RWAM的timer、时钟、UART设置

   bldr_handshake(&handler);    //UART、USB握手测试(保证可以通信)

   bldr_load_images;                    //导入Uboot镜像(镜像地址在此函数内的addr有定义)

   bldr_post_process();                

   bldr_jump(jump_addr,jump_arg, sizeof(boot_arg_t));  //跳转到DRAM执行

}

在跳转到DRAM执行LK时,传递了参数哪些参数呢?

bldr_jump(jump_addr, jump_arg, sizeof(boot_arg_t));

1、jump_addr跳转到LK执行的地址

2、向LK传递参数的地址

3、传递参数的大小

传递了一个boot_arg_t 结构的数据,这个结构数据定义在platform.c的platform_set_boot_args()函数下定义


跳转到LK执行<代码都在lk目录下面>

LK里面进行外设的初始化,加载内核并启动android系统初始化等操作,具体如下:

1、获取Pre-loader传递的参数

2、使能MMU单元

3、使能外设

4、设置Boot模式(这里可以进入fastboot模式)

5、导入kernel

6、调到kernel进行加载

跳转到LK中,在lk\arch\arm\crt0.s中

.globl _start

_start:

         b       reset

… … …

reset:

  ldr     r6, =BOOT_ARGUMENT_LOCATION                //把寄存器数据转移r6中

  str     r4, [r6]

在这个文件执行后,会跳转到kmain执行(通过 bl  kmain)

kmain 在 lk/kernel/main.c 中

void kmain(void){

         //初始化线程队列,创建一个bootstrap2线程并加入到队列中,这里可以看到线程有6种状态

         thread_init_early();

六种状态定义如下:

enum thread_state {

         THREAD_SUSPENDED= 0,             //中止

         THREAD_READY,                              //准备

         THREAD_RUNNING,                       //运行

         THREAD_BLOCKED,                        //阻塞

         THREAD_SLEEPING,                       //休眠

         THREAD_DEATH,                              //死亡

};

         // MMU初始化、相关寄存器初始化

         arch_early_init();

        //中断初始化、timer初始化准备、GPIO初始化、uart初始化、WDT(看门狗)初始化、SRAM修复、I2C固件初始化、Led初始化(背光)、pmic初始化(电源)

         platform_early_init();

         //null操作,在此没意义

         target_early_init();

         dprintf(INFO,"welcome to lk\n\n");

         //构造器,循环执行定义在.ctros里面的func

         dprintf(SPEW,"calling constructors\n");

         call_constructors();

         // thekernel heap初始化

         dprintf(SPEW,"initializing heap\n");

         heap_init();

         //initialize the threading system

         dprintf(SPEW,"initializing threads\n");

         thread_init();

         //软中断系统

         dprintf(SPEW,"initializing dpc\n");

         dpc_init();

         // timer初始化

         dprintf(SPEW,"initializing timers\n");

         timer_init();

#ifdef MTK_LK_IRRX_SUPPORT

  mtk_ir_init(0);

#endif

#if (!ENABLE_NANDWRITE)

         // resume线程bootstrap2

         dprintf(SPEW,"creating bootstrap completion thread\n");

        thread_resume(thread_create(“bootstrap2”,&bootstrap2, NULL,DEFAULT_PRIORITY,DEFAULT_STACK_SIZE));

         // enableinterrupts

         exit_critical_section();

         // 把当前线程变为idle线程

         thread_become_idle();

#endif

}

到此,当前线程变为idle,开启了新的线程bootstrap2。线程优先级为DEFAULT_PRIORITY,列出线程优先级的定义:

/* thread priority */

#define NUM_PRIORITIES 32                                                      

#define LOWEST_PRIORITY 0                                                       //最低优先级0

#define HIGHEST_PRIORITY (NUM_PRIORITIES - 1)                   //最高优先级31

#define DPC_PRIORITY  HIGHEST_PRIORITY                  //最高优先级31

#define IDLE_PRIORITY  LOWEST_PRIORITY                    //空闲 最低优先级0

#define LOW_PRIORITY (NUM_PRIORITIES / 4)                //低优先级8     

#define DEFAULT_PRIORITY (NUM_PRIORITIES / 2)          //默认优先级16

#define HIGH_PRIORITY ((NUM_PRIORITIES / 4) * 3)                //高优先级24

进入bootstrap2线程:

static int bootstrap2( void *arg){

         // platform初始化(nand初始化、环境变量env获取并打印、LCM显示相关(显示LOGO)、选择进入模式<这里按键判断可以进入boot烧写模式>)

         dprintf(SPEW,"initializing platform\n");

         platform_init();

         // null函数

         dprintf(SPEW,"initializing target\n");

         target_init();

         //执行__apps_start到__apps_end的app

         dprintf(SPEW,"calling apps_init()\n");

         apps_init();

         return 0;

}

apps跳到bootable\bootloader\lk\app\mt_boot\mt_boot.c执行mt_boot_init

看代码:

APP_START(mt_boot)

.init = mt_boot_init,                       //执行这个操作

    APP_END

进入mt_boot_init之后会执行boot_linux_from_storage操作,然后会执行

boot_linux((void *)CFG_BOOTIMG_LOAD_ADDR, (unsigned*)CFG_BOOTARGS_ADDR,

       (char*)commanline, board_machtype(), (void *)CFG_RAMDISK_LOAD_ADDR, g_rimg_sz);

CFG_BOOTIMG_LOAD_ADDR ————DRAM中BOOTIMG的物理地址

CFG_BOOTARGS_ADDR         ————向DRAM传递参数的位置

Commanline                               ————传递的参数commanline

board_machtype()                      ————board信息

CFG_RAMDISK_LOAD_ADDR ————ramdisk地址

注意:

1、传递到kernel的数据必须以ATAG的结构传递(便于接收)

2、关闭cache与MMU

最后执行————entry(0, machtype, tags);跳转到kernel执行   CFG_BOOTIMG_LOAD_ADDR地址处

LK向kernel传递的参数:(数据被封装的过程)

ATAG的结构封装必须以CORE开始,以END结束

         /* CORE*/

    *ptr++ = 2;

    *ptr++ =0x54410001;

    ptr =target_atag_boot(ptr);

    ptr =target_atag_mem(ptr);

    ptr =target_atag_meta(ptr);

    ptr =target_atag_commmandline(ptr, cmdline);

    ptr =target_atag_initrd(ptr,(unsigned long) ramdisk, ramdisk_size);

    ptr =target_atag_videolfb(ptr);

         /* END */

    *ptr++ = 0;

    *ptr++ = 0;

   

分析源码 ::

 unsigned*target_atag_boot(unsigned *ptr){

    *ptr++ =tag_size(tag_boot);           //tag_size大小

    *ptr++ =ATAG_BOOT;                      //tag name

    *ptr++ =g_boot_mode;                            //传递的数据

    return ptr;

}

unsigned *target_atag_mem(unsigned *ptr)

{

    int i;

    for (i = 0; i< g_nr_bank; i++) {

        *ptr++ =4;         //tag size

        *ptr++ =ATAG_MEM; //tag name

        *ptr++ =bi_dram[i].size;

        *ptr++ =bi_dram[i].start;

}

关于ATAG数据的定义以及传递到SRAM后的位置图

typedef enum{

    NORMAL_BOOT =0,

    META_BOOT =1,

    RECOVERY_BOOT= 2,

    SW_REBOOT =3,

    FACTORY_BOOT= 4,

    ADVMETA_BOOT= 5,

   ATE_FACTORY_BOOT = 6,

    ALARM_BOOT =7,

#if defined (MTK_KERNEL_POWER_OFF_CHARGING)

   KERNEL_POWER_OFF_CHARGING_BOOT = 8,

   LOW_POWER_OFF_CHARGING_BOOT = 9,

#endif

    FASTBOOT =99,

    DOWNLOAD_BOOT= 100,

    UNKNOWN_BOOT

} BOOTMODE;

进入kernel代码执行:<代码都在kernel中执行>

1、  指针入口操作

2、  Start Kernel

3、  Boot 参数

4、  Kthread

5、  Kernel_init()

6、  Init.rc

指针入口做的操作:

1、  超级用户模式,disable irq

2、  查询处理器/机器type

3、  检测ATAG格式

4、  建立页表,启动MMU

5、  调到init/main.c的start_kernel执行

asmlinkage void __init start_kernel(void){

         //mem初始化、cache初始化(装载页表)

         mm_init();

         //主要是解析传递过来的参数tags

         setup_arch(&command_line);

         /*

          * Set up the scheduler prior starting anyinterrupts (such as the

          * timer interrupt). Full topology setuphappens at smp_init()

          * time - but meanwhile we still have afunctioning scheduler.

          */

         sched_init();

         init_IRQ();

         /*

          * HACK ALERT! This is early. We're enablingthe console before

          * we've done PCI setups etc, andconsole_init() must be aware of

          * this. But we do want output early, in casesomething goes wrong.

          */

         console_init();

         //kernel初始化、开启Kthread

         rest_init();

}

在rest_init()执行驱动加载等操作---- >

static noinline void __init_refok rest_init(void){

         rcu_scheduler_starting();

         /*

          * We need to spawn init first so that itobtains pid 1, however

          * the init task will end up wanting to createkthreads, which, if

          * we schedule it before we create kthreadd,will OOPS.

          */

         kernel_thread(kernel_init,NULL, CLONE_FS | CLONE_SIGHAND);

         pid =kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);

         rcu_read_lock();

         kthreadd_task= find_task_by_pid_ns(pid, &init_pid_ns);

         rcu_read_unlock();

         complete(&kthreadd_done);

         /* Callinto cpu_idle with preempt disabled */

         cpu_startup_entry(CPUHP_ONLINE);

}

Kernel_init做了哪些操作————加载Root文件系统、初始化驱动模块、run init进程

run_init_process("/sbin/init") 、run_init_process("/etc/init") 、run_init_process("/bin/init")、run_init_process("/bin/sh")

开启init进程————设备初始化、开启Servicemanamger和zygote(两个android进程)

到此,完成初步的总结。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

pre loader简单分析 的相关文章

  • [网络]公共网络安全漏洞库:CVE/CNCVE

    1 前言 以网络安全行业中最大的 影响范围最广的CVE为例 CVE 的英文全称是 Common Vulnerabilities Exposures 通用漏洞披露 CVE就好像是一个字典表 为广泛认同的信息安全漏洞或者已经暴露出来的弱点给出一
  • 【数据库】redis数据持久化

    目录 数据持久化 一 RDB 1 什么是RDB 2 持久化流程 3 相关配置 案例演示 4 备份和恢复 1 备份 2 恢复 3 优势 4 劣势 二 AOF 1 什么是AOF 2 持久化流程 3 使用AOF 1 开启AOF 2 使用演示 3
  • SDAutoLayout的使用方法

    Cell高度自适应 label文字自适应 1 gt gt 设置cell高度自适应 cell 布局设置好之后调用此方法就可以实现高度自适应 注意 如果用高度自适应则不要再以cell的底边为参照去布局其子view cell setupAutoH
  • IC封装——从基本概念到TSV

    一 IC封装 在之前文章中有大致提过封装 这里展开讲讲 芯片生产流程 沧海一升的博客 CSDN博客每个半导体产品的制造都需要数百个工艺 泛林集团将整个制造过程分为八个步骤 晶圆加工 氧化 光刻 刻蚀 薄膜沉积 互连 测试 封装 芯片生产流程
  • 【Unix 网络编程】TCP状态转换图详解

    在前面 已经介绍了TCP协议的三路握手和四次挥手 如下图所示 TCP通信过程包括三个步骤 建立TCP连接通道 三次握手 数据传输 断开TCP连接通道 四次挥手 这里进一步探究TCP三路握手和四次挥手过程中的状态变迁以及数据传输过程 先看TC
  • 实现3D照片墙效果

  • 如何与老板谈加薪

    工作时间不短了 自己感觉业绩也不少了 可是老板似乎总也视而不见 发到手的薪水还只是那么点儿 于是乎 总有些愤愤不平的 心里难免就打起了小九九 觉得老板太抠 觉得自己遭遇太不公 这时候 就该跟老板谈谈加薪的事情啦 如果不谈 也许就该考虑是不是
  • 嵌入式程序员 应该知道的0x10个基本问题

    文章目录 1 用 预处理指令 define 声明一个常数 用以表明 1 年中有多少秒 忽略闰年问题 2 写一个标准宏 MIN 这个宏输入两个参数 并返回较小的一个 3 预处理器标识 error 的目的是什么 4 嵌入式系统中经常要用到无限循
  • sudo配置文件/etc/sudoers详解及实战用法

    一 sudo执行命令的流程 将当前用户切换到超级用户下 或切换到指定的用户下 然后以超级用户或其指定切换到的用户身份执行命令 执行完成后 直接退回到当前用户 具体工作过程如下 当用户执行sudo时 系统会主动寻找 etc sudoers文件
  • Spark 从入门到放弃(一)Spark基础概念

    一 Spark基础概念 1 Application Spark应用程序 application 应用 其实就是用spark submit提交的程序 一个application通常包含三部分 从数据源 比方说HDFS 取数据形成RDD 通过R
  • linux下python组织自定义模块,解决模块存在无法导入

    问题背景 在windows下使用pycharm开发python程序 包导入正常 但是移植到Linux却说包找不到了 No module named xxx python包路径搜索机制 python搜索包的路径存储在sys path下 临时添
  • 【测试设计】使用jenkins 插件Allure生成自动化测试报告

    前言 以前做自动化测试的时候一直用的HTMLTestRunner来生成测试报告 后来也尝试过用Python的PyH模块自己构建测试报告 在后来看到了RobotFramework的测试报告 感觉之前用的测试报告都太简陋 它才是测试报告应该有的
  • 分布式两阶段提交和三阶段提交

    随着大型网站的各种高并发访问 海量数据处理等场景越来越多 如何实现网站的高可用 易伸缩 可扩展 安全等目标就显得越来越重要 为了解决这样一系列问题 大型网站的架构也在不断发展 提高大型网站的高可用架构 不得不提的就是分布式 本文主要介绍关于
  • CSS 动画实战:创建一个漂亮的加载动画

    这篇文章 用一个实例来讲下用伪元素和CSS Animation来创建一个漂亮的加载动画 首先来看下 要实现的动画效果 先来分析下 这个动画效果是由哪几个动画组成 1 线段依次出现 2 然后红色 橙色和白色矩形依次出现 3 这些矩形出现之后
  • 微信小程序nodejs+vue高校食堂餐厅点餐订餐系统ja221

    本文以实际运用为开发背景 运用软件工程原理和开发方法 它主要是采用 语言 node js 框架 Express 前端 Vue js 数据库 mysql 数据库工具 Navicat 开发软件 VScode 前端vue elementui 1
  • 12000字解读白小T:成立1年创收1亿,单品类策略如何引爆流行?

    主笔 西兰卡普 研究员 白婷丹 Leo 西兰卡普 陆压 出品 增长黑盒研究组 研究支持 久谦中台 飞瓜数据 App Growing 前言 最近两年 当我们与新消费品牌创业者及操盘手探讨服饰赛道最新风向时 大家高频提及的不外乎是Bosie A
  • kubernetes Ingress资源管理

    k8s 对外服务之 Ingress Ingress 简介 service的作用体现在两个方面 对集群内部 它不断跟踪pod的变化 更新endpoint中对应pod的对象 提供了ip不断变化的pod的服务发现机制 对集群外部 他类似负载均衡器
  • 关于STM32的IAP与APP互相跳转

    关于STM32的IAP与APP互相跳转 之前做了一个不带系统的IAP与APP互相跳转 在网上找了资料后 很顺畅就完成了 后来在IAR集成开发环境下 IAP无系统 APP用UCOS系统做互相跳转出现了很多问题 现将IAP学习过程和实际遇到问题
  • 柏林噪声(Perlin Noise) 介绍及应用

    什么是噪声 信号处理中一般指原信号中不存在的无规则的额外信号 在处理过程中一般是我们不需要的 需要被处理掉的 噪声和信号本身无关 其频率和强弱变化无规律 噪声有什么用处 就如上面提到的那样 噪声是干扰原信号的存在 在信号处理中 我们一般都希
  • Spring基础总结

    Spring基础总结篇 1 获取 Spring 的 IOC 容器 并根据 bean 的 id 获取注入对象 1 通过 BeanFactory 获取 Bean 2 通过 ApplicationContext 应用上下文获取 Bean 2 Be

随机推荐

  • 玩转Mysql系列 - 第8篇:详解排序和分页(order by & limit),及存在的坑

    这是Mysql系列第7篇 环境 mysql5 7 25 cmd命令中进行演示 代码中被 包含的表示可选 符号分开的表示可选其一 本章内容 详解排序查询 详解limit limit存在的坑 分页查询中的坑 排序查询 order by 电商中
  • RedditVideoMakerBot 视频制作机器人自动生成视频搭建教程

    https github com elebumm RedditVideoMakerBot搭建教程 RedditVideoMakerBot视频制作机器人 有些在抖音 快手上的视频获得了数百万的观看次数 你仔细分析他们的视频 他们唯一做的原创事
  • 修改pip国内源

    修改pip国内源 修改源方法 临时使用 可以在使用pip的时候在后面加上 i参数 指定pip源 例如 pip install scrapy i https pypi tuna tsinghua edu cn simple 永久修改 linu
  • 【计算机视觉】直接线性变换(DLT)求解P矩阵(3 加入坐标的归一化)(附MATLAB代码)

    引言 本来上一篇帖子就已经达到了精度要求 不过经过同学提醒才发现老师的作业要求中有要求考虑归一化 emmmmm 坐标归一化 进行归一化的必要性和方法参考 计算机视觉中的多视几何 中的描述 上面的是从 2D到2D的结论 不过与从3D到2D的结
  • el-table添加行/单元格样式

    文章目录 一 官方文档释义 1 row style cell style 2 row class name cell class name 二 row style cell style的使用 1 row style 使用Object 使用F
  • 前端基础第一天:HTML常用标签知识点

    学习目标 理解 相对路径三种形式 应用 排版标签 文本格式化标签 图像标签 链接 相对路径 绝对路径的使用 1 HTML常用标签 首先 HTML和CSS是两种完全不同的语言 我们学的是结构 就只写HTML标签 认识标签就可以了 不会再给结构
  • antdv表格的rowSelection设置单选禁用选中等

    这个问题在项目中已经遇到过两次了 一次为表格想实现单选 禁用等 另一次则是今天 遇上需求需要在初始化表格的时候默认选中项目 鉴于自己的记性太差 记录记录 万一哪天又遇到这个问题心血来潮来翻了一翻博客 那问题就解决了 犹记得实现表格项单选和禁
  • 决策树(信息熵、增益率、基尼指数)

    目录 前言 一 决策树是什么 二 实验过程 1 选择数据集中各个决策属性的优先级 1 1信息熵 1 2增益率 1 3基尼指数 2 决策树的构造 2 1创建决策树 2 2准备数据 2 3 读取和保存决策树 2 4绘制决策树 3运行结果 3 1
  • 升级Linux中的默认JDK的版本

    我用的Linux是 红帽企业级Linux AS版 TLF SOFT Redhat Enterprise Linux AS V4 0 UPDATE 7 DVD 因工作需要 将Linux中默认安装的Jdk 版本为1 4 进行升级 将升级的经验和
  • BigDecimal的常用方法

    一 BigDecimal概述 Java在java math包中提供的API类BigDecimal 用来对超过16位有效位的数进行精确的运算 双精度浮点型变量double可以处理16位有效数 但在实际应用中 可能需要对更大或者更小的数进行运算
  • Python学习笔记(基础篇)

    目录 一 Python编程基础 1 1print 1 2 input 1 3 ASC 码 1 4注释 二 数据类型与基本运算符 2 1变量 2 2数值类型 整数 浮点数 复数 2 3字符串 2 4布尔类型 2 5数据类型转换 2 6算数运算
  • 【mysql】mysql group by分组后取每组的最小值

    方法一 非严格模式下 group by后 会取分组后多个create time 的其中一个 由于我们的 create time 时间是有序的 会取第一条 如果是无序字段 很可能取的顺序会有问题 可以在create time 前面加上grou
  • 苹果系统 macOS Mojave 10.14.4上安装 Ubuntu 18.04 双系统

    macOS Mojave 10 14 4 安装Ubuntu 18 04 双系统 0 准备工作 系统情况 1 制作Ubuntu安装盘 U盘 2 硬盘分区 3 安装Ubuntu 4 正常使用GRUB 5 调整Ubuntu设置 2019 07 1
  • Tomcat开启远程调试端口

    部署环境 Linux 亲测成功 tomcat7 bin startup sh的文件开头位置添加 declare x CATALINA OPTS server Xdebug Xnoagent Djava compiler NONE Xrunj
  • JavaWeb JDBC

    1 实现第一个JDBC程序 在MySQL中创建一个名称为jdbc的数据库 然后在该数据库中创建一个users表 创建 数据库和表的SQL语句如下所示 CREATE DATABASE jdbc USE jdbc CREATE TABLE us
  • html前后端缓存,前后端分离系列-缓存篇

    1 我们需要在静态文件返回给浏览器的时候header中的缓存变长 这样就可以在本地秒加载 省去了带宽和加载时间 修改server js const path require path const Koa require koa const
  • 内存泄露原因和解决方案

    资料参考出自 http blog chinaunix net uid 26930580 id 3844811 html http www jianshu com p 90caf813682d 为什么会产生内存泄漏 当一个对象已经不需要再使用
  • 基于Matlab应用DBSCAN

    基于Matlab应用DBSCAN Density Based Spatial Clustering of Applications with Noise 具有噪声的基于密度的聚类方法 一 算法原理 Matlab中的统计与机器学习工具箱 Th
  • SuperSocket实战手把手教程:一个完整的SocketServer项目

    SuperSocket系列教程 1 SuperSocket基础 一 基本概念 2 SuperSocket实战手把手教程 一个完整的SocketServer项目 目录 一 项目场景 1 Visual Studio新建项目 2 自定义自己服务器
  • pre loader简单分析

    ZZ from http blog csdn net ly601579033 article details 48318239 大致的流程图如下 上电后RESET ARM核开始执行Boot ROM 具体操作有 代码固化在ROM中 1 初始化