这篇文章介绍了MDM平台的Little Kernel(LK)的启动流程。Little Kernel的作用是在启动的时候初始化硬件,从存储器中载入Linux内核和ramdisk到RAM中,配置初始化寄存器和命令行参数,最后跳转到内核中运行
LK的代码在apps_proc\bootable\bootloader\lk目录
从C程序入口开始讲起kmain
target_init:初始化flash参数,以及分区表
qpic_nand_init(&config);//初始化flash 参数,如page size等
ptable_init(&flash_ptable);
smem_ptable_init();//读取分区表
smem_add_modem_partitions(&flash_ptable);
update_ptable_names();
flash_set_ptable(&flash_ptable);
支持的flash型号在supported_flash 定义,通过flash id索引,配置了pagesize 等参数
apps_init:加载kernel到ram,并配置命令行,跳转到kernel
调用 aboot_init,boot_into_fastboot boot_into_recovery flag确认进入fastboot 模式还是recovery 模式还是正常启动
check_reboot_mode 检查重启原因,查看是否是升级或者其他需要进入recovery模式的操作
unsigned check_reboot_mode(void)
{
uint32_t restart_reason = 0;
/* Read reboot reason and scrub it */
restart_reason = readl(RESTART_REASON_ADDR);//读取寄存器值
writel(0x00, RESTART_REASON_ADDR);
return restart_reason;
}
该寄存器值在重启时调用sys_reboot ( apps_proc\system\core\powerapp/powerapp.c) 中写该寄存器,标明是否需要进入recovery 模式
fastboot 模式
static void create_fastboot_mode()
{
fastboot_register("oem xxx", cmd_oem_xxx);//定义OEM命令
/* 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());打开usb通信,建立新的线程处理fastboot 命令
}
recovery模式 正常启动
调用boot_system_normal(), 通过flag boot_into_recovery会决定传递给kernel的cmdline挂载哪个fs recoveryfs or system
boot_linux_from_flash()
{
if(!boot_into_recovery) 通过flag确认 使用哪个kernel
{
ptn = ptable_find(ptable, "boot");
if (ptn == NULL) {
dprintf(CRITICAL, "ERROR: No boot partition found\n");
return -1;
}
}
else
{
ptn = ptable_find(ptable, "recovery");
if (ptn == NULL) {
dprintf(CRITICAL, "ERROR: No recovery partition found\n");
return -1;
}
}
flash_read(ptn, offset, buf, page_size) //读取 boot.img 的第一个page,也就是header
hdr->kernel_addr = VA((addr_t)(hdr->kernel_addr));
hdr->ramdisk_addr = VA((addr_t)(hdr->ramdisk_addr));
hdr->tags_addr = VA((addr_t)(hdr->tags_addr));
flash_read(ptn, offset, (void *)hdr->kernel_addr, kernel_actual)//加载kernel到ram中,地址为kernel_addr
flash_read(ptn, offset + dt_entry.offset, (void *)hdr->tags_addr, dt_entry.size)//
加载dts到ram中,地址为tags_addr
boot_linux((void *)hdr->kernel_addr, (void *)hdr->tags_addr,
(const char *)hdr->cmdline, board_machtype(),
(void *)hdr->ramdisk_addr, hdr->ramdisk_size);//启动kernel
}
上面提到读取boot.img的header, 在bootable/bootloader/lk/app/aboot/bootimg.h 定义,也包括了boot.img的构成
struct boot_img_hdr
{
unsigned char magic[BOOT_MAGIC_SIZE];
unsigned kernel_size; /* size in bytes */
unsigned kernel_addr; /* physical load addr */
unsigned ramdisk_size; /* size in bytes */
unsigned ramdisk_addr; /* physical load addr */
unsigned second_size; /* size in bytes */
unsigned second_addr; /* physical load addr */
unsigned tags_addr; /* physical addr for kernel tags */
unsigned page_size; /* flash page size we assume */
unsigned dt_size; /* device_tree in bytes */
unsigned unused; /* future expansion: should be 0 */
unsigned char name[BOOT_NAME_SIZE]; /* asciiz product name */
unsigned char cmdline[BOOT_ARGS_SIZE];
unsigned id[8]; /* timestamp / checksum / sha1 / etc */
};
boot.img 构成
** +-----------------+
** | boot header | 1 page
** +-----------------+
** | kernel | n pages
** +-----------------+
** | ramdisk | m pages
** +-----------------+
** | second stage | o pages
** +-----------------+
** | device tree | p pages
** +-----------------+
结合实际的image,可以分析出header的各个参数
magic:41 4E 44 52 4F 49 44 21
kernel size 00 3D 8F 30 kernel addr 08 00 80 00
ram size 0 ram addr 08 00 80 00
second size 0 second addr 08 f0 00 00
tag addr 81 E0 00 00 page size 08 00
dt size 07 68 00
boot_linux最后更新了cmdline,并刷新到dts中,跳转到kernel
final_cmdline = update_cmdline((const char*)cmdline);
update_device_tree((void *)tags,(const char *)final_cmdline, ramdisk, ramdisk_size);
entry(0, machtype, (unsigned*)tags_phys);