zoukankan      html  css  js  c++  java
  • 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. ");
    }


  • 相关阅读:
    Python基础之只接收关键字参数的函数
    Python基础之可接受任意数量参数的函数
    Django基础之创建admin账号
    GIT版本控制工具
    全站导航
    python中对url编码解码处理
    VUE安装及初始化报错解决办法
    使用Appium+python爬取手机App
    python发送QQ邮件
    docker部署flask项目
  • 原文地址:https://www.cnblogs.com/liang123/p/6325214.html
Copyright © 2011-2022 走看看