高通平台dtb文件的加载过程

  • 高通平台对dts的两种打包方式
    • zImage-dtb
    • dt.img
  • zImage-dtb方式
    • zImage-dtb的编译
    • 二进制文件查看
    • lk的加载过程代码分析
  • dt.img方式
    • dt.img的编译
    • dt.img的构造
    • lk的加载过程代码分析
  • 小结

高通平台对dts的两种打包方式

zImage-dtb

直接和kernel编译在一起,生成zImage-dtb,dtb的位置在kernel起始地址偏移0x2C的位置,然后和kernel一起打包到bootimage里。

dt.img

独立编译出dt.img, 然后打包到bootimage里。

zImage-dtb方式

zImage-dtb的编译

dtb怎么编译进bootimage的?
makefile文件分析

.config 文件里生成的内容如下

CONFIG_ARCH_MSM8916=yCONFIG_ARCH_MSM8937=yCONFIG_ARCH_MSM8917=yCONFIG_ARCH_MSM8920=yCONFIG_ARCH_MSM8940=yCONFIG_ARCH_MSM8953=y

kernel/msm-3.18/arch/arm/boot/dts/qcom/Makefile

(只要这些arch定义了 这些dtb文件都会被包含进去)

dtb-$(CONFIG_ARCH_MDMCALIFORNIUM) += mdmcalifornium-sim.dtb \mdmcalifornium-rumi.dtb \

mdmcalifornium-v1.1-nand-mtp.dtb \mdmcalifornium-v1.1-nand-dualwifi-mtp.dtbdtb-$(CONFIG_ARCH_MSM8937) += msm8937-rumi.dtb \msm8937-pmi8950-cdp.dtb \.......apq8037-pmi8950-mtp.dtb \apq8037-pmi8937-mtp.dtbdtb-$(CONFIG_ARCH_MSM8917) += msm8917-rumi.dtb \apq8017-pmi8937-cdp.dtb \

msm8917-qgp-tmo.dtb \msm8917-pmi8937-qrd-sku5.dtb

.config 文件里生成的内容如下

CONFIG_USE_OF=yCONFIG_ATAGS=y# CONFIG_DEPRECATED_PARAM_STRUCT is not setCONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=yCONFIG_BUILD_ARM_APPENDED_DTB_IMAGE_NAMES=

kernel/msm-3.18/arch/arm/boot/Makefile

