android 开机流程详细分析

本文详细剖析了Android系统的开机过程,从arm平台的rom code开始,经过uboot加载kernel,到内核初始化,再到C代码的start_kernel()函数。接着讲解了driver的初始化、init进程的启动,如何解析init.rc并运行zygote进程,最终进入SystemServer启动ActivityManagerService,直至展示home界面。整个流程涵盖了从内核到用户空间的关键步骤。
摘要由CSDN通过智能技术生成

arm平台开机的时候,会先跑ic内部的rom code,rom code把flash上的uboot加载到dram中,然后执行uboot。不同的ic厂商uboot实现可能不一样,有些厂商会把uboot拆分为两个部分,第一部分会先加载到ic内部的sram运行起来,然后初始化dram,再把第二部分加载到dram中运行起来。这里我们不再深入探讨,我们只分析common的部分,uboot在跳转到kernel之前,会传递一些参数过来,并且对于arm构架的平台而言,跳转到kernel前,r0寄存器设置为0,r1的值为match type,r2的值为指向参数结构体的指针,所以kernel是通过r2寄存器拿到uboot传递过来的参数。


linux-4.10/arch/arm/kernel/head.S

/*
60   * Kernel startup entry point.
61   * ---------------------------
62   *
63   * This is normally called from the decompressor code.  The requirements
64   * are: MMU = off, D-cache = off, I-cache = dont care, r0 = 0,
65   * r1 = machine nr, r2 = atags or dtb pointer.
66   *
67   * This code is mostly position independent, so if you link the kernel at
68   * 0xc0008000, you call this at __pa(0xc0008000).
69   *
70   * See linux/arch/arm/tools/mach-types for the complete list of machine
71   * numbers for r1.
72   *
73   * We're trying to keep crap to a minimum; DO NOT add any machine specific
74   * crap here - that's what the boot loader (or in extreme, well justified
75   * circumstances, zImage) is for.
76   */
77  	.arm
78  
79  	__HEAD
80  ENTRY(stext)
   // ...
117  	/*
118  	 * r1 = machine no, r2 = atags or dtb,
119  	 * r8 = phys_offset, r9 = cpuid, r10 = procinfo
120  	 */
121  	bl	__vet_atags
  //...
