Android DT/DTO镜像简介

下图引自:https://source.android.com/devices/architecture/dto/partitions
本文中所述工具和源码详见Google代码仓:
git clone https://android.googlesource.com/platform/system/libufdt
Android DT/DTO镜像简介_第1张图片
dt或者dto镜像在这里Google把它笼统地称作dtbo镜像,他们的格式是一样的,都是把多个dtc编译出来的dtb二进制或者dto二进制打包到一个image,在image的结尾加一个avb的校验签名或者各个厂商自定义的镜像签名。
多个硬件设备可能配置都不一样,寄存器或者内存大小的配置等。每个硬件设备对应一个dtb和dto,把多个dtb或者dto按照图示的格式打包成对应的dt.img和dto.img,这样软件可以做到共镜像,方便了厂商对产品的维护工作。
每个硬件设备怎么识别到对应自己的dtb和dto呢?这里就需要依赖dt_table_entry中的id、rev、custom这几个字段了,它作用是硬件标识。这样bootloader就可以根据硬件设备获取的标识加载匹配的dtb和dto了。
例如:单板配置一和二

jun@ubuntu:~/dtbo/libufdt/utils/tests/data$ cat board1v1.dts
/dts-v1/;
/plugin/;

/ {
  compatible = "board_manufacturer,board_model";
  board_id = <0x00010000>;
  board_rev = <0x00010000>;
  /* optional, the soc used by the board */
  soc_id = <0x00020000>;

  deviceB:deviceB {
  };
};

&deviceB {
  value = <0x1>;
  status = "okay";
};
jun@ubuntu:~/dtbo/libufdt/utils/tests/data$ cat board2v1.dts
/dts-v1/;
/plugin/;

/ {
  compatible = "board_manufacturer,board_model";
  board_id = <0x00020000>;
  board_rev = <0x00010000>;
  /* optional, the soc used by the board */
  soc_id = <0x00010000>;

  deviceA: deviceA {
  };
};

&deviceA {
  value = <0x1>;
  status = "okay";
};

安装dts编译器:

sudo apt install device-tree-compiler
jun@ubuntu:~/dtbo/libufdt/utils/tests/data$ dtc --version
Version: DTC 1.4.5

编译dts到dtb二进制格式:

dtc -O dtb board1v1.dts -o board1v1.dtb
dtc -O dtb board2v1.dts -o board2v1.dtb

使用mkdtboimg.py工具制作生成dt.img
注意:version参数没有或者是0,代表打包前不对dtb进行压缩处理,如果version参数为1,并且配合flags参数可设置dtb压缩格式。
flags为0,不压缩dtb
flags为1,zlib压缩dtb
flags为2,gzip压缩dtb

jun@ubuntu:~/dtbo/libufdt/utils/tests/data$ ../../src/mkdtboimg.py create dt.img --page_size=4096 --flags=2 --version=1 board1v1.dtb --id=0x10000 board2v1.dtb --id=0x20000
jun@ubuntu:~/dtbo/libufdt/utils/tests/data$ ../../src/mkdtboimg.py dump dt.img
dt_table_header:
               magic = d7b7ab1e
          total_size = 429
         header_size = 32
       dt_entry_size = 32
      dt_entry_count = 2
   dt_entries_offset = 32
           page_size = 4096
             version = 1
dt_table_entry[0]:
             dt_size = 166
           dt_offset = 96
                  id = 00010000
                 rev = 00000000
           custom[0] = 00000002
           custom[1] = 00000000
           custom[2] = 00000000
           custom[3] = 00000000
dt_table_entry[1]:
             dt_size = 167
           dt_offset = 262
                  id = 00020000
                 rev = 00000000
           custom[0] = 00000002
           custom[1] = 00000000
           custom[2] = 00000000
           custom[3] = 00000000

dtbo镜像详细的数据结构定义:

#define DT_TABLE_MAGIC 0xd7b7ab1e
#define DT_TABLE_DEFAULT_PAGE_SIZE 2048
#define DT_TABLE_DEFAULT_VERSION 0

struct dt_table_header {
  uint32_t magic;             /* DT_TABLE_MAGIC */
  uint32_t total_size;        /* includes dt_table_header + all dt_table_entry
                                 and all dtb/dtbo */
  uint32_t header_size;       /* sizeof(dt_table_header) */