DTB_NAMES := $(subst $\",,$(CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE_NAMES))ifneq ($(DTB_NAMES),)DTB_LIST := $(addsuffix .dtb,$(DTB_NAMES))elseDTB_LIST := $(dtb-y)endifDTB_OBJS := $(addprefix $(obj)/dts/qcom/,$(DTB_LIST))

因为CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE_NAMES 这个为空,

所以

DTB_LIST := $(dtb-y)DTB_OBJS := $(obj)/dts/qcom/$(dtb-y)

需要编译zImage-dtb

# Default target when executing plain makeifeq ($(CONFIG_XIP_KERNEL),y)
KBUILD_IMAGE := xipImageelse ifeq ($(CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE),y)KBUILD_IMAGE := zImage-dtbelseKBUILD_IMAGE := zImageendif$(obj)/Image: vmlinux FORCE$(call if_changed,objcopy)@$(kecho) ' Kernel: $@ is ready'$(obj)/compressed/vmlinux: $(obj)/Image FORCE$(Q)$(MAKE) $(build)=$(obj)/compressed $@$(obj)/zImage: $(obj)/compressed/vmlinux FORCE$(call if_changed,objcopy)@$(kecho) ' Kernel: $@ is ready'$(obj)/zImage-dtb: $(obj)/zImage $(DTB_OBJS) FORCE$(call if_changed,cat)@echo ' Kernel: $@ is ready'

可以看出zImage-dtb 依赖于 $(obj)/zImage $(DTB_OBJS)

%.dtb: | scripts$(Q)$(MAKE) $(build)=$(boot)/dts MACHINE=$(MACHINE) $(boot)/dts/$@dtbs: scripts$(Q)$(MAKE) $(build)=$(boot)/dts MACHINE=$(MACHINE) dtbs$(foreach DIR, $(DTSSUBDIR), $(Q)$(MAKE) $(build)=$(boot)/dts/$(DIR) MACHINE=$(MACHINE) dtbs)zImage-dtb: vmlinux scripts dtbs$(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) DTSSUBDIR=$(DTSSUBDIR) $(boot)/$@

二进制文件查看

查看kernel的二进制文件,查看0x2C位置的值,此处存放的值是第一个dtb文件的偏移地址

从图中可以看出dtb所在的地址为0x008e7db0 + 0x800 = 0x008e85b0

0x008e85b0地址可以看到magic 0xd00dfeed(大端)

0x008e85b0 + 0x0002bef5 = 0x009144A5为下一个dtb的起始地址

0x009144A5地址可以看到新的dtb开始,看到magic 0xd00dfeed(大端)

lk的加载过程代码分析

app\aboot\aboot.c

boot_linux_from_mmc
dt_size = hdr->dt_size;
if(dt_size) {

}else{
dtb = dev_tree_appended()
}

void *dev_tree_appended(void *kernel, uint32_t kernel_size, uint32_t dtb_offset, void *tags)
{if (dtb_offset)app_dtb_offset = dtb_offset;elsememcpy((void*) &app_dtb_offset, (void*) (kernel + DTB_OFFSET), sizeof(uint32_t)); ....while (((uintptr_t)dtb + sizeof(struct fdt_header)) < (uintptr_t)kernel_end) {struct fdt_header dtb_hdr;uint32_t dtb_size;/* the DTB could be unaligned, so extract the header,* and operate on it separately */memcpy(&dtb_hdr, dtb, sizeof(struct fdt_header));if (fdt_check_header((const void *)&dtb_hdr) != 0 ||fdt_check_header_ext((const void *)&dtb_hdr) != 0 ||((uintptr_t)dtb + (uintptr_t)fdt_totalsize((const void *)&dtb_hdr) < (uintptr_t)dtb) ||((uintptr_t)dtb + (uintptr_t)fdt_totalsize((const void *)&dtb_hdr) > (uintptr_t)kernel_end))break;dtb_size = fdt_totalsize(&dtb_hdr);dev_tree_compatible(dtb, dtb_size, dt_entry_queue);/* goto the next device tree if any */dtb += dtb_size;}best_match_dt_entry = platform_dt_match_best(dt_entry_queue);if (best_match_dt_entry){bestmatch_tag = (void *)best_match_dt_entry->offset;bestmatch_tag_size = best_match_dt_entry->size;dprintf(INFO, "Best match DTB tags %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",best_match_dt_entry->platform_id, best_match_dt_entry->variant_id,best_match_dt_entry->board_hw_subtype, best_match_dt_entry->soc_rev,best_match_dt_entry->pmic_rev[0], best_match_dt_entry->pmic_rev[1],best_match_dt_entry->pmic_rev[2], best_match_dt_entry->pmic_rev[3],best_match_dt_entry->offset, best_match_dt_entry->size);dprintf(INFO, "Using pmic info 0x%0x/0x%x/0x%x/0x%0x for device 0x%0x/0x%x/0x%x/0x%0x\n",best_match_dt_entry->pmic_rev[0], best_match_dt_entry->pmic_rev[1],best_match_dt_entry->pmic_rev[2], best_match_dt_entry->pmic_rev[3],board_pmic_target(0), board_pmic_target(1),board_pmic_target(2), board_pmic_target(3));}.......................return NULL;
}

其中DTB_OFFSET的定义为0x2C,与上一节的图相对应。
根据偏移值找到dtb的位置,然后对每个dtb进行解析,找到最匹配的那个dtb,这个是有dev_tree_compatible(dtb, dtb_size, dt_entry_queue);函数来实现的。

dev_tree_compatible(void *dtb, uint32_t dtb_size, struct dt_entry_node *dtb_list)
platform_dt_absolute_match(cur_dt_entry, dtb_list)

dev_tree_compatible会调用platform_dt_absolute_match来判断

static int platform_dt_absolute_match(struct dt_entry *cur_dt_entry, struct dt_entry_node *dt_list)
{uint32_t cur_dt_hlos_ddr;uint32_t cur_dt_hw_platform;uint32_t cur_dt_hw_subtype;uint32_t cur_dt_msm_id;dt_node *dt_node_tmp = NULL;/* Platform-id* bit no |31  24|23  16|15   0|*        |reserved|foundry-id|msm-id|*/cur_dt_msm_id = (cur_dt_entry->platform_id & 0x0000ffff);cur_dt_hw_platform = (cur_dt_entry->variant_id & 0x000000ff);cur_dt_hw_subtype = (cur_dt_entry->board_hw_subtype & 0xff);/* Determine the bits 10:8 to check the DT with the DDR Size */cur_dt_hlos_ddr = (cur_dt_entry->board_hw_subtype & 0x700);/* 1. must match the msm_id, platform_hw_id, platform_subtype and DDR size*  soc, board major/minor, pmic major/minor must less than board info*  2. find the matched DTB then return 1*  3. otherwise return 0*/if((cur_dt_msm_id == (board_platform_id() & 0x0000ffff)) &&(cur_dt_hw_platform == board_hardware_id()) &&(cur_dt_hw_subtype == board_hardware_subtype()) &&(cur_dt_hlos_ddr == (target_get_hlos_subtype() & 0x700)) &&(cur_dt_entry->soc_rev <= board_soc_version()) &&((cur_dt_entry->variant_id & 0x00ffff00) <= (board_target_id() & 0x00ffff00)) &&((cur_dt_entry->pmic_rev[0] & 0x00ffff00) <= (board_pmic_target(0) & 0x00ffff00)) &&((cur_dt_entry->pmic_rev[1] & 0x00ffff00) <= (board_pmic_target(1) & 0x00ffff00)) &&((cur_dt_entry->pmic_rev[2] & 0x00ffff00) <= (board_pmic_target(2) & 0x00ffff00)) &&((cur_dt_entry->pmic_rev[3] & 0x00ffff00) <= (board_pmic_target(3) & 0x00ffff00))) {dt_node_tmp = dt_entry_list_init();memcpy((char*)dt_node_tmp->dt_entry_m,(char*)cur_dt_entry, sizeof(struct dt_entry));dprintf(SPEW, "Add DTB entry %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",dt_node_tmp->dt_entry_m->platform_id, dt_node_tmp->dt_entry_m->variant_id,dt_node_tmp->dt_entry_m->board_hw_subtype, dt_node_tmp->dt_entry_m->soc_rev,dt_node_tmp->dt_entry_m->pmic_rev[0], dt_node_tmp->dt_entry_m->pmic_rev[1],dt_node_tmp->dt_entry_m->pmic_rev[2], dt_node_tmp->dt_entry_m->pmic_rev[3],dt_node_tmp->dt_entry_m->offset, dt_node_tmp->dt_entry_m->size);insert_dt_entry_in_queue(dt_list, dt_node_tmp);return 1;}return 0;
}

board_platform_id() board_hardware_id() board_hardware_subtype() target_get_hlos_subtype() board_soc_version()board_target_id()
几乎都来自board结构体

struct board_data {uint32_t platform;  //board_platform_iduint32_t foundry_id;uint32_t chip_serial;uint32_t platform_version;//board_soc_versionuint32_t platform_hw;//board_hardware_id()uint32_t platform_subtype;//board_hardware_subtypeuint32_t target;//board_target_id()uint32_t baseband;struct board_pmic_data pmic_info[MAX_PMIC_DEVICES];uint32_t platform_hlos_subtype;//target_get_hlos_subtype即board_hlos_subtypeuint32_t num_pmics;uint32_t pmic_array_offset;struct board_pmic_data *pmic_info_array;
};

board在platform\msm_shared\board.c 文件里赋值
board_init()
platform_detect()

         board.platform = board_info_v11.board_info_v3.msm_id;board.platform_version = board_info_v11.board_info_v3.msm_version;board.platform_hw = board_info_v11.board_info_v3.hw_platform;board.platform_subtype = board_info_v11.platform_subtype;/** fill in board.target with variant_id information* bit no         |31  24 |23             16|15              8|7         0|* board.target = |subtype|plat_hw_ver major|plat_hw_ver minor|hw_platform|**/board.target = (((board_info_v11.platform_subtype & 0xff) << 24) |(((board_info_v11.platform_version >> 16) & 0xff) << 16) |((board_info_v11.platform_version & 0xff) << 8) |(board_info_v11.board_info_v3.hw_platform & 0xff));board.foundry_id = board_info_v11.foundry_id;board.chip_serial = board_info_v11.chip_serial;board.num_pmics = board_info_v11.num_pmics;board.pmic_array_offset = board_info_v11.pmic_array_offset;}/* HLOS subtype* bit no                        |31    20 | 19        16|15    13 |12      11 | 10          8 | 7     0|* board.platform_hlos_subtype = |reserved | Boot device |Reserved | Panel     | DDR detection | subtype|*                               |  bits   |             |  bits   | Detection |*/board.platform_hlos_subtype = (board_get_ddr_subtype() << 8) | (platform_get_boot_dev() << 16) | (platform_detect_panel() << 11);