130  	/*
131  	 * The following calls CPU specific code in a position independent
132  	 * manner.  See arch/arm/mm/proc-*.S for details.  r10 = base of
133  	 * xxx_proc_info structure selected by __lookup_processor_type
134  	 * above.
135  	 *
136  	 * The processor init function will be called with:
137  	 *  r1 - machine type
138  	 *  r2 - boot data (atags/dt) pointer
139  	 *  r4 - translation table base (low word)
140  	 *  r5 - translation table base (high word, if LPAE)
141  	 *  r8 - translation table base 1 (pfn if LPAE)
142  	 *  r9 - cpuid
143  	 *  r13 - virtual address for __enable_mmu -> __turn_mmu_on
144  	 *
145  	 * On return, the CPU will be ready for the MMU to be turned on,
146  	 * r0 will hold the CPU control register value, r1, r2, r4, and
147  	 * r9 will be preserved.  r5 will also be preserved if LPAE.
148  	 */
149  	ldr	r13, =__mmap_switched		@ address to jump to after
150  						@ mmu has been enabled
151  	badr	lr, 1f				@ return (PIC) address
152  #ifdef CONFIG_ARM_LPAE
153  	mov	r5, #0				@ high TTBR0
154  	mov	r8, r4, lsr #12			@ TTBR1 is swapper_pg_dir pfn
155  #else
156  	mov	r8, r4				@ set TTBR1 to swapper_pg_dir
157  #endif
158  	ldr	r12, [r10, #PROCINFO_INITFUNC]
159  	add	r12, r12, r10
160  	ret	r12
161  1:	b	__enable_mmu
162  ENDPROC(stext)

bl      __vet_atags 就是把uboot传递给kernel的参数拷贝到一个位置,ldr        r13, =__mmap_switched  保存后面要执行的指令

/*
436   * Setup common bits before finally enabling the MMU.  Essentially
437   * this is just loading the page table pointer and domain access
438   * registers.  All these registers need to be preserved by the
439   * processor setup function (or set in the case of r0)
440   *
441   *  r0  = cp#15 control register
442   *  r1  = machine ID
443   *  r2  = atags or dtb pointer
444   *  r4  = TTBR pointer (low word)
445   *  r5  = TTBR pointer (high word if LPAE)
446   *  r9  = processor ID
447   *  r13 = *virtual* address to jump to upon completion
448   */
449  __enable_mmu:
//...
471  	b	__turn_mmu_on
472  ENDPROC(__enable_mmu)
__enable_mmu执行完之后,又跳转到__turn_mmu_on,我们接下来看一下__turn_mmu_on。

490  ENTRY(__turn_mmu_on)
491  	mov	r0, r0
492  	instr_sync
493  	mcr	p15, 0, r0, c1, c0, 0		@ write control reg
494  	mrc	p15, 0, r3, c0, c0, 0		@ read id reg
495  	instr_sync
496  	mov	r3, r3
497  	mov	r3, r13
498  	ret	r3   //子程序返回时,执行这条指令,也就是跳到 __mmap_switched
499  __turn_mmu_on_end:
500  ENDPROC(__turn_mmu_on) 
__turn_mmu_on最后执行r3中的指令,r3从r13来,而r13在上面的赋值是__mmap_switched。

linux-4.10/arch/arm/kernel/head-common.S

15  #define ATAG_CORE 0x54410001
16  #define ATAG_CORE_SIZE ((2*4 + 3*4) >> 2)
17  #define ATAG_CORE_SIZE_EMPTY ((2*4) >> 2)

47  __vet_atags:
48  	tst	r2, #0x3			@ aligned?
49  	bne	1f
50  
51  	ldr	r5, [r2, #0]
52  #ifdef CONFIG_OF_FLATTREE
53  	ldr	r6, =OF_DT_MAGIC		@ is it a DTB?
54  	cmp	r5, r6
55  	beq	2f
56  #endif
57  	cmp	r5, #ATAG_CORE_SIZE		@ is first tag ATAG_CORE?
58  	cmpne	r5, #ATAG_CORE_SIZE_EMPTY
59  	bne	1f
60  	ldr	r5, [r2, #4]
61  	ldr	r6, =ATAG_CORE
62  	cmp	r5, r6
63  	bne	1f
64  
65  2:	ret	lr				@ atag/dtb pointer is ok
66  
67  1:	mov	r2, #0
68  	ret	lr
69  ENDPROC(__vet_atags)

在分析__mmap_switched之前,我们先看一下__vet_atags把参数拷贝到了哪里,下面这两句汇编相当于把uboot传递过来的参数拷贝到了0x54410001这个地址开始的内存中。

ldr    r5, [r2, #4]

ldr    r6, =ATAG_CORE

下面我们接着看__mmap_switched 汇编代码做了什么事。

/*
72   * The following fragment of code is executed with the MMU on in MMU mode,
73   * and uses absolute addresses; this is not position independent.
74   *
75   *  r0  = cp#15 control register
76   *  r1  = machine ID
77   *  r2  = atags/dtb pointer
78   *  r9  = processor ID
79   */
80  	__INIT
81  __mmap_switched:
82  	adr	r3, __mmap_switched_data
83  
84  	ldmia	r3!, {r4, r5, r6, r7}
85  	cmp	r4, r5				@ Copy data segment if needed
86  1:	cmpne	r5, r6
87  	ldrne	fp, [r4], #4
88  	strne	fp, [r5], #4
89  	bne	1b
90  
91  	mov	fp, #0				@ Clear BSS (and zero fp)
92  1:	cmp	r6, r7
93  	strcc	fp, [r6],#4
94  	bcc	1b
95  
96   ARM(	ldmia	r3, {r4, r5, r6, r7, sp})
97   THUMB(	ldmia	r3, {r4, r5, r6,
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值