Android系统分析——Bootloader(Lk)

  • 1、Crt0.S
  • 2、bootable/bootloader/lk/app
  • Android系统分析——Bootloader(Lk)

  • LK是android系统的bootloader,是系统启动后的最早入口点(排除另一个核心modem部分)lk是little kernel的简称,如其名字一样,很多东西都做得很精简,但模块化实现的却很好,是一个真正的可抢占式多任务操作系统。其任务的总数可达到32个。而且其实现的功能也较丰富,包括:
  • 多种nand设备支持;
  • 加载多个Linux Kernel(其中一个是recovery);
  • 按键支持;
  • USB驱动支持(用于fastboot);
  • 显示设备支持;
  • Shell控制台支持等。
  • 下面从启动入口开始分析lk的实现。
    1. Lk启动流程
  • 入口是crt0.S,这里设置了arm的基本中断向量:
  • 其中,所有的中断向量除了reset之外,都是在exception.S中实现。
  • 如:FUNCTION(arm_undefined),FUNCTION(arm_irq)等
  • 汇编中的FUNCTION,是一个宏,其定义在asm.h中,如下:
  • 下面先分析reset之后的启动流程
  • reset也就是系统上电之后的启动流程,有如下几个关键步骤:
    1. 判断是否需要禁用中断,mmu等。
    1. 判断是否需要重新定向代码位置,因为当前运行位置有可能与链接时所指定的地址不一致,如果需要的话,则搬移代码。这一般是代码在Flash上启动,而又想要在Ram中运行所用到的。其判断依据是把当前PC指针同当前代码位置点(.Laddr)与代码启动点(_start)的差值做比较。即:PC ?= (.Laddr - _start)。
    1. 下面就进行各种运行模式的堆栈设置(.Lstack_setup)
    2. 设置/清零数据段
    1. 做完初始化动作之后,跳main.c中C代码入口:kmain,永远不退出:
  • Main.c中的kmain函数相当于操作系统的入口,它完成了系统基本
  • 线程早期初始化
  • 特定体系结构的早期初始化代码(指arm体系结构)
  • 平台相关硬件早期初始化,包括定时器,中断,串口等
  • 由于上面初始化了串口,这里就可以打印消息了
  • 调用所有的静态构造函数
  • 系统的堆初始化
  • 线程初始化(事实上前面已经初始化了,这里是空函数)
  • 初始化系统定时器,这里是任务调度的定时器,时间片是10ms
  • 创建一个bootstrap2线程(这是应用程序的调度线程),其实现下文分析
  • 把当前函数变为一个idle线程。
  • 上面系统的基本初始化就结束了,特定的硬件功能都是是在app线程中进行的,像fastbootUSB下载等线程,都是属于app线程。他们的父线程是bootstrap2
  • 空函数
  • 这里主要是初始化LCD等外设
  • 这里完成按键和flash分区表的初始化
  • 启动每一个注册的app线程
    1. app任务
  • Lk中,app的线程是通过一个宏注册的,这个宏是APP_START,它后面还必须跟一个APP_END,如下:
  • 到所有使用这个宏的,都是被定义到了“.apps”段中,而apps_init()函数就是通过调用此段中所有的函数指针,完成app线程的创建。apps_init()内容如下:
  • 可以看到此函数的实现是先调用app->init,然后通过start_app创建线程。事实上start_app()的实现是创建了一个入口时app->entry的线程(这里app变量的类型是app_descriptor)。
  • 从app_descriptor的声明来看,init是一个初始化,entry才是线程循环体。
  • BootloaderLk中注册app线程的主要有两个,一个是在aboot.c中,实现fastboot功能,另一个是shell.c,实现Shell功能。其中aboot.c中和shell.c中注册任务的方法如下:
  • 这里发现,aboot中并没有实现entry入口,而是仅仅实现了一个.init。而且这个aboot_init并不会退出,而这里并没有创建另一个线程,这就导致一旦调用aboot_init,上面的app_init函数就不能再创建任何其它线程了!也就是说,在.apps段中,所有在aboot之后的任务声明都无法调用。
  • 但lk中重要的实现:fastboot和引导Linux kernel的任务都是在aboot.c中完成的,所以这并不影响实际的功能。但这里还是值得注意的。
    1. 线程分析
  • lk中的线程也就是相当于操作系统下的任务,前文提到了线程创建的位置,即在kmain中。调度任务的实现在thread.c中,它实现了任务阻塞(thread_block),退出(thread_exit),时间片用完(即被抢占,thread_preemt)等的调度。实际上线程的任务抢占调度是通过timer_tick来实现(其它操作系统也是类似的实现)。
  • 线程调度的实现是在thread_resched中,它通过调用arch_context_switch实现调度功能。
  • 而最终调度的实现,是在asm.S中的会变实现的。
  • 其原理是,首先压栈所有的寄存器,并设置sp指针到新的线程,然后通过bx指令返回,因为返回指令会根据sp指针跳转,这样就切换到了新线程中。
  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值