Android LK Bootlaoder启动概览
LK - Little kernel
1. 起源地: bootable\bootloader\lk\arch\arm
(1)rule.mk
$(BUILDDIR)/trustzone-test-system-onesegment.ld: $(LOCAL_DIR)/trustzone-test-system-onesegment.ld
?? ?@echo generating $@
?? ?@$(MKDIR)
?? ?$(NOECHO)sed "s/%MEMBASE%/$(MEMBASE)/;s/%MEMSIZE%/$(MEMSIZE)/;s/%ROMLITE_PREFLASHED_DATA%/$(ROMLITE_PREFLASHED_DATA)/" < $< > $@
$(BUILDDIR)/trustzone-system-onesegment.ld: $(LOCAL_DIR)/trustzone-system-onesegment.ld
?? ?@echo generating $@
?? ?@$(MKDIR)
?? ?$(NOECHO)sed "s/%MEMBASE%/$(MEMBASE)/;s/%MEMSIZE%/$(MEMSIZE)/" < $< > $@
$(BUILDDIR)/system-onesegment.ld: $(LOCAL_DIR)/system-onesegment.ld
?? ?@echo generating $@
?? ?@$(MKDIR)
?? ?$(NOECHO)sed "s/%MEMBASE%/$(MEMBASE)/;s/%MEMSIZE%/$(MEMSIZE)/" < $< > $@
$(BUILDDIR)/system-twosegment.ld: $(LOCAL_DIR)/system-twosegment.ld
?? ?@echo generating $@
?? ?@$(MKDIR)
?? ?$(NOECHO)sed "s/%ROMBASE%/$(ROMBASE)/;s/%MEMBASE%/$(MEMBASE)/;s/%MEMSIZE%/$(MEMSIZE)/" < $< > $@
(2) system-onesegment.ld
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
(3) crt0.S (crt - C RunTime)
#define DSB .byte 0x4f, 0xf0, 0x7f, 0xf5
#define ISB .byte 0x6f, 0xf0, 0x7f, 0xf5
.section ".text.boot"
.globl _start
_start:
?? ?b?? ?reset
?? ?b?? ?arm_undefined
?? ?b?? ?arm_syscall
?? ?b?? ?arm_prefetch_abort
?? ?b?? ?arm_data_abort
?? ?b?? ?arm_reserved
?? ?b?? ?arm_irq
?? ?b?? ?arm_fiq
reset:
...
????bl?? ??? ?kmain // 轉到C代碼
?? ?b?? ??? ?.
.ltorg
.bss
.align 2
abort_stack:
?? ?.skip 1024
abort_stack_top:
2. bootable\bootloader\lk\kernel\main.c
/* 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();?? // 調(diào)用調(diào)試串口初始化uart_dm_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
}
int main(void);
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;
}
3. bootable\bootloader\lk\app\app.c
void?apps_init(void)
{
?? ?const struct app_descriptor *app;
??? // #define APP_START(appname) struct app_descriptor _app_##appname __SECTION(".apps") = { .name = #appname,
?? ?/* 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);
?? ??? ?}
?? ?}
}
static int app_thread_entry(void *arg)
{
?? ?const struct app_descriptor *app = (const struct app_descriptor *)arg;
?? ?app->entry(app, NULL);
?? ?return 0;
}
static void?start_app(const struct app_descriptor *app)
{
?? ?thread_t *thr;
?? ?printf("starting app %s\n", app->name);
?? ?thr =?thread_create(app->name, &app_thread_entry, (void *)app, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE);
?? ?if(!thr)
?? ?{
?? ??? ?return;
?? ?}
?? ?thread_resume(thr);
}
4. bootable\bootloader\lk\app\aboot\aboot.c
void?aboot_init(const struct app_descriptor *app)
{
?? ?unsigned reboot_mode = 0;
?? ?unsigned hard_reboot_mode = 0;
?? ?bool boot_into_fastboot = false;
?? ?/* Setup page size information for nv storage */
?? ?if (target_is_emmc_boot())
?? ?{
?? ??? ?page_size = mmc_page_size();
?? ??? ?page_mask = page_size - 1;
?? ?}
?? ?else
?? ?{
?? ??? ?page_size = flash_page_size();
?? ??? ?page_mask = page_size - 1;
?? ?}
?? ?ASSERT((MEMBASE + MEMSIZE) > MEMBASE);
?? ?read_device_info(&device);
?? ?read_allow_oem_unlock(&device);
?? ?/* Display splash screen if enabled */
#if DISPLAY_SPLASH_SCREEN
?? ?dprintf(SPEW, "Display Init: Start\n");
?? ?target_display_init(device.display_panel);
?? ?dprintf(SPEW, "Display Init: Done\n");
#endif
?? ?target_serialno((unsigned char *) sn_buf);
?? ?dprintf(SPEW,"serial number: %s\n",sn_buf);
?? ?memset(display_panel_buf, '\0', MAX_PANEL_BUF_SIZE);
?? ?/*
?? ? * Check power off reason if user force reset,
?? ? * if yes phone will do normal boot.
?? ? */
?? ?if (is_user_force_reset())
?? ??? ?goto normal_boot;
?? ?/* Check if we should do something other than booting up */
?? ?if (keys_get_state(KEY_VOLUMEUP) && keys_get_state(KEY_VOLUMEDOWN))
?? ?{
?? ??? ?dprintf(ALWAYS,"dload mode key sequence detected\n");
?? ??? ?if (set_download_mode(EMERGENCY_DLOAD))
?? ??? ?{
?? ??? ??? ?dprintf(CRITICAL,"dload mode not supported by target\n");
?? ??? ?}
?? ??? ?else
?? ??? ?{
?? ??? ??? ?reboot_device(DLOAD);
?? ??? ??? ?dprintf(CRITICAL,"Failed to reboot into dload mode\n");
?? ??? ?}
?? ??? ?boot_into_fastboot = true;
?? ?}
?? ?if (!boot_into_fastboot)
?? ?{
?? ??? ?if (keys_get_state(KEY_HOME) || keys_get_state(KEY_VOLUMEUP))
?? ??? ??? ?boot_into_recovery = 1;
?? ??? ?if (!boot_into_recovery &&
?? ??? ??? ?(keys_get_state(KEY_BACK) || keys_get_state(KEY_VOLUMEDOWN)))
?? ??? ??? ?boot_into_fastboot = true;
?? ?}
?? ?#if NO_KEYPAD_DRIVER
?? ?if (fastboot_trigger())
?? ??? ?boot_into_fastboot = true;
?? ?#endif
?? ?reboot_mode = check_reboot_mode();
?? ?hard_reboot_mode = check_hard_reboot_mode();
?? ?if (reboot_mode == RECOVERY_MODE ||
?? ??? ?hard_reboot_mode == RECOVERY_HARD_RESET_MODE) {
?? ??? ?boot_into_recovery = 1;
?? ?} else if(reboot_mode == FASTBOOT_MODE ||
?? ??? ?hard_reboot_mode == FASTBOOT_HARD_RESET_MODE) {
?? ??? ?boot_into_fastboot = true;
?? ?} else if(reboot_mode == ALARM_BOOT ||
?? ??? ?hard_reboot_mode == RTC_HARD_RESET_MODE) {
?? ??? ?boot_reason_alarm = true;
?? ?}
?? ?gpio_tlmm_config(FACTORY_TEST_GPIO, 0, GPIO_INPUT, GPIO_PULL_UP, GPIO_2MA, GPIO_ENABLE);
normal_boot:
?? ?if (!boot_into_fastboot)
?? ?{
?? ??? ?if (target_is_emmc_boot())
?? ??? ?{
?? ??? ??? ?if(emmc_recovery_init())
?? ??? ??? ??? ?dprintf(ALWAYS,"error in emmc_recovery_init\n");
?? ??? ??? ?if(target_use_signed_kernel())
?? ??? ??? ?{
?? ??? ??? ??? ?if((device.is_unlocked) || (device.is_tampered))
?? ??? ??? ??? ?{
?? ??? ??? ??? ?#ifdef TZ_TAMPER_FUSE
?? ??? ??? ??? ??? ?set_tamper_fuse_cmd();
?? ??? ??? ??? ?#endif
?? ??? ??? ??? ?#if USE_PCOM_SECBOOT
?? ??? ??? ??? ??? ?set_tamper_flag(device.is_tampered);
?? ??? ??? ??? ?#endif
?? ??? ??? ??? ?}
?? ??? ??? ?}
?? ??? ??? ?boot_linux_from_mmc(); // 執(zhí)行此行,它調(diào)用boot_linux()
?? ??? ?}
?? ??? ?else
?? ??? ?{
?? ??? ??? ?recovery_init();
?? ?#if USE_PCOM_SECBOOT
?? ??? ?if((device.is_unlocked) || (device.is_tampered))
?? ??? ??? ?set_tamper_flag(device.is_tampered);
?? ?#endif
?? ??? ??? ?boot_linux_from_flash();
?? ??? ?}
?? ??? ?dprintf(CRITICAL, "ERROR: Could not do normal boot. Reverting "
?? ??? ??? ?"to fastboot mode.\n");
?? ?}
?? ?/* We are here means regular boot did not happen. Start fastboot. */
?? ?/* register aboot specific fastboot commands */
?? ?aboot_fastboot_register_commands();
?? ?/* dump partition table for debug info */
?? ?partition_dump();
?? ?/* initialize and start fastboot */
?? ?fastboot_init(target_get_scratch_address(), target_get_max_flash_size());
}
...
void?boot_linux(void *kernel, unsigned *tags,
?? ??? ?const char *cmdline, unsigned machtype,
?? ??? ?void *ramdisk, unsigned ramdisk_size)
{
?? ?unsigned char *final_cmdline;
#if DEVICE_TREE
?? ?int ret = 0;
#endif
??? dprintf(INFO, "***ByTom B001 \n");
?? ?void (*entry)(unsigned, unsigned, unsigned*) = (entry_func_ptr*)(PA((addr_t)kernel));
?? ?uint32_t tags_phys = PA((addr_t)tags);
?? ?struct kernel64_hdr *kptr = (struct kernel64_hdr*)kernel;
?? ?dprintf(INFO, "***ByTom B002 \n");
?? ?ramdisk = PA(ramdisk);
?? ?dprintf(INFO, "***ByTom B003 \n");
?? ?final_cmdline = update_cmdline((const char*)cmdline);
?? ?dprintf(INFO, "***ByTom B004 \n");
#if DEVICE_TREE
?? ?dprintf(INFO, "Updating device tree: start\n");
?? ?/* Update the Device Tree */
?? ?ret = update_device_tree((void *)tags, final_cmdline, ramdisk, ramdisk_size);
?? ?if(ret)
?? ?{
?? ??? ?dprintf(CRITICAL, "ERROR: Updating Device Tree Failed \n");
?? ??? ?ASSERT(0);
?? ?}
?? ?dprintf(INFO, "Updating device tree: done\n");
#else
?? ?/* Generating the Atags */
??? dprintf(INFO, "***ByTom B005 \n");
?? ?generate_atags(tags, final_cmdline, ramdisk, ramdisk_size);
#endif
??? dprintf(INFO, "***ByTom B006 \n");
?? ?free(final_cmdline);
?? ?dprintf(INFO, "***ByTom B007 \n");
#if VERIFIED_BOOT
?? ?/* Write protect the device info */
??? dprintf(INFO, "***ByTom B008 \n");
?? ?if (target_build_variant_user() && devinfo_present && mmc_write_protect("devinfo", 1))
?? ?{
?? ??? ?dprintf(INFO, "Failed to write protect dev info\n");
?? ??? ?ASSERT(0);
?? ?}
#endif
??? dprintf(INFO, "***ByTom B009 \n");
?? ?/* Perform target specific cleanup */
?? ?target_uninit();
?? ?/* Turn off splash screen if enabled */
#if DISPLAY_SPLASH_SCREEN
??? dprintf(INFO, "***ByTom B010 \n");
?? ?target_display_shutdown();
#endif
?? ?dprintf(INFO, "booting linux @ %p, ramdisk @ %p (%d), tags/device tree @ %p\n",
?? ??? ?entry, ramdisk, ramdisk_size, tags_phys);
?? ?enter_critical_section();
?? ?dprintf(INFO, "***ByTom B011 \n");
?? ?/* do any platform specific cleanup before kernel entry */
?? ?platform_uninit();
?? ?dprintf(INFO, "***ByTom B012 \n");
?? ?arch_disable_cache(UCACHE);
?? ?dprintf(INFO, "***ByTom B013 \n");
#if ARM_WITH_MMU
?? ?arch_disable_mmu();
#endif
?? ?bs_set_timestamp(BS_KERNEL_ENTRY);
??? dprintf(INFO, "***ByTom B014 \n");
?? ?if (IS_ARM64(kptr))
?? ?{
?? ???? dprintf(INFO, "***ByTom B015 \n");
?? ??? ?/* Jump to a 64bit kernel */
?? ??? ?scm_elexec_call((paddr_t)kernel, tags_phys);
?? ?}
?? ?else
?? ?{
?? ???? dprintf(INFO, "***ByTom B016 \n");
?? ??? ?/* Jump to a 32bit kernel */
?? ??? ?entry(0, machtype, (unsigned*)tags_phys);? // 可能跳到kernel\arch\arm\boot\compressed\head.S,其中調(diào)用了kernel\arch\arm\boot\compressed\misc.c函數(shù)decompress_kernel()
?? ?}
}
...
APP_START(aboot)
?? ?.init = aboot_init,
APP_END
解壓后正式進入內(nèi)核運行起點,是從文件kernel/arch/arm/kernel/head.S開始,因為連接文件vmlinux.lds里決定的ENTRY(stext)。
head.S包含同目錄文件head-common.S,其調(diào)用kernel\init\main.c函數(shù)start_kernel(),進入到C代碼。
附:??kernel\init\main.c函數(shù)start_kernel()
asmlinkage void __init?start_kernel(void)
{
?? ?char * command_line;
?? ?extern const struct kernel_param __start___param[], __stop___param[];
?? ?/*
?? ? * Need to run as early as possible, to initialize the
?? ? * lockdep hash:
?? ? */
?? ?lockdep_init();
?? ?smp_setup_processor_id();
?? ?debug_objects_early_init();
?? ?cgroup_init_early();
?? ?local_irq_disable();
?? ?early_boot_irqs_disabled = true;
/*
?* Interrupts are still disabled. Do necessary setups, then
?* enable them
?*/
?? ?boot_cpu_init();
?? ?page_address_init();
?? ?pr_notice("%s", linux_banner);
?? ?setup_arch(&command_line);
?? ?/*
?? ? * Set up the the initial canary ASAP:
?? ? */
?? ?boot_init_stack_canary();
?? ?mm_init_owner(&init_mm, &init_task);
?? ?mm_init_cpumask(&init_mm);
?? ?setup_command_line(command_line);
?? ?setup_nr_cpu_ids();
?? ?setup_per_cpu_areas();
?? ?smp_prepare_boot_cpu();?? ?/* arch-specific boot-cpu hooks */
?? ?build_all_zonelists(NULL, NULL);
?? ?page_alloc_init();
?? ?pr_notice("Kernel command line: %s\n", boot_command_line);
?? ?parse_early_param();
?? ?parse_args("Booting kernel", static_command_line, __start___param,
?? ??? ??? __stop___param - __start___param,
?? ??? ??? -1, -1, &unknown_bootoption);
?? ?jump_label_init();
?? ?/*
?? ? * These use large bootmem allocations and must precede
?? ? * kmem_cache_init()
?? ? */
?? ?setup_log_buf(0);
?? ?pidhash_init();
?? ?vfs_caches_init_early();
?? ?sort_main_extable();
?? ?trap_init();
?? ?mm_init();
?? ?/*
?? ? * Set up the scheduler prior starting any interrupts (such as the
?? ? * timer interrupt). Full topology setup happens at smp_init()
?? ? * time - but meanwhile we still have a functioning scheduler.
?? ? */
?? ?sched_init();
?? ?/*
?? ? * Disable preemption - early bootup scheduling is extremely
?? ? * fragile until we cpu_idle() for the first time.
?? ? */
?? ?preempt_disable();
?? ?if (WARN(!irqs_disabled(), "Interrupts were enabled *very* early, fixing it\n"))
?? ??? ?local_irq_disable();
?? ?idr_init_cache();
?? ?perf_event_init();
?? ?rcu_init();
?? ?tick_nohz_init();
?? ?radix_tree_init();
?? ?/* init some links before init_ISA_irqs() */
?? ?early_irq_init();
?? ?init_IRQ();
?? ?tick_init();
?? ?init_timers();
?? ?hrtimers_init();
?? ?softirq_init();
?? ?timekeeping_init();
?? ?time_init();
?? ?sched_clock_postinit();
?? ?profile_init();
?? ?call_function_init();
?? ?WARN(!irqs_disabled(), "Interrupts were enabled early\n");
?? ?early_boot_irqs_disabled = false;
?? ?local_irq_enable();
?? ?kmem_cache_init_late();
?? ?/*
?? ? * HACK ALERT! This is early. We're enabling the console before
?? ? * we've done PCI setups etc, and console_init() must be aware of
?? ? * this. But we do want output early, in case something goes wrong.
?? ? */
?? ?console_init();
?? ?if (panic_later)
?? ??? ?panic(panic_later, panic_param);
?? ?lockdep_info();
?? ?/*
?? ? * Need to run this when irqs are enabled, because it wants
?? ? * to self-test [hard/soft]-irqs on/off lock inversion bugs
?? ? * too:
?? ? */
?? ?locking_selftest();
#ifdef CONFIG_BLK_DEV_INITRD
?? ?if (initrd_start && !initrd_below_start_ok &&
?? ???? page_to_pfn(virt_to_page((void *)initrd_start)) < min_low_pfn) {
?? ??? ?pr_crit("initrd overwritten (0x%08lx < 0x%08lx) - disabling it.\n",
?? ??? ???? page_to_pfn(virt_to_page((void *)initrd_start)),
?? ??? ???? min_low_pfn);
?? ??? ?initrd_start = 0;
?? ?}
#endif
?? ?page_cgroup_init();
?? ?debug_objects_mem_init();
?? ?kmemleak_init();
?? ?setup_per_cpu_pageset();
?? ?numa_policy_init();
?? ?if (late_time_init)
?? ??? ?late_time_init();
?? ?sched_clock_init();
?? ?calibrate_delay();
?? ?pidmap_init();
?? ?anon_vma_init();
#ifdef CONFIG_X86
?? ?if (efi_enabled(EFI_RUNTIME_SERVICES))
?? ??? ?efi_enter_virtual_mode();
#endif
?? ?thread_info_cache_init();
?? ?cred_init();
?? ?fork_init(totalram_pages);
?? ?proc_caches_init();
?? ?buffer_init();
?? ?key_init();
?? ?security_init();
?? ?dbg_late_init();
?? ?vfs_caches_init(totalram_pages);
?? ?signals_init();
?? ?/* rootfs populating might need page-writeback */
?? ?page_writeback_init();
#ifdef CONFIG_PROC_FS
?? ?proc_root_init();
#endif
?? ?cgroup_init();
?? ?cpuset_init();
?? ?taskstats_init_early();
?? ?delayacct_init();
?? ?check_bugs();
?? ?acpi_early_init(); /* before LAPIC and SMP init */
?? ?sfi_init_late();
?? ?if (efi_enabled(EFI_RUNTIME_SERVICES)) {
?? ??? ?efi_late_init();
?? ??? ?efi_free_boot_services();
?? ?}
?? ?ftrace_init();
?? ?/* Do the rest non-__init'ed, we're now alive */
?? ?rest_init();
}
另: kernel\arch\arm\boot\compressed\misc.c文件中
void decompress_kernel(unsigned long output_start, unsigned long free_mem_ptr_p, unsigned long free_mem_ptr_end_p, int arch_id)
{
?? ?int ret;
?? ?__stack_chk_guard_setup();
?? ?output_data?? ??? ?= (unsigned char *)output_start;
?? ?free_mem_ptr?? ??? ?= free_mem_ptr_p;
?? ?free_mem_end_ptr?? ?= free_mem_ptr_end_p;
?? ?__machine_arch_type?? ?= arch_id;
?? ?arch_decomp_setup();
?? ?putstr("Uncompressing Linux...");
?? ?ret = do_decompress(input_data, input_data_end - input_data, output_data, error);
?? ?if (ret)
?? ??? ?error("decompressor returned an error");
?? ?else
?? ??? ?putstr("?done, booting the kernel.\n");
}
總結
以上是生活随笔為你收集整理的Android LK Bootlaoder启动概览的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何写好一份竞品运营分析报告?
- 下一篇: 平述factory reset——从ma