根据代码里给的注释,从smem里获得

platform_dt_absolute_match过程

static int platform_dt_absolute_match(struct dt_entry *cur_dt_entry, struct dt_entry_node *dt_list)
{/* Platform-id* bit no |31  24|23  16|15   0|*        |reserved|foundry-id|msm-id|*/cur_dt_msm_id = (cur_dt_entry->platform_id & 0x0000ffff);cur_dt_hw_platform = (cur_dt_entry->variant_id & 0x000000ff);cur_dt_hw_subtype = (cur_dt_entry->board_hw_subtype & 0xff);/* Determine the bits 10:8 to check the DT with the DDR Size */cur_dt_hlos_ddr = (cur_dt_entry->board_hw_subtype & 0x700);/* 1. must match the msm_id, platform_hw_id, platform_subtype and DDR size*  soc, board major/minor, pmic major/minor must less than board info*  2. find the matched DTB then return 1*  3. otherwise return 0*/if((cur_dt_msm_id == (board_platform_id() & 0x0000ffff)) &&(cur_dt_hw_platform == board_hardware_id()) &&(cur_dt_hw_subtype == board_hardware_subtype()) &&(cur_dt_hlos_ddr == (target_get_hlos_subtype() & 0x700)) &&(cur_dt_entry->soc_rev <= board_soc_version()) &&((cur_dt_entry->variant_id & 0x00ffff00) <= (board_target_id() & 0x00ffff00)) &&((cur_dt_entry->pmic_rev[0] & 0x00ffff00) <= (board_pmic_target(0) & 0x00ffff00)) &&((cur_dt_entry->pmic_rev[1] & 0x00ffff00) <= (board_pmic_target(1) & 0x00ffff00)) &&((cur_dt_entry->pmic_rev[2] & 0x00ffff00) <= (board_pmic_target(2) & 0x00ffff00)) &&((cur_dt_entry->pmic_rev[3] & 0x00ffff00) <= (board_pmic_target(3) & 0x00ffff00))) {dt_node_tmp = dt_entry_list_init();memcpy((char*)dt_node_tmp->dt_entry_m,(char*)cur_dt_entry, sizeof(struct dt_entry));... ...
}

对比之前需要从dts里将信息提取出来,主要是通过读取三个属性值然后提取

pmic_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,pmic-id", &len_pmic_id);
board_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,board-id", &len_board_id);

plat_prop = (const char *)fdt_getprop(dtb, root_offset, “qcom,msm-id”, &len_plat_id);

     board_data[i].variant_id = fdt32_to_cpu(((struct board_id *)board_prop)->variant_id);board_data[i].platform_subtype = fdt32_to_cpu(((struct board_id *)board_prop)->platform_subtype);dt_entry_array[k].board_hw_subtype = board_data[j].platform_subtype;platform_data[i].platform_id = fdt32_to_cpu(((struct plat_id *)plat_prop)->platform_id);platform_data[i].soc_rev = fdt32_to_cpu(((struct plat_id *)plat_prop)->soc_rev);pmic_data[i].pmic_version[0]= fdt32_to_cpu(((struct pmic_id *)pmic_prop)->pmic_version[0]);pmic_data[i].pmic_version[1]= fdt32_to_cpu(((struct pmic_id *)pmic_prop)->pmic_version[1]);pmic_data[i].pmic_version[2]= fdt32_to_cpu(((struct pmic_id *)pmic_prop)->pmic_version[2]);pmic_data[i].pmic_version[3]= fdt32_to_cpu(((struct pmic_id *)pmic_prop)->pmic_version[3]);

must match the msm_id, platform_hw_id, platform_subtype and DDR size
可见 msm_id, platform_hw_platform, platform_subtype and DDR size 这几个需要完全匹配才可以
cur_dt_msm_id = (cur_dt_entry->platform_id & 0x0000ffff);
来自"qcom,msm-id"

platform_hw_platform = (cur_dt_entry->variant_id & 0x000000ff);
来自 "qcom,board-id"

cur_dt_hw_subtype = (cur_dt_entry->board_hw_subtype & 0xff);
同样来自 "qcom,board-id"

总之,最终会找到一个最合适的dtb,也有可能因为配置不对找不到匹配的dtb文件。

由此可见,在dtb未匹配时,需要修改sbl里的id,或者同步修改dts里的board id,让两者匹配才可以。

dt.img方式

dt.img的编译

device\qcom\common\generate_extra_images.mk

#----------------------------------------------------------------------
# Generate device tree image (dt.img)
#----------------------------------------------------------------------
ifneq ($(strip $(TARGET_NO_KERNEL)),true)
ifeq ($(strip $(BOARD_KERNEL_SEPARATED_DT)),true)
ifeq ($(strip $(BUILD_TINY_ANDROID)),true)
include device/qcom/common/dtbtool/Android.mk
endifDTBTOOL := $(HOST_OUT_EXECUTABLES)/dtbTool$(HOST_EXECUTABLE_SUFFIX)INSTALLED_DTIMAGE_TARGET := $(PRODUCT_OUT)/dt.imgpossible_dtb_dirs = $(KERNEL_OUT)/arch/$(TARGET_KERNEL_ARCH)/boot/dts/ $(KERNEL_OUT)/arch/arm/boot/dts/ $(KERNEL_OUT)/arch/arm/boot/
dtb_dir = $(firstword $(wildcard $(possible_dtb_dirs)))define build-dtimage-target$(call pretty,"Target dt image: $(INSTALLED_DTIMAGE_TARGET)")$(hide) $(DTBTOOL) -o $@ -s $(BOARD_KERNEL_PAGESIZE) -p $(KERNEL_OUT)/scripts/dtc/ $(dtb_dir)$(hide) chmod a+r $@
endef$(INSTALLED_DTIMAGE_TARGET): $(DTBTOOL) $(INSTALLED_KERNEL_TARGET)$(build-dtimage-target)ALL_DEFAULT_INSTALLED_MODULES += $(INSTALLED_DTIMAGE_TARGET)
ALL_MODULES.$(LOCAL_MODULE).INSTALLED += $(INSTALLED_DTIMAGE_TARGET)
endif
endif

可见是使用dtbtool
dtbtool代码定义在device\qcom\common\dtbtool\dtbtool.c, 与这个文件同一目录下的dtbtool.txt是对dtbtool的使用说明。

1.1) Android boot image Header:

  1. Magic (8B)
  2. kernel size (4B)
  3. kernel addr (4B)
  4. ramdisk size (4B)
  5. ramdisk addr (4B)
  6. 2ndary size (4B)
  7. 2ndary addr (4B)
  8. tags addr (4B)
  9. page size (4B)
  10. unused #1 (4B) (zero in standard Android)
  11. unused #2 (4B) (zero in standard Android)
  12. product name (16B)
  13. kernel cmdline (512B)
  14. id (8B)

