栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

【SemiDrive源码分析】【X9芯片启动流程】29 - AP1 Android Bootloader启动流程分析(加载并跳转kernel)

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【SemiDrive源码分析】【X9芯片启动流程】29 - AP1 Android Bootloader启动流程分析(加载并跳转kernel)

【SemiDrive源码分析】【X9芯片启动流程】29 - AP1 Android Bootloader启动流程分析(加载并跳转kernel)
  • 一、Android Bootloader
    • 1.1 汇编入口 start.S:跳转 lk_main() 函数
    • 1.2 lk_main() 函数:创建并运行 bootstrap2 线程
    • 1.3 .lk_init段代码任务分析
    • 1.4 .app段代码任务分析
      • 1.4.1 _app_shell 命令
      • 1.4.2 _app_bootloader 代码分析: 根据镜像头信息,解析是否跳转qnxandroidlinux,此处我们正式加载 kernel镜像跳转android
      • 1.4.3 BOOT Pin Map


本 SemiDrive源码分析 之 Yocto源码分析 系列文章汇总如下:

  1. 《【SemiDrive源码分析】【Yocto源码分析】01 - yocto/base目录源码分析(编译环境初始化流程)》
  2. 《【SemiDrive源码分析】【Yocto源码分析】02 - yocto/meta-openembedded目录源码分析》
  3. 《【SemiDrive源码分析】【Yocto源码分析】03 - yocto/meta-semidrive目录及Yocto Kernel编译过程分析(上)》
  4. 《【SemiDrive源码分析】【Yocto源码分析】04 - yocto/meta-semidrive目录及Yocto Kernel编译过程分析(下)》
  5. 《【SemiDrive源码分析】【Yocto源码分析】05 - 找一找Yocto Kernel编译过程中所有Task的源码在哪定义的呢?》
  6. 《【SemiDrive源码分析】【Yocto源码分析】06 - Kernel编译生成的Image.bin、Image_nobt.dtb、modules.tgz 这三个文件分别是如何生成的?》
  7. 《【SemiDrive源码分析】【Yocto源码分析】07 - core-image-base-x9h_ref_serdes.rootfs.ext4 文件系统是如何生成的》
  8. 《【SemiDrive源码分析】【X9芯片启动流程】08 - X9平台 lk 目录源码分析 之 目录介绍》
  9. 《【SemiDrive源码分析】【X9芯片启动流程】09 - X9平台系统启动流程分析》
  10. 《【SemiDrive源码分析】【X9芯片启动流程】10 - BareMetal_Suite目录R5 DIL.bin 引导程序源代码分析》
  11. 《【SemiDrive源码分析】【X9芯片启动流程】11 - freertos_safetyos目录Cortex-R5 DIL2.bin 引导程序源代码分析》
  12. 《【SemiDrive源码分析】【X9芯片启动流程】12 - freertos_safetyos目录Cortex-R5 DIL2.bin 之 sdm_display_init 显示初始化源码分析》
  13. 《【SemiDrive源码分析】【X9芯片驱动调试】13 - GPIO 配置方法》
  14. 《【SemiDrive源码分析】【X9芯片启动流程】14 - freertos_safetyos目录Cortex-R5 SafetyOS/RTOS工作流程分析》
  15. 《【SemiDrive源码分析】【X9芯片启动流程】15 - freertos_safetyos目录 R5 SafetyOS 之 tcpip_init() 代码流程分析》
  16. 《【SemiDrive源码分析】【X9 Audio音频模块分析】16 - 音频模块框图及硬件原理图分析》
  17. 《【SemiDrive源码分析】【X9芯片启动流程】17 - R5 SafetyOS 之 LK_INIT_LEVEL_PLATFORM 阶段代码流程分析(上)dcf_init 核间通信初始化》
  18. 《【SemiDrive源码分析】【X9芯片启动流程】18 - R5 SafetyOS 之 LK_INIT_LEVEL_PLATFORM 阶段代码流程(下)启动QNX、Android》
  19. 《【SemiDrive源码分析】【X9芯片启动流程】19 - MailBox 核间通信机制介绍(理论篇)》
  20. 《【SemiDrive源码分析】【X9芯片启动流程】20 - MailBox 核间通信机制介绍(代码分析篇)之 MailBox for RTOS 篇》
  21. 《【SemiDrive源码分析】【X9芯片启动流程】21 - MailBox 核间通信机制介绍(代码分析篇)之 Mailbox for Linux 篇》
  22. 《【SemiDrive源码分析】【X9芯片启动流程】22 - MailBox 核间通信机制介绍(代码分析篇)之 RPMSG-VIRTIO Kernel 篇》
  23. 《【SemiDrive源码分析】【X9芯片启动流程】23 - MailBox 核间通信机制介绍(代码分析篇)之 RPMSG-IPCC Kernel 篇》
  24. 《【SemiDrive源码分析】【X9芯片启动流程】24 - MailBox 核间通信机制相关寄存器介绍》
  25. 《【SemiDrive源码分析】【X9芯片启动流程】25 - MailBox 核间通信机制介绍(代码分析篇)之 RPMSG-IPCC RTOS & QNX篇》
  26. 《【SemiDrive源码分析】【X9芯片启动流程】26 - R5 SafetyOS 之 LK_INIT_LEVEL_TARGET 阶段代码流程分析(TP Drvier、Audio Server初始化)》
  27. 《【SemiDrive源码分析】【X9芯片启动流程】27 - AP1 Android Preloader启动流程分析(加载atf、tos、bootloader镜像后进入BL31环境)》
  28. 《【SemiDrive源码分析】【X9芯片启动流程】28 - AP1 Android SMC 指令进入 EL3 环境执行 ATF 镜像(加载并跳转 bootloader)》
  29. 《【SemiDrive源码分析】【X9芯片启动流程】29 - AP1 Android Bootloader启动流程分析(加载并跳转kernel)》
    .
  30. 《【SemiDrive源码分析】【X9芯片启动流程】28 - MailBox 核间通信机制介绍(代码分析篇)之 Property篇》
  31. 《【SemiDrive源码分析】【X9芯片启动流程】29 - MailBox 核间通信机制介绍(代码分析篇)之 RPCall篇》
  32. 《【SemiDrive源码分析】【X9芯片启动流程】30 - MailBox 核间通信机制介绍(代码分析篇)之 Notify篇》
  33. 《【SemiDrive源码分析】【X9芯片启动流程】31 - MailBox 核间通信机制介绍(代码分析篇)之 Socket篇》
  34. 《【SemiDrive源码分析】【X9芯片启动流程】32 - MailBox 核间通信机制介绍(代码分析篇)之 /dev/vircan篇》


