پارتیشن‌های DTB و DTBO

اگر درختواره دستگاه (DTB) یا درختواره دستگاه برای رونهاد (DTBO) در پارتیشن یکتایی قرار دارد، برای مثال، پارتیشن dtb و dtbo، از ساختار جدول زیر و قالب سرایند استفاده کنید:

شکل ۱. نمونه چیدمان بخش DTB و DTBO.

ساختارهای داده

dt_table_header فقط برای بخش‌بندی dtb/dtbo است؛ نمی‌توانید این قالب را بعداز پایان image.gz اضافه کنید. اگر یک DTB یا DTBO دارید، باید همچنان از این قالب استفاده کنید (و dt_entry_count در dt_table_header برابر با ۱ است).

#define DT_TABLE_MAGIC 0xd7b7ab1e

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

  uint32_t page_size;         // flash page size we assume
  uint32_t version;       // DTBO image version, the current version is 0.
                          // The version is incremented when the
                          // dt_table_header struct is updated.
};

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
};

برای خواندن همه dt_table_entry، از dt_entry_size، dt_entry_count، و dt_entries_offset استفاده کنید. مثال:

my_read(entries_buf,
        header_addr + header->dt_entries_offset,
        header->dt_entry_size * header->dt_entry_count);

‫id،‏ rev،‏ custom در dt_table_entry شناسه‌های سخت‌افزاری اختیاری درخت دستگاه هستند که راه‌انداز سیستم می‌تواند از آن‌ها برای شناسایی کارآمد DTB یا DTBO برای بار کردن استفاده کند. اگر بوت‌لودر به اطلاعات بیشتری نیاز دارد، آن را در DTB یا DTBO قرار دهید تا بوت‌لودر بتواند آن را با تجزیه DTB یا DTBO بخواند (کد نمونه زیر را ببینید).

کدگذاری نمونه

کد نمونه زیر شناسه سخت‌افزار را در راه‌انداز سیستم بررسی می‌کند.

  • تابع check_dtbo() شناسایی سخت‌افزار را بررسی می‌کند. ابتدا داده‌های ساختار dt_table_entry (id، rev، و غیره) را بررسی می‌کند. اگر این داده‌ها کافی نباشد، dtb داده را در حافظه بار می‌کند و مقدار را در dtb بررسی می‌کند.
  • مقادیر my_hw_information و soc_id دارایی‌ها در گره ریشه تجزیه می‌شوند (مثال در my_dtbo_1.dts).
    [my_dtbo_1.dts]
    /dts-v1/;
    /plugin/;
    
    / {
      /* As DTS design, these properties only for loader, won't overlay */
      compatible = "board_manufacturer,board_model";
    
      /* These properties are examples */
      board_id = <0x00010000>;
      board_rev = <0x00010001>;
      another_hw_information = "some_data";
      soc_id = <0x68000000>;
      ...
    };
    
    &device@0 {
      value = <0x1>;
      status = "okay";
    };
    
    
    [my_bootloader.c]
    int check_dtbo(const dt_table_entry *entry, uint32_t header_addr) {
      ...
      if (entry->id != ... || entry->rev != ...) {
        ...
      }
      ...
      void * fdt_buf = my_load_dtb(header_addr + entry->dt_offset, entry->dt_size);
      int root_node_off = fdt_path_offset(fdt_buf, "/");
      ...
      const char *my_hw_information =
        (const char *)fdt_getprop(fdt_buf, root_node_off, "my_hw_information", NULL);
      if (my_hw_information != NULL && strcmp(my_hw_information, ...) != 0) {
        ...
      }
      const fdt32_t *soc_id = fdt_getprop(fdt_buf, root_node_off, "soc_id", NULL);
      if (soc_id != NULL && *soc_id != ...) {
        ...
      }
      ...
    }

mkdtimg

‫mkdtimg ابزاری برای ایجاد dtb/dtbo تصویر (کد منبع در system/libufdt در AOSP) است. ‫mkdtimg از چندین فرمان، ازجمله create،‏ cfg_create، و dump پشتیبانی می‌کند.

ایجاد

برای ایجاد تصویر dtb/dtbo، از فرمان create استفاده کنید:

mkdtimg create <image_filename> (<global-option>...) \
    <ftb1_filename> (<entry1_option>...) \
    <ftb2_filename> (<entry2_option>...) \
    ...

‫ftbX_filename یک dt_table_entry در تصویر تولید می‌کند. entryX_option مقادیری است که باید به dt_table_entry اختصاص داده شود. این مقادیر می‌تواند هریک از موارد زیر باشد:

