Android系统启动过程-uBoot+Kernel+Android
摘要:本⽂是参考⼤量⽹上资源在结合⾃⼰查看源代码总结出来的,让⾃⼰同时也让⼤家加深对Android系统启动过程有⼀个更加深⼊的了解!再次强调,本⽂的⼤多数功劳应归功于那些原创者们,同时⼀些必要的参考链接我会⼀⼀附上。
注:由于本⼈采⽤Exynos4412开发板学习,所以本⽂⼤部分资料都是基于此处理器的
简介:对于整个Android系统的启动总的来说分为三个阶段:
BootLoader引导即uBoot.bin
linux内核启动即zImage
Android系统启动即ramdisk.img与system.img
以上四个⽂件都是经过⾃⼰编译后⽣成的且通过烧写测试,接下来开始说这三⼤部分的启动过程。
⽬录:⼀、BootLoader的启动
1.汇编部分
2.c部分
⼆、Kernel的启动
1.zImage解压缩
2.kernel的汇编启动阶段
3.kernel的c启动阶段
三、Android的启动
1.init进程
2.init启动的各种服务
3.android启动图⽰
第⼀部分:BootLoader的启动流程
uBoot的第⼀条指令从cpu/arm920t/start.S⽂件开始
1. 设置CPU进⼊SVC模式(系统管理模式),cpsr[4:0]=0xd3。
1 #include <common.h>
2 #include <config.h>
3
4/*
5 *************************************************************************
6 *
7 * Jump vector table as in table 3.1 in [1]
8 *
9 *************************************************************************
10*/
11
12
13 .globl _start
14 _start: b start_code
15 ldr pc, _undefined_instruction
16 ldr pc, _software_interrupt
17 ldr pc, _prefetch_abort
18 ldr pc, _data_abort
19 ldr pc, _not_ud
describe是什么意思
20 ldr pc, _irq
21 ldr pc, _fiq
22
23 _undefined_instruction: .word undefined_instruction
24 _software_interrupt: .word software_interrupt
25 _prefetch_abort: .word prefetch_abort
26 _data_abort: .word data_abort
27 _not_ud: .word not_ud
28 _irq: .word irq
29 _fiq: .word fiq
30
31 .balignl 16,0xdeadbeef
接着进⼊Start_code中:设置CPU进⼊SVC模式。
1/*
2 * the actual start code
3*/
4
5 start_code:
6/*
7 * t the cpu to SVC32 mode
8*/
9 mrs r0, cpsr
10 bic r0, r0, #0x1f
11 orr r0, r0, #0xd3
12 msr cpsr, r0
13
14 bl coloured_LED_init
15 bl red_LED_on
2.关看门狗,WTCON=0x0,并设置寄存器地址。
1/* turn off the watchdog */
2
3 # if defined(CONFIG_S3C2400)
4 # define pWTCON 0x15300000
5 # define INTMSK 0x14400008/* Interupt-Controller ba address */
6 # define CLKDIVN 0x14800014/* clock divisor register */
7#el
8 # define pWTCON 0x53000000
9 # define INTMSK 0x4A000008/* Interupt-Controller ba address */
10 # define INTSUBMSK 0x4A00001C
11 # define CLKDIVN 0x4C000014/* clock divisor register */
12 # endif
13
14 ldr r0, =pWTCON
15 mov r1, #0x0
16 str r1, [r0]
3.关中断,INTMSK=0xFFFFFFFF, INTSUBMSK=0x3FF。 1/*
2 * mask all IRQs by tting all bits in the INTMR - default
3*/
4 mov r1, #0xffffffff
5 ldr r0, =INTMSK
6 str r1, [r0]
7 # if defined(CONFIG_S3C2410)
8 ldr r1, =0x3ff
9 ldr r0, =INTSUBMSK
10 str r1, [r0]
11 # endif
4.时钟设置CLKDIVN=0x3 , FCLK:HCLK:PCLK = 1:2:4
日语三级
1/* FCLK:HCLK:PCLK = 1:2:4 */
2/* default FCLK is 120 MHz ! */
3 ldr r0, =CLKDIVN
4 mov r1, #3
5 str r1, [r0]
6#endif /* CONFIG_S3C24X0 */
5.询问是否进⾏CPU初始化
1 #ifndef CONFIG_SKIP_LOWLEVEL_INIT
2 bl cpu_init_crit
3#endif
6.relocate函数
1 #ifndef CONFIG_SKIP_RELOCATE_UBOOT
2 relocate: /* relocate U-Boot to RAM */
3 adr r0, _start /* r0 <- current position of code */
4 ldr r1, _TEXT_BASE /* test if we run from flash or RAM */
5 cmp r0, r1 /* don't reloc during debug */
6 beq stack_tup
7
8 ldr r2, _armboot_start
9 ldr r3, _bss_start
10 sub r2, r3, r2 /* r2 <- size of armboot */
11 add r2, r0, r2 /* r2 <- source end address */
12
13 copy_loop:
14 ldmia r0!, {r3-r10} /* copy from source address [r0] */
15 stmia r1!, {r3-r10} /* copy to target address [r1] */
16 cmp r0, r2 /* until source end addreee [r2] */
17 ble copy_loop
18#endif /* CONFIG_SKIP_RELOCATE_UBOOT */
7.初始化堆栈
1/* Set up the stack */
2 stack_tup:
3 ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */
4 sub r0, r0, #CONFIG_SYS_MALLOC_LEN /* malloc area */
5 sub r0, r0, #CONFIG_SYS_GBL_DATA_SIZE /* bdinfo */
6 #ifdef CONFIG_USE_IRQ
7 sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
8#endif
9 sub sp, r0, #12/* leave 3 words for abort-stack */
10
11 clear_bss:
12 ldr r0, _bss_start /* find start of bss gment */
13 ldr r1, _bss_end /* stop here */
14 mov r2, #0x00000000/* clear */
15
16 clbss_l:str r2, [r0] /* */
17 add r0, r0, #4
18 cmp r0, r1
19 ble clbss_l
8.CPU的初始化,即cpu_init_crit函数,完成以后回到主函数
1 #ifndef CONFIG_SKIP_LOWLEVEL_INIT
2 cpu_init_crit:
3/*
4 * flush v4 I/D caches
5*/
6 mov r0, #0
7 mcr p15, 0, r0, c7, c7, 0/* flush v3/v4 cache */
8 mcr p15, 0, r0, c8, c7, 0/* flush v4 TLB */
9
10/*
11 * disable MMU stuff and caches
12*/
13 mrc p15, 0, r0, c1, c0, 0
14 bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS)
15 bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM)
16 orr r0, r0, #0x00000002 @ t bit 2 (A) Align
17 orr r0, r0, #0x00001000 @ t bit 12 (I) I-Cache
18 mcr p15, 0, r0, c1, c0, 0
19
preparation20/*
21 * before relocating, we have to tup RAM timing
22 * becau memory timing is board-dependend, you will
23 * find a lowlevel_init.S in your board directory.
会计实操班24*/
25 mov ip, lr
26
27 bl lowlevel_init
startover
28
29 mov lr, ip
30 mov pc, lr
31#endif /* CONFIG_SKIP_LOWLEVEL_INIT */
9.从这⾥跳转到第⼆阶段C代码中去
1 ldr pc, _start_armboot
2
3 _start_armboot: .word start_armboot
C部分从⽂件/lib_arm/board.c的start_armboot()函数开始
1.定义⼀个struct global_data结构体指针gd,struct global_data结构体对象gd_data,
定义⼀个struct bd_info结构体对象bd_data,定义⼀个指向函数的⼆级指针init_fnc_ptr,定义的全局结构体对象都是放在堆栈中的,gd是放在寄存器中的。
2. gd=&gd_data,gd->bd = &bd_data,并且全部空间清0。
3.init_fnc_ptr = init_quence(⼀个初始化函数指针数组)。将会在接下来的for循环中提取出每⼀个函数来依次执⾏完。
tua
4.配置可⽤的flash空间,并且打印出相关信息,flash_init()和display_flash_config()。
5.mem_malloc_init()函数,分配堆空间.athena
6.env_relocate该函数的作⽤是将0x33ef0000开始16K的环境参数拷贝到堆空间中去。
7.gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr")通过这中⽅式获得环境变量列表中的ipaddr参数(开发板ip),获得环境变量中的MAC地址,设置到gd->bd->bi_enetaddr[reg]中。
8.devices_init函数,创建了devlist,但是只有⼀个串⼝设备注册在内。
9.console_init_r函数:控制台完全初始化,此后可以使⽤函数rial_getc和rial_putc或者putc和getc来输出log。
10.使能中断,如果有⽹卡设备,设置⽹卡MAC和IP地址。
11.main_loop ();定义于common/main.c。到此所有的初始化⼯作已经完成,main_loop在标准输⼊设备中接受命令,然后分析,查找和执⾏。
12.在上⾯的main_loop函数中,通常在开发完成的阶段都会设置⼀个bootcmd的环境变量,然后将延时bootdelay设置成0,这样当u-boot跑到这⾥的时候就不会因为⽤户按下了任意键就进⼊了命令⾏模式,
可以直接运⾏bootcmd的命令来直接加载kernel的Image然后移交控制权。如果进⼊了命令⾏模式,我们也可以⼿动输⼊命令来启动系统,输⼊的命令也是基本和bootcmd⼀样
1#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
2 s = getenv ("bootdelay");
3 bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;
4
5 debug ("### main_loop entered: bootdelay=%d\n\n", bootdelay);
这个地⽅时设置bootdelay的地⽅,即在引导kernel时等待⽤户命令,进⼊命令⾏模式,进⾏分区,格式化等操作。
13.uBoot 引导内核启动的最后⼀步是:通过⼀个函数指针 thekernel()带三个参数跳转到内核( zImage )⼊⼝点开始执⾏,此时, u-boot 的任务已经完成,控制权完全交给内核( zImage )。
在 uBoot 的⽂件lib_arm\bootm.c中定义了 thekernel, 并在 do_bootm_linux 的最后执⾏ thekernel。
定义thekernel函数指针,获取bootargs参数给commandline指针。
theKernel (0, machid, bd->bi_boot_params);第⼀个参数必须为0,第⼆个参数为机器类型ID,第三个参数为传递给内核参数的起始地址0x30000100
1int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images)
2 {
3 bd_t *bd = gd->bd;
4char *s;
四六级准考证号
5int machid = bd->bi_arch_number;
6void (*theKernel)(int zero, int arch, uint params);
7int ret;
8
9 #ifdef CONFIG_CMDLINE_TAG
10char *commandline = getenv ("bootargs");
11#endif
12
13if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
14return1;
15
16 theKernel = (void (*)(int, int, uint))images->ep;
17
18 s = getenv ("machid");
19if (s) {
20 machid = simple_strtoul (s, NULL, 16);
21 printf ("Using machid 0x%x from environment\n", machid);
22 }
23
24 ret = boot_get_ramdisk(argc, argv, images, IH_ARCH_ARM,
25 &(images->rd_start), &(images->rd_end));
26if(ret)
27 printf("[err] boot_get_ramdisk\n");
28
29 show_boot_progress (15);
30
31 debug ("## Transferring control to Linux (at address %08lx) ...\n",
32 (ulong) theKernel);
33
34#if defined (CONFIG_SETUP_MEMORY_TAGS) || \
35 defined (CONFIG_CMDLINE_TAG) || \
36 defined (CONFIG_INITRD_TAG) || \
37 defined (CONFIG_SERIAL_TAG) || \
38 defined (CONFIG_REVISION_TAG) || \
39 defined (CONFIG_LCD) || \
40 defined (CONFIG_VFD)
41 tup_start_tag (bd);
大写字母怎么写42 #ifdef CONFIG_SERIAL_TAG
43 tup_rial_tag (¶ms);
44#endif
45 #ifdef CONFIG_REVISION_TAG
46 tup_revision_tag (¶ms);
47#endif
48 #ifdef CONFIG_SETUP_MEMORY_TAGS
49 tup_memory_tags (bd);
50#endif
51 #ifdef CONFIG_CMDLINE_TAG
52 tup_commandline_tag (bd, commandline);
53#endif
54 #ifdef CONFIG_INITRD_TAG
55if (images->rd_start && images->rd_end)
56 tup_initrd_tag (bd, images->rd_start, images->rd_end); 57#endif
58#if defined (CONFIG_VFD) || defined (CONFIG_LCD)
59 tup_videolfb_tag ((gd_t *) gd);
60#endif
61 tup_end_tag (bd);
62#endif
63
64/* we assume that the kernel is in place */
65 printf ("\nStarting kernel ...\n\n");
66
67 #ifdef CONFIG_USB_DEVICE
68 {
69extern void udc_disconnect (void);
70 udc_disconnect ();
71 }
72#endif
73
74 cleanup_before_linux ();
75
76 theKernel (0, machid, bd->bi_boot_params);
77/* does not return */
78
79return1;
80 }
附上BootLoader启动时的调试信息
OK
U-Boot 2010.03 (Jul 142015 - 00:08:57) for iTOP-4412 Android CPU: SMDK4412-AP1.1 [e4412211]
APLL = 1000MHz, MPLL = 800MHz
ARM_CLOCK = 1000MHz
PMIC: S5M8767(VER5.0)
Board: iTOP-4412-Quad
POP type: POP for C220
DRAM: 1023 MB
MMC: Count: 100
max_emmc_clock:40 MHZ
Set CLK to 400 KHz
EMMC CLOCK OUTPUT:: 400KHz -[div:50]
respon timeout error : 00000104 cmd 8
respon timeout error : 00000104 cmd 55
max_emmc_clock:40 MHZ
Input CLK [ 50 MHz] is higher than limit [40 MHZ]
Set CLK to 40000 KHz
EMMC clock output: 40000 KHz
max_emmc_clock:40 MHZ
Input CLK [ 50 MHz] is higher than limit [40 MHZ]
Set CLK to 40000 KHz
EMMC clock output: 40000 KHz
MMC0: 3728 MB
SD sclk_mmc is 400K HZ
rai: Signal # 8 caught
沈阳培训学校
rai: Signal # 8 caught
MMC1: 0 MB
0 MB
*** Warning - using default environment