  uint32_t dt_entry_size;     /* sizeof(dt_table_entry) */
  uint32_t dt_entry_count;    /* number of dt_table_entry */
  uint32_t dt_entries_offset; /* offset to the first dt_table_entry
                                 from head of dt_table_header.
                                 The value will be equal to header_size if
                                 no padding is appended */

  uint32_t page_size;         /* flash page size we assume */
  uint32_t version;           /* DTBO image version, the current version is 0.
                                 The version will be incremented when the dt_table_header
                                 struct is updated. */
};
// 下面定义的是dtb或dto支持的压缩格式,mkdtboimg.py命令行version必须为1,flags可设0~2
enum dt_compression_info {
    NO_COMPRESSION,     // mkdtboimg.py --version=1 --flags=0
    ZLIB_COMPRESSION,   // mkdtboimg.py --version=1 --flags=1
    GZIP_COMPRESSION    // mkdtboimg.py --version=1 --flags=2
};
// 下面这个结构体对应的是mkdtboimg.py脚本命令行参数version是0或默认的情况
struct dt_table_entry {
  uint32_t dt_size;
  uint32_t dt_offset;         /* offset from head of dt_table_header */

  uint32_t id;                /* optional, must be zero if unused */
  uint32_t rev;               /* optional, must be zero if unused */
  uint32_t custom[4];         /* optional, must be zero if unused */
};
// 下面这个结构体对应的是mkdtboimg.py脚本命令行参数version是1的情况
struct dt_table_entry_v1 {
  uint32_t dt_size;
  uint32_t dt_offset;         /* offset from head of dt_table_header */

  uint32_t id;                /* optional, must be zero if unused */
  uint32_t rev;               /* optional, must be zero if unused */
  uint32_t flags;             /* For version 1 of dt_table_header, the 4 least significant bits
                                 of 'flags' will be used indicate the compression
                                 format of the DT entry as per the enum 'dt_compression_info' */
  uint32_t custom[3];         /* optional, must be zero if unused */
};

bootloader中查找硬件设备对于的dtb或者dto示例代码:

#include 
#include 
#include "../../src/dt_table.h"
#include 
#include 
#include 
#include 
#include 

void *read_dtbo(char *ptn)
{
	int ret;
	char *dtbo;
	struct stat buf = {0};

	ret = stat(ptn, &buf);
	if (ret != 0) {
		printf("stat err\n");
		return NULL;
	}

	dtbo = (char *)malloc(buf.st_size);
	ret = open(ptn, O_RDONLY);
	if (ret < 0) {
		printf("open fail\n");
		return NULL;
	}
	ret = read(ret, dtbo, buf.st_size);
	if (ret != buf.st_size) {
		printf("read err\n");
		return NULL;
	}
	return dtbo;
}


unsigned int get_board_id(void)
{
	return 0x20000;
}

void *load_dtbo(void)
{
	char *dtbo;
	struct dt_table_header *dtbo_head;
	unsigned int board_id;
	struct dt_table_entry_v1 *dtbo_entry;

	dtbo = read_dtbo("dt.img");
	if (!dtbo) {
		printf("read_dtbo err!\n");
		return NULL;
	}

	dtbo_head = (struct dt_table_header *)dtbo;
	printf("magic %x\n", be32toh(dtbo_head->magic));
	if (be32toh(dtbo_head->magic) != DT_TABLE_MAGIC) {
		printf("Magic not match!\n");
		return NULL;
	}

	board_id = get_board_id();
	for (dtbo_entry = (struct dt_table_entry_v1 *)(dtbo + be32toh(dtbo_head->dt_entries_offset));
	     (char *)dtbo_entry < dtbo + be32toh(dtbo_head->dt_entries_offset) +
	     be32toh(dtbo_head->dt_entry_size) * be32toh(dtbo_head->dt_entry_count);
	     ++dtbo_entry) {
		if (be32toh(dtbo_entry->id) == board_id) {
			printf("dtbo_entry info dt_size %x\n",   be32toh(dtbo_entry->dt_size));
			printf("dtbo_entry info dt_offset %x\n", be32toh(dtbo_entry->dt_offset));
			printf("dtbo_entry info id %x\n",        be32toh(dtbo_entry->id));
			printf("dtbo_entry info rev %x\n",       be32toh(dtbo_entry->rev));
			break;
		}
	}
	return dtbo_entry;
}

void main()
{
	load_dtbo();
}

你可能感兴趣的:(Android)