我们前面看到:

AP1 preloader 在触发 AP2 watchdog 后,接着从 eMMC 中加载 ATF,TOS,bootloader,
然后 进入 ATF,由 ATF 切换到 non-secure world 运行 bootloader,
bootloader 从 eMMC 中加载 kernel, dtb 等镜像并运行。

本文我们来看下 bootloader 的启动流程。

由于RTOS 的存在,传统高通 Android中很多SBL、preloader、bootloader 的代码均被放入 rtos 中执行了,
所以 preloder、bootloader 中基本没啥功能,
最大的作用还是 preloader 加载 ATF,ATF 加载bootloader,bootloader加载 kernel,
所以代码流程估计也没啥好写的,我们来看看吧。


一、Android Bootloader 1.1 汇编入口 start.S:跳转 lk_main() 函数

从 system-onesegment-sd.ld 可以看出,bootloader 使用的代码和 preloader 是一样的,都是 start.s,然后bl lk_main()
这种启动汇编代码,前面我分析的太多了,就不细写了,没啥意义,有兴趣的兄弟自行分析。

# buildsystemrtoslk_bootbuild-ivi_bootloader_x9_plus_ref_serdessystem-onesegment-sd.ld
OUTPUT_FORMAT("elf64-littleaarch64", "elf64-bigaarch64", "elf64-littleaarch64")
OUTPUT_ARCH(aarch64)