--id=<number|path>
--rev=<number|path>
--custom0=<number|path>
--custom1=<number|path>
--custom2=<number|path>
--custom3=<number|path>

مقادیر عددی می‌توانند یک رقم ۳۲ بیتی (مانند ۶۸۰۰۰) یا یک عدد هگز (مانند 0x6800) باشند. یا می‌توانید مسیری را بااستفاده از قالب زیر مشخص کنید:

<full_node_path>:<property_name>

برای مثال، /board/:id. ‫mkdtimg مقدار را از مسیر در فایل DTB یا DTBO می‌خواند و مقدار (۳۲ بیتی) را به دارایی نسبی در dt_table_entry اختصاص می‌دهد. یا می‌توانید global_option را به‌عنوان گزینه پیش‌فرض برای همه ورودی‌ها ارائه دهید. مقدار پیش‌فرض page_size در dt_table_header برابر با ۲۰۴۸ است؛ از global_option --page_size=<number> برای اختصاص دادن مقدار دیگری استفاده کنید.

مثال:

[board1.dts]
/dts-v1/;
/plugin/;

/ {
  compatible = "board_manufacturer,board_model";
  board_id = <0x00010000>;
  board_rev = <0x00010001>;
  another_hw_information = "some_data";
  ...
};

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


mkdtimg create dtbo.img --id=/:board_id --custom0=0xabc \
  board1.dtbo \
  board2.dtbo --id=0x6800 \
  board3.dtbo --id=0x6801 --custom0=0x123
  • ‫dt_table_entry (board1.dtbo) id اول ‫0x00010000 و custom[0] ‫0x00000abc است.
  • ‫id دوم 0x00006800 و ‫custom[0]‏ 0x00000abc است.
  • ‫id سوم 0x00006801 و custom[0] ‏ 0x00000123 است.
  • همه موارد دیگر از مقدار پیش‌فرض (0) استفاده می‌کنند.

cfg_create

فرمان cfg_create تصویری با فایل پیکربندی در قالب زیر ایجاد می‌کند:

# global options
  <global_option>
  ...
# entries
<ftb1_filename>     # comment
  <entry1_option>   # comment
  ...
<ftb2_filename>
  <entry2_option>
  ...
...

گزینه‌های global_option و entryX_option باید با یک یا چند نویسه فاصله شروع شوند (این گزینه‌ها همان گزینه‌های create هستند، بدون پیشوند --). خطوط خالی یا خطوطی که با # شروع می‌شوند نادیده گرفته می‌شوند.

مثال:

[dtboimg.cfg]
# global options
  id=/:board_id
  rev=/:board_rev
  custom0=0xabc

board1.dtbo

board2.dtbo
  id=0x6800       # override the value of id in global options

board2.dtbo
  id=0x6801       # override the value of id in global options
  custom0=0x123   # override the value of custom0 in global options


mkdtimg cfg_create dtbo.img dtboimg.cfg

‫mkdtimg تراز کردن فایل‌های .dtb/.dtbo را انجام نمی‌دهد، بلکه آن‌ها را به تصویر اضافه می‌کند. وقتی از dtc برای کامپایل کردن .dts به .dtb/.dtbo استفاده می‌کنید، باید گزینه -a را اضافه کنید. برای مثال، افزودن گزینه -a 4 حاشیه اضافه می‌کند تا اندازه .dtb/.dtbo با ۴ بایت تراز شود.

چندین ورودی جدول DT می‌توانند .dtb/.dtbo را هم‌رسانی کنند. اگر از نام فایل یکسانی برای ورودی‌های مختلف استفاده کنید، فقط یک محتوا در تصویر با dt_offset و dt_size یکسان ذخیره می‌شود. این کار هنگام استفاده از سخت‌افزارهای مختلف با DT یکسان مفید است.

روبرداری کردن

برای تصاویر dtb/dtbo، از فرمان dump برای چاپ اطلاعات تصویر استفاده کنید. مثال:

mkdtimg dump dtbo.img
dt_table_header:
               magic = d7b7ab1e
          total_size = 1300
         header_size = 32
       dt_entry_size = 32
      dt_entry_count = 3
   dt_entries_offset = 32
           page_size = 2048
             version = 0
dt_table_entry[0]:
             dt_size = 380
           dt_offset = 128
                  id = 00010000
                 rev = 00010001
           custom[0] = 00000abc
           custom[1] = 00000000
           custom[2] = 00000000
           custom[3] = 00000000
           (FDT)size = 380
     (FDT)compatible = board_manufacturer,board_model
...