高通MDM平臺-LK

1、前言

這篇文章介紹了MDM平臺的Little Kernel(LK)的啓動流程。Little Kernel的作用是在啓動的時候初始化硬件,從存儲器中載入Linux內核和ramdisk到RAM中,配置初始化寄存器和命令行參數,最後跳轉到內核中運行

2、LK

2.1代碼路徑

LK的代碼在apps_proc\bootable\bootloader\lk目錄

2.2代碼概述

從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);

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章