ENTRY(_start)
SECTIONS
{
    . = 0xffff000000000000 + 0;
    . = 0xffff000000000000 + 0x59800000;
    
    

# buildsystemrtoslkarcharm64start.S
FUNCTION(_start)
	...... 省略.......
    bl  lk_main
    b   .

1.2 lk_main() 函数:创建并运行 bootstrap2 线程

整套代码跟 preloader 走的一模一样,没啥好分析,详细看注释。

# buildsystemrtoslktopmain.c

void lk_main(ulong arg0, ulong arg1, ulong arg2, ulong arg3)
{
    // save the boot args
    lk_boot_args[0] = arg0;
    lk_boot_args[1] = arg1;
    lk_boot_args[2] = arg2;
    lk_boot_args[3] = arg3;

    // 1. 配置当前线程为bootstrap,优先级为HIGHEST_PRIORITY
    thread_init_early();
    // 2. 触发 LK_INIT_LEVEL_EARLIEST 到 LK_INIT_LEVEL_ARCH_EARLY - 1等级的任务运行
    lk_primary_cpu_init_level(LK_INIT_LEVEL_EARLIEST, LK_INIT_LEVEL_ARCH_EARLY - 1);
    // 3. 切换CPU 从EL3 到 EL1,初始化MMU 
    arch_early_init();
	// 4. 触发 LK_INIT_LEVEL_ARCH_EARLY到 LK_INIT_LEVEL_PLATFORM_EARLY- 1等级的任务运行
    // do any super early platform initialization
    lk_primary_cpu_init_level(LK_INIT_LEVEL_ARCH_EARLY, LK_INIT_LEVEL_PLATFORM_EARLY - 1);
    // 5. 串口初始化、gic中断初始、通过psci_call 启动剩余的CPU
    platform_early_init();

    // 6. 触发 LK_INIT_LEVEL_PLATFORM_EARLY到 LK_INIT_LEVEL_TARGET_EARLY - 1等级的任务运行
    lk_primary_cpu_init_level(LK_INIT_LEVEL_PLATFORM_EARLY, LK_INIT_LEVEL_TARGET_EARLY - 1);
    target_early_init();	//空函数

    dprintf(INFO, "nwelcome to lk/MPnn");
    dprintf(INFO, "boot args 0x%lx 0x%lx 0x%lx 0x%lxn",  lk_boot_args[0], lk_boot_args[1], lk_boot_args[2], lk_boot_args[3]);

    // 7. 触发 LK_INIT_LEVEL_TARGET_EARLY到 LK_INIT_LEVEL_HEAP - 1等级的任务运行
    lk_primary_cpu_init_level(LK_INIT_LEVEL_TARGET_EARLY, LK_INIT_LEVEL_HEAP - 1);
    dprintf(SPEW, "initializing heapn");
    // 8. 初始化堆Heap
    heap_init();
	// 9. 运行 .ctors 段中的函数
    // deal with any static constructors
    dprintf(SPEW, "calling constructorsn");
    call_constructors();
	// 10. 触发 LK_INIT_LEVEL_HEAP到 LK_INIT_LEVEL_KERNEL-1等级的任务运行
    // initialize the kernel
    lk_primary_cpu_init_level(LK_INIT_LEVEL_HEAP, LK_INIT_LEVEL_KERNEL - 1);
    // 11. 初始化多线程、初始化时钟、初始化write_port_list中的port口
    kernel_init();
	// 12. 触发 LK_INIT_LEVEL_KERNEL到 LK_INIT_LEVEL_THREADING -1等级的任务运行
    lk_primary_cpu_init_level(LK_INIT_LEVEL_KERNEL, LK_INIT_LEVEL_THREADING - 1);

	// 13. 创建线程 bootstrap2 然后运行
    // create a thread to complete system initialization
    dprintf(SPEW, "creating bootstrap completion threadn");
    thread_t *t = thread_create("bootstrap2", &bootstrap2, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE);
    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();
}


1.3 .lk_init段代码任务分析

下面是 bootloader 阶段的 TASK 任务,我看了下,没啥重要的函数,没啥好分析,直接跳过。

# buildsystemrtoslk_bootbuild-ivi_bootloader_x9_plus_ref_serdeslk.elf.map
.lk_init        0xffff000059851a40       0xd8 load address 0x0000000059851a40
                0xffff000059851a40                __lk_init = .
 *(.lk_init)
 .lk_init       0xffff000059851a40       0x18 lk_boot/build-ivi_bootloader_x9_plus_ref_serdes/lk_boot/platform/kunlun/ap1.mod.o
                0xffff000059851a40                _init_struct_demo
 .lk_init       0xffff000059851a58       0x48 lk_boot/build-ivi_bootloader_x9_plus_ref_serdes/lk_boot/chipdev/interrupt/arm_gic.mod.o
                0xffff000059851a58                _init_struct_arm_gic_resume_cpu
                0xffff000059851a70                _init_struct_arm_gic_suspend_cpu
                0xffff000059851a88                _init_struct_arm_gic_init_percpu
 .lk_init       0xffff000059851aa0       0x18 lk_boot/build-ivi_bootloader_x9_plus_ref_serdes/lk_boot/hal/crypto_hal/.mod.o
                0xffff000059851aa0                _init_struct_cryto_init
 .lk_init       0xffff000059851ab8       0x18 lk_boot/build-ivi_bootloader_x9_plus_ref_serdes/lk/lib/version.mod.o
                0xffff000059851ab8                _init_struct_version
 .lk_init       0xffff000059851ad0       0x18 lk_boot/build-ivi_bootloader_x9_plus_ref_serdes/lk_boot/platform/kunlun/common.mod.o
                0xffff000059851ad0                _init_struct_nocache
 .lk_init       0xffff000059851ae8       0x30 lk_boot/build-ivi_bootloader_x9_plus_ref_serdes/lk/kernel/vm.mod.o
                0xffff000059851ae8                _init_struct_vm
                0xffff000059851b00                _init_struct_vm_preheap
                0xffff000059851b18                __lk_init_end = .

1.4 .app段代码任务分析
# buildsystemrtoslk_bootbuild-ivi_bootloader_x9_plus_ref_serdeslk.elf.map
.apps           0xffff0000598519f0       0x50 load address 0x00000000598519f0
                0xffff0000598519f0                __apps_start = .
 *(.apps)
 .apps          0xffff0000598519f0       0x28 lk_boot/build-ivi_bootloader_x9_plus_ref_serdes/lk/app/shell.mod.o
                0xffff0000598519f0                _app_shell
 .apps          0xffff000059851a18       0x28 lk_boot/build-ivi_bootloader_x9_plus_ref_serdes/lk_boot/application/system/bootloader.mod.o
                0xffff000059851a18                _app_bootloader
                0xffff000059851a40                __apps_end = .

从 .app 段可以看出,主要是 shell 和 bootloadr 两个app,我们先来看下 shell 支持哪些命令

1.4.1 _app_shell 命令

commands 段中,惟一一个有作用的就是 _cmd_block_bootloader,其他的基本没啥意义,不分析。

# buildsystemrtoslk_bootbuild-ivi_bootloader_x9_plus_ref_serdeslk.elf.map
.commands       0xffff0000598535f8      0x120 load address 0x00000000598535f8
                0xffff0000598535f8                __commands_start = .
 *(.commands)
 .commands      0xffff0000598535f8       0x18 lk_boot/build-ivi_bootloader_x9_plus_ref_serdes/lk_boot/application/system/bootloader.mod.o
                0xffff0000598535f8                _cmd_block_bootloader
 .commands      0xffff000059853610       0x18 lk_boot/build-ivi_bootloader_x9_plus_ref_serdes/lk_boot/chipdev/fuse_ctrl.mod.o
                0xffff000059853610                _cmd_block_fuse
 .commands      0xffff000059853628       0x18 lk_boot/build-ivi_bootloader_x9_plus_ref_serdes/lk/kernel.mod.o
                0xffff000059853628                _cmd_block_kernel
 .commands      0xffff000059853640       0x18 lk_boot/build-ivi_bootloader_x9_plus_ref_serdes/lk/lib/version.mod.o
                0xffff000059853640                _cmd_block_version
 .commands      0xffff000059853658       0x18 lk_boot/build-ivi_bootloader_x9_plus_ref_serdes/lk/platform.mod.o
                0xffff000059853658                _cmd_block_platform_power
 .commands      0xffff000059853670       0x48 lk_boot/build-ivi_bootloader_x9_plus_ref_serdes/lk/kernel/vm.mod.o
                0xffff000059853670                _cmd_block_pmm
                0xffff000059853688                _cmd_block_vm
                0xffff0000598536a0                _cmd_block_vmm
 .commands      0xffff0000598536b8       0x18 lk_boot/build-ivi_bootloader_x9_plus_ref_serdes/lk/lib/console.mod.o
                0xffff0000598536b8                _cmd_block_help
 .commands      0xffff0000598536d0       0x18 lk_boot/build-ivi_bootloader_x9_plus_ref_serdes/lk_boot/lib/dloader.mod.o
                0xffff0000598536d0                _cmd_block_dloader
 .commands      0xffff0000598536e8       0x18 lk_boot/build-ivi_bootloader_x9_plus_ref_serdes/lk/external/lib/cksum.mod.o
                0xffff0000598536e8                _cmd_block_crc
 .commands      0xffff000059853700       0x18 lk_boot/build-ivi_bootloader_x9_plus_ref_serdes/lk_boot/lib/sdunittest.mod.o
                0xffff000059853700                _cmd_block_unittest
                0xffff000059853718                __commands_end = .

1.4.2 _app_bootloader 代码分析: 根据镜像头信息,解析是否跳转qnxandroidlinux,此处我们正式加载 kernel镜像跳转android

可以看出,在 bootloader app中,主要同样了实现了 fastboot 命令:

# buildsystemrtoslk_bootapplicationsystembootloaderbootloader.c
static void bootloader_entry(const struct app_descriptor *app, void *args){
    _bootloader_main();
}

STATIC_COMMAND("bootloader",  "bootloader",(console_cmd)&bootloader_main)
STATIC_COMMAND("fastboot",  "fastboot", (console_cmd)&fastboot)
STATIC_COMMAND_END(bootloader);

APP_START(bootloader)
.flags = 0,
.entry = bootloader_entry,
APP_END

我们进入 _bootloader_main 函数中看一下,主要工作如下:

  1. 根据 boot pin 来配置启动的设备,如emmc1、ospi1等
  2. 如果支持USB 或 SdCard 启动,如果检测到 /updata/sdrv_update.img 文件,则进入recovery 升级模式
  3. 初始化启动设备,如emmc 的 mmcblk0,根据 btdev_cfg->cfg 中的信息,配置相关的电压、clk、位宽等信息
  4. 读取启动设备分区信息
  5. 如果 boot reason 是 HALT_REASON_SW_UPDATE,则进入 fastboot模式
  6. 申请 block_size 倍数的内存,解析镜像头信息,如果是QNX镜像内则直接 jump_to_kernel(startup_hadr) 进入qnx kernel
  7. 申请 IO 内存空间 fdt,加载 DTB 分区内存,保存在fdt 中
  8. 如果 dtb 分区,不是 flattened device tree ,就直接启动进入android
  9. 如果 dtb分区,不是 xen compatible ,就直接启动进入android
  10. xen是虚拟机 Hypervisor的方式,我们不用这个,先忽略掉
  11. 正式进入启动 android 的代码
  12. 通过调用 smc(SMC_DIS_HCE)的方式,来禁止 HVC CAALL
  13. 申请 block_size 的内存空间,加载并解析 bootimage 镜像
  14. 解析 dtb 设备树,,如果没有设备树分区,说明进入纯 linux 镜像
  15. 检查头信息,主要是检查 sub dtb 如果不是 flattened device tree,说明进入纯 linux 镜像
  16. 解析 dtbo 信息保存在 dtbo_info, 将 dtbo 加入verified_image_list
  17. 通过 verified_images_list 解析部分 cmdline 信息
  18. 拷贝 cmdline 到 cmdline_board 中
  19. 将 cmdline 写入对应的内存中
  20. 配置 kernel 物理地址 entry_p,以及dtb 物理地址 dtb_p
  21. 禁止中断,正式通过 arm_chain_load 来加载 kernel 地址 entry_p 及 dtb 地址 dtb_p
# buildsystemrtoslk_bootapplicationsystembootloaderbootloader.c
int _bootloader_main(void)
{
    int ret = 0, root_type;
    boot_img_hdr *hdr;
    unsigned char *cmdline_board;
    char *storage_type;
    dtbo_img_info dtbo_info;
    partition_device_t *ptdev;
    storage_device_t *storage_dev = NULL;
    boot_device_cfg_t *btdev_cfg = NULL;
    unsigned ramdisk_addr, ramdisk_size;
    uint64_t memory_start[MEMORY_BANKS_MAX] = {0};
    uint64_t memory_size[MEMORY_BANKS_MAX] = {0};
    void *rootfs_buf = NULL;
    void *fdt, *dom0_buf, *dtb_buf, *xen_buf, *kernel;
    unsigned long dtb_p;
    struct list_node verified_images_list;
    struct startup_header  *startup_hdr = NULL;

    uint64_t ret_smc;
    void *entry_p;
	// 1. 根据 boot pin 来配置启动的设备,如emmc1、ospi1等
    uint64_t ddr_size = get_ddr_size();
    uint32_t pin = boot_get_pin();
    if (BOOT_PIN_0 == pin) {
        uint32_t pin_ap = boot_get_pin_scr_overwrite();
        pin = pin_ap;
    }
    btdev_pin_cfg_t *btdev_pin = find_btdev(pin);
    =========> return &btdev_pin_mapping[pin];

	// 2. 如果支持USB或SdCard启动,如果检测到/updata/sdrv_update.img 文件,则进入recovery升级模式
    KEY_NODE_INFO("bootloader start!n");
#if SUPPORT_USB_BOOT || SUPPORT_SDCARD_BOOT
    static FATFS fs;
    ret = recovery_file_detect(&fs);
    if (0 == ret) {
        dprintf(CRITICAL, "recovery file detect success.n");
        KEY_NODE_INFO("start recovery from u disk!n");
        return boot_recovery_file(&fs);
    }
#endif
	
	// 3. 初始化启动设备,如emmc的mmcblk0,根据btdev_cfg->cfg中的信息,配置相关的电压、clk、位宽等信息
    if (btdev_pin) {
        btdev_cfg =  btdev_pin->ap;
    }
    if (btdev_cfg) {
        disk_name = btdev_cfg->disk_name;		// "mmcblk0:"
        storage_type = btdev_cfg->storage_type; // "emmc"
        // 传参 MMC, RES_MSHC_SD1, .mmc_cfg 其中包含电压、clk、位宽等信息
        storage_dev = setup_storage_dev(btdev_cfg->device_type, btdev_cfg->res_idex, (void *)&btdev_cfg->cfg); 
    }

    list_initialize(&verified_images_list);
	// 4. 读取启动设备分区信息
    
    //storage_dev->switch_part(storage, PART_USER);
    
    ptdev = ptdev_setup(storage_dev, 0);
    if (ptdev) {
        ptdev_read_table(ptdev);
    }
    uint32_t block_size =  storage_dev->get_block_size(storage_dev);
	
	// 5. 如果 boot reason 是HALT_REASON_SW_UPDATE,则进入 fastboot模式
    if (is_software_update()) {		
        storage_dev_destroy(storage_dev);
        KEY_NODE_INFO("start fastboot mode!n");
        return fastboot(block_size);
    }
	// 6. 申请 block_size 倍数的内存,解析镜像头信息,如果是QNX镜像内则直接 jump_to_kernel(startup_hadr) 进入qnx kernel
boot_qnx:
    startup_hdr = memalign(block_size, ROUNDUP(sizeof(struct startup_header), block_size));
    
    bootloader_entry_qnx(ptdev, startup_hdr);
    KEY_NODE_INFO("The next os is not qnx!n");
	
	// 7. 申请IO内存空间fdt,加载 DTB 分区内存,保存在fdt中,
    fdt = (void *)_ioaddr(REE_MEMBASE + BOARD_TARS_OFFSET);
    ret = partition_load(ptdev, dtb_part, fdt,BOARD_KERNEL_OFFSET - BOARD_TARS_OFFSET, NULL);
    // 8. 如果 dtb分区,不是flattened device tree ,就直接启动进入android
    ret = fdt_check_header(fdt);
    if (ret) {
        dprintf(INFO, "not a flattened device tree.n");
        goto boot_android;
    }
    // 9. 如果 dtb分区,不是xen compatible ,就直接启动进入android
    if (!check_xen_compatible(fdt)) {
        dprintf(INFO, "no xen compatible found.n");
        goto boot_android;
    }

boot_xen:		// 10. xen是虚拟机 Hypervisor的方式,我们不用这个,先忽略掉
    
    uint64_t dom0_img_sz = DOM0_MEMSIZE;
    dom0_buf = (void *)_ioaddr(memory_start[0] + DOM0_KERNEL_OFFSET);
    ret = partition_load(ptdev, dom0_kernel, dom0_buf, DOM0_MEMSIZE, &dom0_img_sz);
    
    xen_buf = (void *)_ioaddr(memory_start[0] + XEN_IMG_OFFSET);
    ret = partition_load(ptdev, xen_part, xen_buf, HYP_MEMSIZE, NULL);
    fdt = relocate_fdt(fdt, (void *)_ioaddr(memory_start[0] + XEN_FDT_OFFSET));
    if (root_type == 1)
        update_root_dev(ptdev, cmdline_board, dom0_rootfs);
    merge_fdt_bootargs(fdt, (const char *)cmdline_board);
    merge_fdt_bootargs(fdt, vbmeta_cmdline);
    merge_fdt_bootargs(fdt, get_verified_state());
    merge_fdt_bootargs(fdt, get_serialno());
    unsigned long fdt_p = _paddr(fdt);
    unsigned long xen_p = _paddr(xen_buf);
    KEY_NODE_INFO("start xen Hypervisor!n");
    
    hvc(xen_p, fdt_p, 0, 0, 0, 0, 0, 0);
    return 0;

	// 11. 正式进入启动android
boot_android:
	// 12. 通过调用 smc(SMC_DIS_HCE)的方式,来禁止 HVC CAALL
    
    
    
    smc(SMC_DIS_HCE, 0, 0, 0, 0, 0, 0, 0);
    
    // 13. 申请block_size 的内存空间,加载并解析 bootimage 镜像
    hdr = memalign(block_size, ROUNDUP(sizeof(boot_img_hdr), block_size));
    ret = parse_bootimage(hdr, ptdev);
    // 14. 解析 dtb 设备树,,如果没有设备树分区,说明进入纯linux镜像
    ret = partition_load(ptdev, dtb_part, fdt, BOARD_KERNEL_OFFSET - BOARD_TARS_OFFSET, NULL);
    if (ret) {
        dprintf(INFO, "%s dtb load failed.n", dtb_part);
        free(hdr);  goto boot_linux;
    }
	// 15. 检查头信息,主要是检查 sub dtb 如果不是 flattened device tree,说明进入纯linux镜像
    ret = fdt_check_header(fdt);
    if (ret) {
        dprintf(INFO, "sub dtb not a flattened device tree.n");
        free(hdr);  	goto boot_linux;
    }
	// 16. 解析dtbo 信息保存在 dtbo_info, 将dtbo 加入verified_image_list
    memset(&dtbo_info, 0x0, sizeof(dtbo_info));
    if (load_dtbo_image(ptdev, &dtbo_info)  && 
    	!add_verified_image_list(&verified_images_list, dtbo_info.base, dtbo_info.size, dtbo_info.pt_name)) {
        goto error;
    }
    if (!add_verified_image_list(&verified_images_list, fdt, BOARD_KERNEL_OFFSET - BOARD_TARS_OFFSET, dtb_part)) {
        goto error;
    }
	// 17. 通过verified_images_list 解析部分 cmdline 信息
    if (!get_cmdline_by_verified_image(ptdev, &verified_images_list)) {
        goto error;
    }
    free_image_info_list(&verified_images_list);
    if (dtbo_info.base)
        dtbo_find_apply_match(fdt, dtbo_info.base, dtbo_find_hw_match);
    
    ret = fdt_update_memory_range(fdt, HYP_MEMBASE, 0, ddr_size);
	// 18. 没看懂这个 smc 是指什么
    ret_smc = smc(SMCCC_ARCH_FEATURES, SMCCC_ARCH_FEATURES, 0, 0,  0, 0, 0, 0);
    if (ret_smc != SMC_OK) {
        update_dt_psci_method(fdt, "native");
    }

    
    dtb_buf = (void *)_ioaddr((paddr_t)(hdr->tags_addr));
    if (dtb_buf != fdt) {
        dprintf(CRITICAL, "tags addr do not meet memory layout.n");
        
        hdr->tags_addr = REE_MEMBASE + BOARD_TARS_OFFSET;
        dtb_buf = fdt;
    }
    ramdisk_addr = hdr->ramdisk_addr;
    ramdisk_size = hdr->ramdisk_size;
    ret = update_fdt_initrd(dtb_buf, ramdisk_addr, ramdisk_size);

    
    cmdline_board = calloc(1, COMMAND_LINE_PARTITION);
	// 19. 拷贝 cmdline 到 cmdline_board 中
    strcpy((char *)cmdline_board, (const char *)&hdr->cmdline);

    dprintf(INFO, "board cmdline %sn", cmdline_board);

    int slot;
    slot = ptdev_find_boot_slot(ptdev);
    strcat((char *)cmdline_board, " androidboot.slot_suffix=");
    if (slot != SLOT_A  && slot != SLOT_B) {
        dprintf(CRITICAL, "invalid slot, set default slot A, slot:%dn", slot);
        slot = SLOT_A;
    }
    strcat((char *)cmdline_board, suffix_slot[slot]);

#if SUPPORT_BOARDINFO
    hwid = calloc(sizeof(char), 64);
    property = calloc(sizeof(char), 96);

    get_hwid_friendly_name(hwid, 64);
    
    sprintf(property, " androidboot.hwid=%s ", hwid);
    merge_fdt_bootargs(dtb_buf, property);
    free(hwid);
    free(property);
#endif
	// 20. 将 cmdline 写入对应的内存中
    ret = generate_storage_cmdline(cmdline_board, storage_type);
    
    merge_fdt_bootargs(dtb_buf, (const char *)cmdline_board);
    merge_fdt_bootargs(dtb_buf, vbmeta_cmdline);
    merge_fdt_bootargs(dtb_buf, get_verified_state());
    merge_fdt_bootargs(dtb_buf, get_android_boot_mode(ptdev));
    merge_fdt_bootargs(dtb_buf, get_serialno());

    if (is_recovery())
        merge_fdt_bootargs(dtb_buf, "recovery_mode");
	// 21. 配置 kernel 物理地址entry_p,以及 dtb 物理地址 dtb_p 
    
    entry_p = (void *)_ioaddr((paddr_t)(hdr->kernel_addr));
    dtb_p = _paddr(dtb_buf);

	// 22. 禁止中断,正式通过 arm_chain_load 来加载 kernel地址 entry_p 及dtb地址 dtb_p
    KEY_NODE_INFO("start native android!n");
    arch_chain_load(entry_p, dtb_p, 0, 0, 0);
    =====================>
    	arch_disable_ints();
    	target_quiesce();
    	platform_quiesce();
    	entry_pa = (paddr_t)entry;
    	loader_pa = (paddr_t)arm_chain_load;
    	arch_quiesce();
    	void (*loader)(paddr_t entry, ulong, ulong, ulong, ulong) __NO_RETURN = (void *)loader_pa;
    	loader(entry_pa, arg0, arg1, arg2, arg3);
  	<====================
    return 0;

boot_linux:

    smc(SMC_DIS_HCE, 0, 0, 0, 0, 0, 0, 0);
    fdt = (void *)_ioaddr(REE_MEMBASE + BOARD_TARS_OFFSET);
    ret = partition_load(ptdev, alias_dtb, fdt, BOARD_KERNEL_OFFSET - BOARD_TARS_OFFSET, NULL);
    ret = fdt_check_header(fdt);
    kernel = (void *)_ioaddr(REE_MEMBASE + BOARD_KERNEL_OFFSET);
    ret = partition_load(ptdev, alias_kernel_part, kernel,  BOARD_RAMDISK_OFFSET - BOARD_KERNEL_OFFSET, NULL);
    root_type = check_root_type(fdt);

    if (root_type == 0) {
        
        rootfs_buf = (void *)_ioaddr(REE_MEMBASE + BOARD_RAMDISK_OFFSET);
        ret = partition_load(ptdev, alias_rootfs_part, rootfs_buf, ROOTFS_MEMSIZE, NULL);
    }

    memset(&dtbo_info, 0x0, sizeof(dtbo_info));
    if (load_dtbo_image(ptdev, &dtbo_info)  && !add_verified_image_list(&verified_images_list, dtbo_info.base,
                                        dtbo_info.size, dtbo_info.pt_name)) {
        goto error;
    }

    if (!add_verified_image_list(&verified_images_list, fdt,BOARD_KERNEL_OFFSET - BOARD_TARS_OFFSET, alias_dtb)
            || !add_verified_image_list(&verified_images_list, kernel,BOARD_RAMDISK_OFFSET - BOARD_KERNEL_OFFSET, alias_kernel_part)
            || (rootfs_buf   && !add_verified_image_list(&verified_images_list, rootfs_buf, ROOTFS_MEMSIZE,
                                            alias_rootfs_part))) {
        goto error;
    }

    if (!get_cmdline_by_verified_image(ptdev, &verified_images_list)) {
        goto error;
    }

    free_image_info_list(&verified_images_list);

    if (dtbo_info.base)
        dtbo_find_apply_match(fdt, dtbo_info.base, dtbo_find_hw_match);


    
    ret = fdt_update_memory_range(fdt, HYP_MEMBASE, 0, ddr_size);

    if (ret)
        dprintf(CRITICAL, "failed to update memory range.n");


    ret_smc = smc(SMCCC_ARCH_FEATURES, SMCCC_ARCH_FEATURES, 0, 0,
                  0, 0, 0, 0);

    if (ret_smc != SMC_OK) {
        update_dt_psci_method(fdt, "native");
    }

    
    if (root_type == 0)
        ret =  update_fdt_initrd(fdt, REE_MEMBASE + BOARD_RAMDISK_OFFSET,
                                 ROOTFS_MEMSIZE);

    
    cmdline_board = calloc(1, COMMAND_LINE_PARTITION);

    if (!cmdline_board) {
        dprintf(CRITICAL, "alloc cmdline buf failedn");
        goto error;
    }

#if SUPPORT_CMDLINE_PART
    ret = generate_active_part_cmdline(cmdline_board, ptdev);

    if (ret) {
        dprintf(CRITICAL, "failed to get all part.n");
        free(cmdline_board);
        goto error;
    }

#endif

    if (root_type == 1) {
        remove_root_dev_fdt_bootargs(fdt);

        if (is_recovery()) {
            update_root_dev(ptdev, cmdline_board, "recovery");
            merge_fdt_bootargs(fdt, "recovery_mode");
        }
        else {
            update_root_dev(ptdev, cmdline_board, alias_rootfs_part);
        }
    }

    merge_fdt_bootargs(fdt, (const char *)cmdline_board);
    subst_dm_root_device_bootargs(fdt);
    free(cmdline_board);

    if (vbmeta_cmdline)
        free(vbmeta_cmdline);

    if (dm_table)
        free(dm_table);

    if (dtbo_info.base)
        free(dtbo_info.base);

    fdt_pack(fdt);

    arch_clean_cache_range((addr_t)fdt, BOARD_KERNEL_OFFSET);

    
    dtb_p = _paddr(fdt);

    KEY_NODE_INFO("start native linux!n");
    arch_chain_load(kernel, dtb_p, 0, 0, 0);
    return 0;
error:
    dprintf(CRITICAL, "no os is available to bootn");
    return -1;
}

int bootloader_main(int argc, const cmd_args *argv)
{
#ifndef BACKDOOR_DDR
    _bootloader_main();
#endif
    return 0;
}

1.4.3 BOOT Pin Map

有关 pin map ,我也贴一下吧,如下:

# buildsystemrtoslk_bootchipcfggeneratex9_high-plusprojectsserdesboot_device_cfg.h
btdev_pin_cfg_t btdev_pin_mapping[] = {
    [0] = {
        .pin_val = BOOT_PIN_0,
        .ap = &mmc1,
        .safety = &ospi1, },
    [1] = {
        .pin_val = BOOT_PIN_1,
        .ap = &mmc1,
        .safety = &ospi1, },
    [2] = {
        .pin_val = BOOT_PIN_2,
        .ap = &mmc2,
        .safety = &ospi1, },
    [3] = {
        .pin_val = BOOT_PIN_3,
        .ap = &mmc3,
        .safety = &ospi1, },
    [4] = {
        .pin_val = BOOT_PIN_4,
        .ap = &ospi2,
        .safety = &ospi1, },
    [5] = {
        .pin_val = BOOT_PIN_5,
        .ap = NULL,
        .safety = &ospi1, },
    [6] = {
        .pin_val = BOOT_PIN_6,
        .ap = NULL,
        .safety = NULL, },
    [7] = {
        .pin_val = BOOT_PIN_7,
        .ap = NULL,
        .safety = NULL, },
    [8] = {
        .pin_val = BOOT_PIN_8,
        .ap = NULL,
        .safety = NULL, },
    [9] = {
        .pin_val = BOOT_PIN_9,
        .ap = &mmc1,
        .safety = NULL, },
    [10] = {
        .pin_val = BOOT_PIN_10,
        .ap = &mmc2,
        .safety = NULL, },
    [11] = {
        .pin_val = BOOT_PIN_11,
        .ap = &mmc3,
        .safety = NULL, },
    [12] = {
        .pin_val = BOOT_PIN_12,
        .ap = &ospi2,
        .safety = NULL, },
    [13] = {
        .pin_val = BOOT_PIN_13,
        .ap = NULL,
        .safety = NULL, },
    [14] = {
        .pin_val = BOOT_PIN_14,
        .ap = NULL,
        .safety = NULL, },
    [15] = {
        .pin_val = BOOT_PIN_15,
        .ap = NULL,
        .safety = NULL, },
};
# buildsystemrtoslk_bootchipcfggeneratex9_high-plusprojectsserdesboot_device_cfg.h
boot_device_cfg_t mmc1 =
{
    .device_type = MMC,
    .res_idex = RES_MSHC_SD1,
    .disk_name = "mmcblk0:",
    .storage_type = "emmc",
    .cfg = {
        .mmc_cfg = {
            .voltage = MMC_VOL_1_8,
            .max_clk_rate = MMC_CLK_200MHZ,
            .bus_width = MMC_BUS_WIDTH_8BIT,
            .hs400_support = 1,
        },
    },
};
boot_device_cfg_t mmc2 =
{
    .device_type = MMC,
    .res_idex = RES_MSHC_SD2,
    .disk_name = "mmcblk0:",
    .storage_type = "emmc",
    .cfg = {
        .mmc_cfg = {
            .voltage = MMC_VOL_1_8,
            .max_clk_rate = MMC_CLK_100MHZ,
            .bus_width = MMC_BUS_WIDTH_8BIT,
        },
    },
};
boot_device_cfg_t mmc3 =
{
    .device_type = MMC,
    .res_idex = RES_MSHC_SD3,
    .disk_name = "mmcblk1:",
    .storage_type = "sd",
    .cfg = {
        .mmc_cfg = {
            .voltage = MMC_VOL_3_3,
            .max_clk_rate = MMC_CLK_25MHZ,
            .bus_width = MMC_BUS_WIDTH_4BIT,
        },
    },
};
boot_device_cfg_t ospi1 =
{
    .device_type = OSPI,
    .res_idex = RES_OSPI_REG_OSPI1,
    .cfg = {
        .ospi_cfg = {
            .cs = SPI_NOR_CS0,
            .bus_clk = SPI_NOR_CLK_25MHZ,
            .octal_ddr_en = 0,
        },
    },
};
boot_device_cfg_t ospi2 =
{
    .device_type = OSPI,
    .res_idex = RES_OSPI_REG_OSPI2,
    .cfg = {
        .ospi_cfg = {
            .cs = SPI_NOR_CS0,
            .bus_clk = SPI_NOR_CLK_25MHZ,
            .octal_ddr_en = 0,
        },
    },
};
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/972701.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号