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(); // 调用调试串口初始化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启动概览的更多相关文章
- 【Android端 APP 启动时长获取】启动时长获取方案及具体实施
一.什么是启动时长? 1.启动时长一般包括三种场景,分别是:新装包的首次启动时长,冷启动时长.热启动时长 冷启动 和 热启动 : (1)冷启动:当启动应用时,后台没有该程序的进程,此时启动的话系统会分 ...
- Android Studio 无法启动模拟器的一种可能是你装的是Ghost版的系统
我遇到的问题是,打开模拟器,进度条走到最后,突然出现了emulator error,然后模拟器就无法启动(不好意思当时没有截图).我是在Ghost版 win7系统下运行Android Studio 的 ...
- android Activity的启动模式
Android中Activity启动模式详解 在Android中每个界面都是一个Activity,切换界面操作其实是多个不同Activity之间的实例化操作.在Android中Activity的启 ...
- Android Activity的启动过程
文章编辑的太长了,请移步我的csdn博客:http://blog.csdn.net/xyh269 Android Activity的启动过程原文链接:http://blog.csdn.net/xyh2 ...
- Android手机app启动的时候第一个Activity必须是MainActivity吗
原文:Android手机app启动的时候第一个Activity必须是MainActivity吗 Android手机APP启动的第一个Activity是可以自己设置的,不是必须的MainActivity ...
- Android 4.2启动代码分析(一)
Android系统启动过程分析 Android系统的框架架构图如下(来自网上): Linux内核启动之后----->就到Android的Init进程 ----->进而启动Android ...
- Cocos2d-x3.3RC0的Android编译Activity启动流程分析
本文将从引擎源代码Jni分析Cocos2d-x3.3RC0的Android Activity的启动流程,以下是具体分析. 1.引擎源代码Jni.部分Java层和C++层代码分析 watermark/2 ...
- Android开机动画启动流程
android开机动画启动流程 从android的Surface Flinger服务启动分析知道,开机动画是在SurfaceFlinger实例通过调用startBootAnim()启动的. 下面我 ...
- Android 跨进程启动Activity黑屏(白屏)的三种解决方案
原文链接:http://www.cnblogs.com/feidu/p/8057012.html 当Android跨进程启动Activity时,过程界面很黑屏(白屏)短暂时间(几百毫秒?).当然从桌面 ...
随机推荐
- 使用EasyNetQ组件操作RabbitMQ消息队列服务
RabbitMQ是一个由erlang开发的AMQP(Advanved Message Queue)的开源实现,是实现消息队列应用的一个中间件,消息队列中间件是分布式系统中重要的组件,主要解决应用耦合, ...
- jQuery ajax中使用serialize()方法提交表单数据示例
<form id="form"> 输入账号 :<input id="name" type="text" name=&quo ...
- RxSwift 系列(八) -- Error Handing Operators
前言 本篇文章我们将学习RxSwift中的错误处理,包括: catchErrorJustReturn catchError retry retry(_:) catchErrorJustReturn 遇 ...
- js求和运算在可变参数的情况下ES3、ES5和ES6的写法区别
//ES3.ES5的写法 function foo(){ var arr = Array.prototype.slice.call(arguments); var sum = 0; arr.forEa ...
- java获取当前系统时间
阿里巴巴推荐 Timestamp d = new Timestamp(System.currentTimeMillis()); 唯一的好处就是除了Timestamp,没有再新建什么了
- WebService之soap类型的服务和rest类型的服务
1.引言 WebService顾名思义就是web服务,web服务主要有两种,一种是基于soap类型的服务,一种是基于rest类型的服务,其中soap类型的服务有两种版本,一种是soap1.1版本,一种 ...
- js中一个对象当做参数传递时候?
高程中讲到:'ECMAScript 中所有函数的参数都是按值传递'. 这就像把值从一个变量复制到另一个变量一样. 那引用类型的值也是像基本类型一样? 直接看栗子一: var person = { na ...
- 基于PHP的对接免费电子面单接口平台的案例-快宝开放平台
一.电子面单对接平台 电子面单对接平台分为两类: 1 .各大快递公司自有的电子面单接口开放平台:对接起来麻烦,需要每个快递公司分别调试接口,费时费力. 2 .第三方快递开放平台:如快宝开放平台(htt ...
- 75. Sort Colors(中等)
Given an array with n objects colored red, white or blue, sort them so that objects of the same colo ...
- python笔记三(list、tuple)
一.list list的增删改查 #增, classmates.append("nadech") #在末尾追加一个元素 classmates.insert(1,"agui ...