Android LK Bootlaoder启动概览

LK - Little kernel

1. 起源地: bootableootloaderlkarcharm

(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. bootableootloaderlkkernelmain.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();   // 调用调试串口初始化uart_dm_init()

    dprintf(INFO, "welcome to lk ");
    bs_set_timestamp(BS_BL_START);

    // deal with any static constructors
    dprintf(SPEW, "calling constructors ");
    call_constructors();

    // bring up the kernel heap
    dprintf(SPEW, "initializing heap ");
    heap_init();

    __stack_chk_guard_setup();

    // initialize the threading system
    dprintf(SPEW, "initializing threads ");
    thread_init();

    // initialize the dpc system
    dprintf(SPEW, "initializing dpc ");
    dpc_init();

    // initialize kernel timers
    dprintf(SPEW, "initializing timers ");
    timer_init();

#if (!ENABLE_NANDWRITE)
    // create a thread to complete system initialization
    dprintf(SPEW, "creating bootstrap completion thread ");
    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() ");

    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 ");
    platform_init();

    // initialize the target
    dprintf(SPEW, "initializing target ");
    target_init();

    dprintf(SPEW, "calling apps_init() ");
    apps_init();

    return 0;
}

3. bootableootloaderlkappapp.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 ", app->name);

    thr = thread_create(app->name, &app_thread_entry, (void *)app, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE);
    if(!thr)
    {
        return;
    }
    thread_resume(thr);
}


4. bootableootloaderlkappabootaboot.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 ");
    target_display_init(device.display_panel);
    dprintf(SPEW, "Display Init: Done ");
#endif


    target_serialno((unsigned char *) sn_buf);
    dprintf(SPEW,"serial number: %s ",sn_buf);

    memset(display_panel_buf, '', 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 ");
        if (set_download_mode(EMERGENCY_DLOAD))
        {
            dprintf(CRITICAL,"dload mode not supported by target ");
        }
        else
        {
            reboot_device(DLOAD);
            dprintf(CRITICAL,"Failed to reboot into dload mode ");
        }
        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 ");
            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(); // 执行此行,它调用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. ");
    }

    /* 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 ");

    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 ");

    ramdisk = PA(ramdisk);
    dprintf(INFO, "***ByTom B003 ");

    final_cmdline = update_cmdline((const char*)cmdline);
    dprintf(INFO, "***ByTom B004 ");

#if DEVICE_TREE
    dprintf(INFO, "Updating device tree: start ");

    /* Update the Device Tree */
    ret = update_device_tree((void *)tags, final_cmdline, ramdisk, ramdisk_size);
    if(ret)
    {
        dprintf(CRITICAL, "ERROR: Updating Device Tree Failed ");
        ASSERT(0);
    }
    dprintf(INFO, "Updating device tree: done ");
#else
    /* Generating the Atags */
    dprintf(INFO, "***ByTom B005 ");
    generate_atags(tags, final_cmdline, ramdisk, ramdisk_size);
#endif

    dprintf(INFO, "***ByTom B006 ");
    free(final_cmdline);
    dprintf(INFO, "***ByTom B007 ");

#if VERIFIED_BOOT
    /* Write protect the device info */
    dprintf(INFO, "***ByTom B008 ");
    if (target_build_variant_user() && devinfo_present && mmc_write_protect("devinfo", 1))
    {
        dprintf(INFO, "Failed to write protect dev info ");
        ASSERT(0);
    }
#endif

    dprintf(INFO, "***ByTom B009 ");
    /* Perform target specific cleanup */
    target_uninit();

    /* Turn off splash screen if enabled */
#if DISPLAY_SPLASH_SCREEN
    dprintf(INFO, "***ByTom B010 ");
    target_display_shutdown();
#endif


    dprintf(INFO, "booting linux @ %p, ramdisk @ %p (%d), tags/device tree @ %p ",
        entry, ramdisk, ramdisk_size, tags_phys);

    enter_critical_section();
    dprintf(INFO, "***ByTom B011 ");

    /* do any platform specific cleanup before kernel entry */
    platform_uninit();
    dprintf(INFO, "***ByTom B012 ");

    arch_disable_cache(UCACHE);
    dprintf(INFO, "***ByTom B013 ");

#if ARM_WITH_MMU
    arch_disable_mmu();
#endif
    bs_set_timestamp(BS_KERNEL_ENTRY);
    dprintf(INFO, "***ByTom B014 ");

    if (IS_ARM64(kptr))
    {
        dprintf(INFO, "***ByTom B015 ");
        /* Jump to a 64bit kernel */
        scm_elexec_call((paddr_t)kernel, tags_phys);
    }
    else
    {
        dprintf(INFO, "***ByTom B016 ");
        /* Jump to a 32bit kernel */
        entry(0, machtype, (unsigned*)tags_phys);  // 可能跳到kernelarcharmootcompressedhead.S,其中调用了kernelarcharmootcompressedmisc.c函数decompress_kernel()
    }
}
...

APP_START(aboot)
    .init = aboot_init,
APP_END

解压后正式进入内核运行起点,是从文件kernel/arch/arm/kernel/head.S开始,因为连接文件vmlinux.lds里决定的ENTRY(stext)。

head.S包含同目录文件head-common.S,其调用kernelinitmain.c函数start_kernel(),进入到C代码。


附:  kernelinitmain.c函数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 ", 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 "))
        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 ");
    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. ",
            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();
}

另: kernelarcharmootcompressedmisc.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. ");
}


原文地址:https://www.cnblogs.com/liang123/p/6325214.html