漫谈android系统(2)androidLK启动过程1
来源:互联网 发布:linux重启mysql数据库 编辑:程序博客网 时间:2024/05/01 08:25
andoid的启动过程
通过audio口所吐出的log,我们可以发现android的启动还是非常之有趣的,因而在此对它的启动做相应的分析。
在此分析LK的启动过程,LK就是bootloader。
现在只截取一部分的Log
[0] welcome to lk[10] platform_init()[10] target_init()[60] SDHC Running in HS400 mode[60] Done initialization of the card[70] pm8x41_get_is_cold_boot: Warm boot[70] Unsupported platform id
现在可以根据这部分的log来看LK是如何加载的。
当android加载完fileware时,LK会通过crt0.s的跳转命令,跳转到main.c中的kmain函数中去。
#ifdef ARM_CPU_CORTEX_A8 DSB ISB#endif bl kmain b ..ltorg
那么kmain又做了什么?
/* called from crt0.S */void kmain(void) __NO_RETURN __EXTERNALLY_VISIBLE;void kmain(void){ // get us into some sort of thread context thread_init_early(); // early arch stuff arch_early_init(); // do any super early platform initialization platform_early_init(); // do any super early target initialization target_early_init(); dprintf(INFO, "welcome to lk\n\n"); bs_set_timestamp(BS_BL_START); // deal with any static constructors dprintf(SPEW, "calling constructors\n"); call_constructors(); // bring up the kernel heap dprintf(SPEW, "initializing heap\n"); heap_init(); __stack_chk_guard_setup(); // initialize the threading system dprintf(SPEW, "initializing threads\n"); thread_init(); // initialize the dpc system dprintf(SPEW, "initializing dpc\n"); dpc_init(); // initialize kernel timers dprintf(SPEW, "initializing timers\n"); timer_init(); #if (!ENABLE_NANDWRITE) // create a thread to complete system initialization dprintf(SPEW, "creating bootstrap completion thread\n"); thread_resume(thread_create("bootstrap2", &bootstrap2, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE)); // enable interrupts exit_critical_section(); // become the idle thread thread_become_idle(); #else bootstrap_nandwrite(); #endif}
在这里,我们充分看到了Lk在kmain()中做了大量的初始化动作,其中thread_init_early()主要的工作是初始化线程系统,就是创建队列,然后系统根据CPU的不同架构进入不同的init线程
/** * @brief Initialize threading system * * This function is called once, from kmain() */void thread_init_early(void){ int i; /* initialize the run queues */ for (i=0; i < NUM_PRIORITIES; i++) list_initialize(&run_queue[i]); /* initialize the thread list */ list_initialize(&thread_list); /* create a thread to cover the current running state */ thread_t *t = &bootstrap_thread; init_thread_struct(t, "bootstrap"); /* half construct this thread, since we're already running */ t->priority = HIGHEST_PRIORITY; t->state = THREAD_RUNNING; t->saved_critical_section_count = 1; list_add_head(&thread_list, &t->thread_list_node); current_thread = t;}
arch_early_init()函数,一般采用的高通的芯片,因而会导向lk/arch/arm/arch.c,那么其主要的工作设置基本CPU属性
void arch_early_init(void) { /* turn off the cache */ arch_disable_cache(UCACHE); /* set the vector base to our exception vectors so we dont need to double map at 0 */ #if ARM_CPU_CORTEX_A8 set_vector_base(MEMBASE); #endif #if ARM_WITH_MMU arm_mmu_init(); #endif /* turn the cache back on */ arch_enable_cache(UCACHE); #if ARM_WITH_NEON /* enable cp10 and cp11 */ uint32_t val; __asm__ volatile("mrc p15, 0, %0, c1, c0, 2" : "=r" (val)); val |= (3<<22)|(3<<20); __asm__ volatile("mcr p15, 0, %0, c1, c0, 2" :: "r" (val)); isb(); /* set enable bit in fpexc */ __asm__ volatile("mrc p10, 7, %0, c8, c0, 0" : "=r" (val)); val |= (1<<30); __asm__ volatile("mcr p10, 7, %0, c8, c0, 0" :: "r" (val)); #endif #if ARM_CPU_CORTEX_A8 /* enable the cycle count register */ uint32_t en; __asm__ volatile("mrc p15, 0, %0, c9, c12, 0" : "=r" (en)); en &= ~(1<<3); /* cycle count every cycle */ en |= 1; /* enable all performance counters */ __asm__ volatile("mcr p15, 0, %0, c9, c12, 0" :: "r" (en)); /* enable cycle counter */ en = (1<<31); __asm__ volatile("mcr p15, 0, %0, c9, c12, 1" :: "r" (en)); #endif }
/lk/platform/msmtitanium/platform.c中的platform_early_init()首先会调用board_init(),它会去调用lk/platform/msm_shared/board.c中的Platform_detect函数来检测平台信息,平台信息包含主要信息(format_major)与次要信息(format_minor)。通过信息来初始化平台版本\hw\type,lk/target/msmtitanium/init.c中target_detect()不做任何事情,而target_baseband_detect函数会测试modem type
void platform_early_init(void){ board_init(); platform_clock_init(); qgic_init(); qtimer_init(); scm_init();}
platform_clock_init会初始化一些时钟信息,qgic_init(void)初始化qgic,qtimer_init()提供初始化频率,scm_init()是scm的初始化函数
target_early_init()函数是对串口的初始化,因而此时可以看到lk的第一条log:welcome to lk,后面的几个函数就是对一些时序,状态等等的初始化。
thread_resume(thread_create("bootstrap2", &bootstrap2, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
这个函数是重点,它创建了一个子线程bootstrap2来进行初始化。调用如下函数:
static int bootstrap2(void *arg){ dprintf(SPEW, "top of bootstrap2()\n"); arch_init(); // XXX put this somewhere else#if WITH_LIB_BIO bio_init();#endif#if WITH_LIB_FS fs_init();#endif // initialize the rest of the platform dprintf(SPEW, "initializing platform\n"); platform_init(); // initialize the target dprintf(SPEW, "initializing target\n"); target_init(); dprintf(SPEW, "calling apps_init()\n"); apps_init(); return 0;}
arch_init()里面什么都没做,然后调用/lk/platform/msmtitanium/platform.c下的platfrom_init(),其中只是打印了一条platform_init()log,
然后调用lk/target/xxxx/init.c的target_init()函数。这个函数可以做许多的定制,如将部分GPIO设定,与设置使用哪一个DTSI文件等等。
void target_init(void){#if VERIFIED_BOOT#if !VBOOT_MOTA int ret = 0;#endif#endif dprintf(INFO, "target_init()\n"); spmi_init(PMIC_ARB_CHANNEL_NUM, PMIC_ARB_OWNER_ID); target_keystatus(); target_sdc_init(); if (partition_read_table()) { dprintf(CRITICAL, "Error reading the partition table info\n"); ASSERT(0); }#if LONG_PRESS_POWER_ON shutdown_detect();#endif#if PON_VIB_SUPPORT vib_timed_turn_on(VIBRATE_TIME);#endif if (target_use_signed_kernel()) target_crypto_init_params();#if VERIFIED_BOOT#if !VBOOT_MOTA clock_ce_enable(CE1_INSTANCE); /* Initialize Qseecom */ ret = qseecom_init(); if (ret < 0) { dprintf(CRITICAL, "Failed to initialize qseecom, error: %d\n", ret); ASSERT(0); } /* Start Qseecom */ ret = qseecom_tz_init(); if (ret < 0) { dprintf(CRITICAL, "Failed to start qseecom, error: %d\n", ret); ASSERT(0); } if (rpmb_init() < 0) { dprintf(CRITICAL, "RPMB init failed\n"); ASSERT(0); } /* * Load the sec app for first time */ if (load_sec_app() < 0) { dprintf(CRITICAL, "Failed to load App for verified\n"); ASSERT(0); }#endif#endif#if SMD_SUPPORT rpm_smd_init();#endif}
该函数有对sim卡的GPIO的初始化,初始化spmi,target_keystatus();函数是对音量上下键的初始化,target_sdc_init初始化了mmc.包含了struct mmc_device *mmc_init(struct mmc_config_data *data)->uint32_t mmc_card_init(struct mmc_device *dev)可以看到mmc的选择模式
/* Enable high speed mode in the follwing order: * 1. HS400 mode if supported by host & card * 1. HS200 mode if supported by host & card * 2. DDR mode host, if supported by host & card * 3. Use normal speed mode with supported bus width */ if (host->caps.hs400_support && mmc_card_supports_hs400_mode(card)) { dprintf(INFO, "SDHC Running in HS400 mode\n"); mmc_return = mmc_set_hs400_mode(host, card, bus_width); if (mmc_return) { dprintf(CRITICAL, "Failure to set HS400 mode for Card(RCA:%x)\n", card->rca); return mmc_return; } }
此时执行完mmc_init,那么Done initialization of the card也就执行完成。
通过bootable/bootloader/lk/platfrom/msm_shared.c下partition_read_table()函数开始检查partition table。
unsigned int partition_read_table(){ unsigned int ret; uint32_t block_size; block_size = mmc_get_device_blocksize(); /* Allocate partition entries array */ if(!partition_entries) { partition_entries = (struct partition_entry *) calloc(NUM_PARTITIONS, sizeof(struct partition_entry)); ASSERT(partition_entries); } /* Read MBR of the card */ ret = mmc_boot_read_mbr(block_size); if (ret) { dprintf(CRITICAL, "MMC Boot: MBR read failed!\n"); return 1; } /* Read GPT of the card if exist */ if (gpt_partitions_exist) { ret = mmc_boot_read_gpt(block_size); if (ret) { dprintf(CRITICAL, "MMC Boot: GPT read failed!\n"); return 1; } } return 0;}
首先先获取mmc block的大小,会分配内存给partition_entries,然后从mmc中读取mbr,并将parse都初始化好。
随后会执行shutdown_detect();
* * Function to support for shutdown detection * If below condition is met, the function will shut down * the device. Otherwise it will do nothing and return to * normal boot. * condition: * 1. it is triggered by power key && * 2. the power key is released before * (PWRKEY_LONG_PRESS_COUNT/MPM_SLEEP_TIMETICK_COUNT) seconds. */void shutdown_detect(){ /* * If it is booted by power key tirigger. * Initialize pon_timer and call long_press_pwrkey_timer_func * function to check if the power key is last press long enough. */ if (is_pwrkey_pon_reason()) { if(!pm8x41_get_pwrkey_is_pressed()){ shutdown_device(); } timer_initialize(&pon_timer); timer_set_oneshot(&pon_timer, 0,(timer_callback)long_press_pwrkey_timer_func, NULL); /* * Wait until long press power key timeout * * It will be confused to end users if we shutdown the device * after the splash screen displayed. But it can be moved the * wait here if the boot time is much more considered. */ wait_for_long_pwrkey_pressed(); }}/* * Function to check if the power on reason is power key triggered. * Return 1 if it is triggered by power key. * Return 0 if it is not triggered by power key. */static uint32_t is_pwrkey_pon_reason(){#if PMI_CONFIGURED return target_is_pwrkey_pon_reason();#else uint8_t pon_reason = pm8x41_get_pon_reason(); if (pm8x41_get_is_cold_boot() && (pon_reason == KPDPWR_N)) return 1; else return 0;#endif}uint8_t pm8x41_get_is_cold_boot(){ if (REG_READ(PON_WARMBOOT_STATUS1) || REG_READ(PON_WARMBOOT_STATUS2)) { dprintf(INFO,"%s: Warm boot\n", __func__); return 0; } dprintf(INFO,"%s: cold boot\n", __func__); return 1;}
后面将会调用apps_init();
/* one time setup */void apps_init(void){ const struct app_descriptor *app; /* call all the init routines */ for (app = &__apps_start; app != &__apps_end; app++) { if (app->init) app->init(app); } /* start any that want to start on boot */ for (app = &__apps_start; app != &__apps_end; app++) { if (app->entry && (app->flags & APP_FLAG_DONT_START_ON_BOOT) == 0) { start_app(app); } }}
从注释中已经不难看出LK现在需要去启动boot了。
本文只是简单地介绍了LK的启动过程。其博大精深处还待我等慢慢发现。
- 漫谈android系统(2)androidLK启动过程1
- 漫谈android系统(1)解析android编译
- 漫谈android系统(7)-log系统1
- 漫谈android系统(8)-唠嗑说说手机制造的过程
- Android系统的启动过程
- Android系统的启动过程
- 漫谈android系统(5)点亮LED
- 漫谈android系统(5)点亮LED
- Android系统默认Home(Launcher)的启动过程小结
- Android系统默认Home(Launcher)的启动过程小结
- 学习Android系统(kitkat)进程Zygote启动过程
- Android系统默认Home(Launcher)的启动过程小结
- Android系统默认Home(Launcher)的启动过程小结
- Android系统源码阅读(2):根Activity组件的启动过程
- Android 4.4 Graphic系统详解(1) SurfaceFlinger的启动过程
- Android 4.4 Graphic系统详解(1) SurfaceFlinger的启动过程
- Android 4.4 Graphic系统详解(1) SurfaceFlinger的启动过程
- Android 4.4 Graphic系统详解(1) SurfaceFlinger的启动过程
- SAP模块常用增强总结
- linux下安装Django
- listview使用方法
- location方法详解,获取地址栏URL请求参数,以对象形式保存
- 流行的更换图片的javascript函数集--MM_swapImage函数和MM_swapImgRestore函数
- 漫谈android系统(2)androidLK启动过程1
- Android硬件访问服务框架分析
- 浅谈iOS中的蓝牙技术(一) --GameKit.framework
- 一般我们app涉及到的库
- char *p[5] 和 char p[5][10] 和 char **p的区别
- Elasticsearch基础教程
- C/C++ 各种计时函数总结
- ARM处理器异常处理
- Linux修改主机名,修改默认localhost.localdomain名称