1.2) Layout:
A) header (as above - 1 page)
B) kernel (n pages)
C) ramdisk (m pages)
D) second stage (o pages)
2) QC table of device tree

dt.img的构造


可以看出magic是QCDT,version是3,num_entries是0x89

可以看出offset是0x1800, size是0x26800 (0x1800+0x26800=0x28000)

0x28000是另一个dtb的开始

lk的加载过程代码分析

int boot_linux_from_mmc(void)
{...............if(dt_size) {dt_table_offset = ((uint32_t)image_addr + page_size + kernel_actual + ramdisk_actual + second_actual);table = (struct dt_table*) dt_table_offset;if (dev_tree_validate(table, hdr->page_size, &dt_hdr_size) != 0) {dprintf(CRITICAL, "ERROR: Cannot validate Device Tree Table \n");return -1;}/* Its Error if, dt_hdr_size (table->num_entries * dt_entry size + Dev_Tree Header)goes beyound hdr->dt_size*/if (dt_hdr_size > ROUND_TO_PAGE(dt_size,hdr->page_size)) {dprintf(CRITICAL, "ERROR: Invalid Device Tree size \n");return -1;}/* Find index of device tree within device tree table */if(dev_tree_get_entry_info(table, &dt_entry) != 0){dprintf(CRITICAL, "ERROR: Getting device tree address failed\n");return -1;}if(dt_entry.offset > (UINT_MAX - dt_entry.size)) {dprintf(CRITICAL, "ERROR: Device tree contents are Invalid\n");return -1;}/* Ensure we are not overshooting dt_size with the dt_entry selected */if ((dt_entry.offset + dt_entry.size) > dt_size) {dprintf(CRITICAL, "ERROR: Device tree contents are Invalid\n");return -1;}if (is_gzip_package((unsigned char *)dt_table_offset + dt_entry.offset, dt_entry.size)){unsigned int compressed_size = 0;out_addr += out_len;out_avai_len -= out_len;dprintf(INFO, "decompressing dtb: start\n");rc = decompress((unsigned char *)dt_table_offset + dt_entry.offset,dt_entry.size, out_addr, out_avai_len,&compressed_size, &dtb_size);if (rc){dprintf(CRITICAL, "decompressing dtb failed!!!\n");ASSERT(0);}dprintf(INFO, "decompressing dtb: done\n");best_match_dt_addr = out_addr;} else {best_match_dt_addr = (unsigned char *)dt_table_offset + dt_entry.offset;dtb_size = dt_entry.size;}/* Validate and Read device device tree in the tags_addr */if (check_aboot_addr_range_overlap(hdr->tags_addr, dtb_size) ||check_ddr_addr_range_bound(hdr->tags_addr, dtb_size)){dprintf(CRITICAL, "Device tree addresses are not valid\n");return -1;}memmove((void *)hdr->tags_addr, (char *)best_match_dt_addr, dtb_size);} else {/* Validate the tags_addr */if (check_aboot_addr_range_overlap(hdr->tags_addr, kernel_actual) ||check_ddr_addr_range_bound(hdr->tags_addr, kernel_actual)){dprintf(CRITICAL, "Device tree addresses are not valid.\n");return -1;}/** If appended dev tree is found, update the atags with* memory address to the DTB appended location on RAM.* Else update with the atags address in the kernel header*/void *dtb;dtb = dev_tree_appended((void*)(image_addr + page_size +patched_kernel_hdr_size),hdr->kernel_size, dtb_offset,(void *)hdr->tags_addr);if (!dtb) {dprintf(CRITICAL, "ERROR: Appended Device Tree Blob not found\n");return -1;}}
....................
}

