1. LK 代码结构
app/ 应用相关
arch/ arm 体系
dev/ 设备相关
include/ 头文件
kernel/ lk系统相关
platform/ 相关驱动
projiect/ makefile文件
scripts/ Jtag 脚本
target/ 具体板子相关
2. LK流程分析
lk/arch/arm/ssystem-onesegment.ld 连接文件中 ENTRY(_start)指定 LK 从_start 函数开始,_start 在 lk/arch/start.S 。
start.S主要做一些基本的CPU的初始化再通过 bl lk_main ;跳转到 C代码中。
lk/top/main.c中有lk_main()函数的定义
lk_main() //lk/top/main.c
bootstrap2()
apps_init(); //lk/app/app.c
app->init(app); //会调用到lk/app/atc_boot/boot_kernel.c中的boot_kernel_init
start_app(app); //会调用到lk/app/atc_boot/boot_kernel.c中的boot_linux_from_emmc
theKernel (FDT_LOAD_ADDR_PHYS, 0, 0); //启动kernel
3. 启动流程详解
/* called from arch code */
void lk_main(ulong arg0, ulong arg1, ulong arg2, ulong arg3)
{
uint32_t cpacr = ARM64_READ_SYSREG(cpacr_el1);
// save the boot args
lk_boot_args[0] = arg0;
lk_boot_args[1] = arg1;
lk_boot_args[2] = arg2;
lk_boot_args[3] = arg3;
lk_boot_time = current_time();
// get us into some sort of thread context
thread_init_early(); //初始化LK的线程系统
// early arch stuff
lk_primary_cpu_init_level(LK_INIT_LEVEL_EARLIEST, LK_INIT_LEVEL_ARCH_EARLY - 1);
arch_early_init(); //架构相关早期初始化,如使能MMU,cache等等)
// do any super early platform initialization
lk_primary_cpu_init_level(LK_INIT_LEVEL_ARCH_EARLY, LK_INIT_LEVEL_PLATFORM_EARLY - 1);
platform_early_init(); //平台相关早期初始化,如获取板级信息,初始化时钟、中断、定时器等等
// do any super early target initialization
lk_primary_cpu_init_level(LK_INIT_LEVEL_PLATFORM_EARLY, LK_INIT_LEVEL_TARGET_EARLY - 1);
target_early_init(); //初始化目标,其中只初始化了串口
// bring up the kernel heap
lk_primary_cpu_init_level(LK_INIT_LEVEL_TARGET_EARLY, LK_INIT_LEVEL_HEAP - 1);
dprintf(SPEW, "initializing heap\n");
heap_init(); //堆初始化,用于malloc等函数的内存分配
// deal with any static constructors
dprintf(SPEW, "calling constructors\n");
call_constructors(); //构造函数相关初始化
// create a thread to complete system initialization
//新建线程入口函数 bootstrap2, 用于boot工作(重点)
dprintf(SPEW, "creating bootstrap completion thread\n");
thread_t *t = thread_create("bootstrap2", &bootstrap2, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE * 3);
thread_set_pinned_cpu(t, 0);
thread_detach(t);
thread_resume(t);
// become the idle thread and enable interrupts to start the scheduler
thread_become_idle(); //将本线程切换至idle状态
}
static int bootstrap2(void *arg)
{
// initialize the rest of the platform
dprintf(SPEW, "initializing platform\n");
lk_primary_cpu_init_level(LK_INIT_LEVEL_ARCH, LK_INIT_LEVEL_PLATFORM - 1);
platform_init();
// initialize the target
dprintf(SPEW, "initializing target\n");
lk_primary_cpu_init_level(LK_INIT_LEVEL_PLATFORM, LK_INIT_LEVEL_TARGET - 1);
target_init();
dprintf(SPEW, "calling apps_init()\n");
lk_primary_cpu_init_level(LK_INIT_LEVEL_TARGET, LK_INIT_LEVEL_APPS - 1);
apps_init(); //初始化APP,启动内核
return 0;
}
void apps_init(void)
{
const struct app_descriptor *app;
/* call all the init routines */ //apps_start和apps_end都是在lk/app/app.ld文件中指定的, 表示apps段
for (app = &__apps_start; app != &__apps_end; app++) {
if (app->init)
app->init(app); //调用到lk/app/atc_boot/boot_kernel.c中的boot_kernel_init
}
/* 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); //调用到lk/app/atc_boot/boot_kernel.c中的boot_linux_from_emmc
}
}
}
static void start_app(const struct app_descriptor *app)
{
uint32_t stack_size = (app->flags & APP_FLAG_CUSTOM_STACK_SIZE) ? app->stack_size : DEFAULT_STACK_SIZE;
printf("starting app %s\n", app->name);
thread_t *t = thread_create(app->name, &app_thread_entry, (void *)app, DEFAULT_PRIORITY, stack_size);
thread_detach(t);
thread_resume(t);
}
static int app_thread_entry(void *arg)
{
const struct app_descriptor *app = (const struct app_descriptor *)arg;
app->entry(app, NULL);
return 0;
}
/* lk/app/atc_boot/boot_kernel.c */
/* jump to kernel */
static void boot_linux_from_emmc(const struct app_descriptor *app, void *args)
{
load_image_from_bootimg(KERNEL_LOAD_ADDR, BOOTIMG_IMAGEGZ);
load_image_from_bootimg(ROOTFS_LOAD_ADDR, BOOTIMG_RAMDISK);
pr_time("[lk time] start jump to kernel at %ums\n", get_current_time_ms());
cleanup_before_linux();
/* simple jump from 64bit LK to 64bit kernel */
void (*theKernel)(unsigned long fdtAddr, unsigned long x1, unsigned long x2);
theKernel = (void (*)(unsigned long, unsigned long, unsigned long))(KERNEL_LOAD_ADDR_PHYS);
theKernel (FDT_LOAD_ADDR_PHYS, 0, 0);
#endif
}
附录
/* lk/app/app.ld */
SECTIONS {
.apps : {
__apps_start = .;
KEEP (*(.apps))
__apps_end = .;
}
}
INSERT AFTER .rodata;
/* lk/app/atc_boot/boot_kernel.c */
APP_START(atc_boot)
.init = boot_kernel_init,
.entry = boot_linux_from_emmc,
APP_END
#define APP_START(appname) const struct app_descriptor _app_##appname __ALIGNED(sizeof(void *)) __SECTION(".apps") = { .name = #appname,
#define APP_END };
/* 由APP_START(atc_boot)得到如下结构体: */
const struct app_descriptor _app_atc_boot __ALIGNED(sizeof(void *)) __SECTION(".apps") = {
.name = atc_boot,
.init = boot_kernel_init,
.entry = boot_linux_from_emmc,
}