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();   // 调用调试串口初始化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(); // 执行此行,它调用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,其中调用了kernel\arch\arm\boot\compressed\misc.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,其调用kernel\init\main.c函数start_kernel(),进入到C代码。

附:  kernel\init\main.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\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启动概览的更多相关文章

  1. 【Android端 APP 启动时长获取】启动时长获取方案及具体实施

    一.什么是启动时长? 1.启动时长一般包括三种场景,分别是:新装包的首次启动时长,冷启动时长.热启动时长 冷启动 和 热启动 : (1)冷启动:当启动应用时,后台没有该程序的进程,此时启动的话系统会分 ...

  2. Android Studio 无法启动模拟器的一种可能是你装的是Ghost版的系统

    我遇到的问题是,打开模拟器,进度条走到最后,突然出现了emulator error,然后模拟器就无法启动(不好意思当时没有截图).我是在Ghost版 win7系统下运行Android Studio 的 ...

  3. android Activity的启动模式

    Android中Activity启动模式详解   在Android中每个界面都是一个Activity,切换界面操作其实是多个不同Activity之间的实例化操作.在Android中Activity的启 ...

  4. Android Activity的启动过程

    文章编辑的太长了,请移步我的csdn博客:http://blog.csdn.net/xyh269 Android Activity的启动过程原文链接:http://blog.csdn.net/xyh2 ...

  5. Android手机app启动的时候第一个Activity必须是MainActivity吗

    原文:Android手机app启动的时候第一个Activity必须是MainActivity吗 Android手机APP启动的第一个Activity是可以自己设置的,不是必须的MainActivity ...

  6. Android 4.2启动代码分析(一)

    Android系统启动过程分析 Android系统的框架架构图如下(来自网上):   Linux内核启动之后----->就到Android的Init进程 ----->进而启动Android ...

  7. Cocos2d-x3.3RC0的Android编译Activity启动流程分析

    本文将从引擎源代码Jni分析Cocos2d-x3.3RC0的Android Activity的启动流程,以下是具体分析. 1.引擎源代码Jni.部分Java层和C++层代码分析 watermark/2 ...

  8. Android开机动画启动流程

    android开机动画启动流程   从android的Surface Flinger服务启动分析知道,开机动画是在SurfaceFlinger实例通过调用startBootAnim()启动的. 下面我 ...

  9. Android 跨进程启动Activity黑屏(白屏)的三种解决方案

    原文链接:http://www.cnblogs.com/feidu/p/8057012.html 当Android跨进程启动Activity时,过程界面很黑屏(白屏)短暂时间(几百毫秒?).当然从桌面 ...

随机推荐

  1. 使用EasyNetQ组件操作RabbitMQ消息队列服务

    RabbitMQ是一个由erlang开发的AMQP(Advanved Message Queue)的开源实现,是实现消息队列应用的一个中间件,消息队列中间件是分布式系统中重要的组件,主要解决应用耦合, ...

  2. jQuery ajax中使用serialize()方法提交表单数据示例

    <form id="form"> 输入账号 :<input id="name" type="text" name=&quo ...

  3. RxSwift 系列(八) -- Error Handing Operators

    前言 本篇文章我们将学习RxSwift中的错误处理,包括: catchErrorJustReturn catchError retry retry(_:) catchErrorJustReturn 遇 ...

  4. js求和运算在可变参数的情况下ES3、ES5和ES6的写法区别

    //ES3.ES5的写法 function foo(){ var arr = Array.prototype.slice.call(arguments); var sum = 0; arr.forEa ...

  5. java获取当前系统时间

    阿里巴巴推荐 Timestamp d = new Timestamp(System.currentTimeMillis()); 唯一的好处就是除了Timestamp,没有再新建什么了

  6. WebService之soap类型的服务和rest类型的服务

    1.引言 WebService顾名思义就是web服务,web服务主要有两种,一种是基于soap类型的服务,一种是基于rest类型的服务,其中soap类型的服务有两种版本,一种是soap1.1版本,一种 ...

  7. js中一个对象当做参数传递时候?

    高程中讲到:'ECMAScript 中所有函数的参数都是按值传递'. 这就像把值从一个变量复制到另一个变量一样. 那引用类型的值也是像基本类型一样? 直接看栗子一: var person = { na ...

  8. 基于PHP的对接免费电子面单接口平台的案例-快宝开放平台

    一.电子面单对接平台 电子面单对接平台分为两类: 1 .各大快递公司自有的电子面单接口开放平台:对接起来麻烦,需要每个快递公司分别调试接口,费时费力. 2 .第三方快递开放平台:如快宝开放平台(htt ...

  9. 75. Sort Colors(中等)

    Given an array with n objects colored red, white or blue, sort them so that objects of the same colo ...

  10. python笔记三(list、tuple)

    一.list list的增删改查 #增, classmates.append("nadech") #在末尾追加一个元素 classmates.insert(1,"agui ...