在这种情况下dt_size是非0的,走第一个分支,第二个分支是zImage-dtb那种方式使用的

int dev_tree_get_entry_info(struct dt_table *table, struct dt_entry *dt_entry_info)for(i = 0; found == 0 && i < table->num_entries; i++)platform_dt_absolute_match(cur_dt_entry, dt_entry_queue);best_match_dt_entry = platform_dt_match_best(dt_entry_queue);

调用关系如上,对每一个dt_entry调用platform_dt_absolute_match,找到最匹配的,匹配方法与zImage-dtb方式类似,不再赘述。

小结

device tree最终编译成dtb文件,而高通平台为了让一个bootimage支持多种不同的配置(甚至是不同的board,不同的平台),将众多的dtb文件一起同时编译和打包。为了区分匹配不同的平台,高通平台需要再sbl里配置id,与device tree里的qcom,pmic-id和qcom,board-id相呼应,这两者需要匹配,才能实现dtb文件的正确加载,然后由lk传递给kernel。而dtb的识别是在lk里实现的,lk代码里对dt.img方式和zImage-dtb方式做了兼容,可以同时识别这两种方式。

高通平台dtb文件的加载过程相关推荐

  1. extjs5(03--项目中文件的加载过程)

    上一节中用sencha工具自动创建了一个项目,并且可以在浏览器中查看.现在我们来看看js类加载过程.如下图所示: 1、首先:浏览器中输入 localhost:1841 ,调用 index.html; ...

  2. EXE文件的加载过程

    一个microsoft的.exe程序文件的启动过程 2009-06-16 14:54 2101人阅读 评论(0) 收藏 举报 microsoftmfcwindowsshelldll数据结构 学习win ...

  3. 浏览器加载一个页面过程,本地的html文件的加载过程

    打开一个本地文件 读取返回给网页 import flask app=flask.Flask(__name__) @app.route('/index') def miaomiao():with ope ...

  4. 高通平台msm8953 Linux DTS(Device Tree Source)设备树详解之二(DTS设备树匹配过程)

    本系列导航: 高通平台8953  Linux DTS(Device Tree Source)设备树详解之一(背景基础知识篇) 高通平台8953 Linux DTS(Device Tree Source ...

  5. ELF文件的加载和动态链接过程

    本文的目的:大家对于Hello World程序应该非常熟悉,随便使用哪一种语言,即使还不熟悉的语言,写出一个Hello World程序应该毫不费力,但是如果让大家详细的说明这个程序加载和链接的过程,以 ...

  6. 高通平台msm8909 LK 实现LCD 兼容

    前段时间小米出现红米note2 换屏门,现在我们公司也要上演了:有两个供应商提供不同IC 的LCD panel. 软件区分的办法是读取LCD IC 的ID 寄存器,下面解析高通平台LK中LCD兼容的过 ...

  7. 高通平台modem部分mbn文件的OTA和PDC升级方法

    高通平台modem部分mbn文件的OTA和PDC升级方法 最近需要采用一种移动物联网卡,发现在apns-conf.xml增加了对应apn信息后,部分设备采用新的xml就可以支持新卡,但部分设备还不行, ...

  8. 高通about.html 文件,高通平台UEFI有关介绍

    高通平台UEFI有关介绍 背景 我需要在高通平台上学习点亮LCD,目前通过同事在别的平台的配置代码,我已经将kernel部分的屏幕点亮了:剩余的工作量就在BP侧,也就是系统刚开机的那一段时间.在开发过 ...

  9. 高通平台8953 Linux DTS(Device Tree Source)设备树详解之一(背景基础知识篇)

    本系列导航: 高通平台8953  Linux DTS(Device Tree Source)设备树详解之一(背景基础知识篇) 高通平台8953 Linux DTS(Device Tree Source ...

最新文章

  1. linux apache 手动安装教程,linux下手动安装apache
  2. (解决办法)ASP.NET导出Excel,打开时提示“您尝试打开文件'XXX.xls'的格式与文件扩展名指定文件不一致...
  3. win10 配置 maven_home 一会儿成功一会儿失败_在macbook上运行移动硬盘里的win10和macos...
  4. springboot参数检验,Assert使用
  5. linux脚本语言求累加和,Linux Shell脚本语言与数学表达式
  6. Gamma阶段第八次scrum meeting
  7. java反射jdk1.8,Java基础----jdk1.8 反射实验
  8. dnf最新地图编号2020_2020手游崛起端游没落?网易新端游好玩刺激能搬砖,网友:妙...
  9. C#实现邮件发送的功能
  10. python使用opencv保存视频_Pythone OpenCV学习笔记之:视频文件读取与保存
  11. CSS按钮动画(四)
  12. 【三维路径规划】基于matlab人工势场算法无人机三维路径规划【含Matlab源码 168期】
  13. 菜鸟也疯狂,易语言自绘控件__按钮篇,用所有者自绘方式实现
  14. ORL人脸数据库matlab,orl ORL人脸数据库,用于图形图像处理,对新接触MATLAB的人来说是一个很好用而且比较简单 238万源代码下载- www.pudn.com...
  15. 在图片上涂鸦(其实就是乱画 O(∩_∩)O)
  16. JAVA开发---微信文章留言功能实现
  17. Linux下的关闭防火墙
  18. 【BZOJ3875】[Ahoi2014Jsoi2014]骑士游戏 SPFA优化DP
  19. mysql 连续登录天数
  20. Jenkins CI服务器搭建及Maven私服Nexus

热门文章

  1. 《系统程序员成长计划》成长过程
  2. es6 三点运算符_基于es6三点运算符的使用方法(实例讲解)
  3. 详解 Pytorch.random
  4. atitit 破解 拦截 绕过 网站 手机 短信 验证码 之自动获取手机短信方式 attilax 总结
  5. 快手小店违约金不交保证金能退吗?保证金怎么退?
  6. Go语言历史背景及语言特性
  7. 最全微信小程序demo
  8. Geohash:算法原理
  9. BibTex的格式说明/解释
  10. 超声波传感器(CH101ch201) - Ⅰ