IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> 【SemiDrive源码分析】【X9芯片启动流程】29 - AP1 Android Bootloader启动流程分析(加载并跳转kernel) -> 正文阅读

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


本 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 中加载 ATFTOSbootloader
然后 进入 ATF,由 ATF 切换到 non-secure world 运行 bootloader
bootloadereMMC 中加载 kerneldtb 等镜像并运行。

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

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


一、Android Bootloader

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

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

# buildsystem\rtos\lk_boot\build-ivi_bootloader_x9_plus_ref_serdes\system-onesegment-sd.ld
OUTPUT_FORMAT("elf64-littleaarch64", "elf64-bigaarch64", "elf64-littleaarch64")
OUTPUT_ARCH(aarch64)

ENTRY(_start)
SECTIONS
{
    . = 0xffff000000000000 + 0;
    . = 0xffff000000000000 + 0x59800000;
    /* text/read-only data */
    /* set the load address to physical MEMBASE */

# buildsystem\rtos\lk\arch\arm64\start.S
FUNCTION(_start)
	...... 省略.......
    bl  lk_main
    b   .

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

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

# buildsystem\rtos\lk\top\main.c
/* called from arch code */
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/MP\n\n");
    dprintf(INFO, "boot args 0x%lx 0x%lx 0x%lx 0x%lx\n",  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 heap\n");
    // 8. 初始化堆Heap
    heap_init();
	// 9. 运行 .ctors 段中的函数
    // deal with any static constructors
    dprintf(SPEW, "calling constructors\n");
    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 thread\n");
    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 任务,我看了下,没啥重要的函数,没啥好分析,直接跳过。

# buildsystem\rtos\lk_boot\build-ivi_bootloader_x9_plus_ref_serdes\lk.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段代码任务分析

# buildsystem\rtos\lk_boot\build-ivi_bootloader_x9_plus_ref_serdes\lk.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,其他的基本没啥意义,不分析。

# buildsystem\rtos\lk_boot\build-ivi_bootloader_x9_plus_ref_serdes\lk.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 代码分析: 根据镜像头信息,解析是否跳转qnx\android\linux,此处我们正式加载 kernel镜像跳转android

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

# buildsystem\rtos\lk_boot\application\system\bootloader\bootloader.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 来配置启动的设备,如emmc1ospi1
  2. 如果支持USBSdCard 启动,如果检测到 /updata/sdrv_update.img 文件,则进入recovery 升级模式
  3. 初始化启动设备,如emmcmmcblk0,根据 btdev_cfg->cfg 中的信息,配置相关的电压、clk、位宽等信息
  4. 读取启动设备分区信息
  5. 如果 boot reasonHALT_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. 拷贝 cmdlinecmdline_board
  19. cmdline 写入对应的内存中
  20. 配置 kernel 物理地址 entry_p,以及dtb 物理地址 dtb_p
  21. 禁止中断,正式通过 arm_chain_load 来加载 kernel 地址 entry_pdtb 地址 dtb_p
# buildsystem\rtos\lk_boot\application\system\bootloader\bootloader.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. 读取启动设备分区信息
    /* TODO, switch part firstly */
    //storage_dev->switch_part(storage, PART_USER);
    /* Read partition table */
    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));
    /* never return if load qnx correctly*/
    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的方式,我们不用这个,先忽略掉
    /* load dom0 linux */
    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);
    /* load xen */
    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 call */
    hvc(xen_p, fdt_p, 0, 0, 0, 0, 0, 0);
    return 0;

	// 11. 正式进入启动android
boot_android:
	// 12. 通过调用 smc(SMC_DIS_HCE)的方式,来禁止 HVC CAALL
    /* No Hypervisor, disable hvc call by clearing SCR_EL3.HCE */
    /* This smc call shall be implemented by ATF */
    /* If ATF is not persistent, preloader's vector will handle and return simply */
    smc(SMC_DIS_HCE, 0, 0, 0, 0, 0, 0, 0);
    /* Load and parse boot partition */
    // 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);
    /* update memory range */
    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");
    }

    /* relocate dtb */
    dtb_buf = (void *)_ioaddr((paddr_t)(hdr->tags_addr));
    if (dtb_buf != fdt) {
        dprintf(CRITICAL, "tags addr do not meet memory layout.\n");
        /* follow memory layout */
        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);

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

    dprintf(INFO, "board cmdline %s\n", 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:%d\n", 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);
    /* android property: ro.boot.hwid */
    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);
    /* Update cmdline */
    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 
    /* Boot kernel by chain load */
    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) {
        /* ramfs type */
        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);


    /* update memory range */
    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");
    }

    /* update initrd */
    if (root_type == 0)
        ret =  update_fdt_initrd(fdt, REE_MEMBASE + BOARD_RAMDISK_OFFSET,
                                 ROOTFS_MEMSIZE);

    /* Report all active part */
    cmdline_board = calloc(1, COMMAND_LINE_PARTITION);

    if (!cmdline_board) {
        dprintf(CRITICAL, "alloc cmdline buf failed\n");
        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);

    /* Boot kernel */
    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 boot\n");
    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 ,我也贴一下吧,如下:

# buildsystem\rtos\lk_boot\chipcfg\generate\x9_high-plus\projects\serdes\boot_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, },
};
# buildsystem\rtos\lk_boot\chipcfg\generate\x9_high-plus\projects\serdes\boot_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,
        },
    },
};
  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-06-23 00:58:02  更:2022-06-23 00:58:49 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 2:59:35-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码