DTO ها را بهینه کنید

این صفحه بهینه‌سازی‌هایی را که می‌توانید در پیاده‌سازی همپوشانی درخت دستگاه (DTO) خود انجام دهید، شرح می‌دهد، محدودیت‌های مربوط به همپوشانی گره ریشه را شرح می‌دهد و نحوه پیکربندی همپوشانی‌های فشرده در تصویر DTBO را شرح می‌دهد. همچنین دستورالعمل‌ها و کد پیاده‌سازی نمونه را ارائه می‌دهد.

خط فرمان هسته

خط فرمان اصلی هسته در درخت دستگاه (DT) در گره chosen/bootargs قرار دارد. بوت لودر باید این مکان را با سایر منابع خط فرمان هسته پیوند دهد:

/dts-v1/;

/ {
  chosen: chosen {
    bootargs = "...";
  };
};

DTO نمی‌تواند مقادیر DT اصلی و DT پوششی را به هم متصل کند، بنابراین باید خط فرمان هسته DT اصلی را در chosen/bootargs و خط فرمان هسته DT پوششی را در chosen/bootargs_ext قرار دهید. سپس بوت‌لودر می‌تواند این مکان‌ها را به هم متصل کرده و نتیجه را به هسته منتقل کند.

فایل اصلی.dts روکش.dts
/dts-v1/;

/ {
  chosen: chosen {
    bootargs = "...";
  };
};
/dts-v1/;
/plugin/;

&chosen {
  bootargs_ext = "...";
};

لیبوفدت

اگرچه آخرین libfdt از DTO پشتیبانی می‌کند، آیا استفاده از libufdt برای پیاده‌سازی DTO توصیه می‌شود (منبع AOSP در platform/system/libufdt ). libufdt یک ساختار درختی واقعی (درخت دستگاه مسطح نشده یا ufdt ) از درخت دستگاه مسطح شده (FDT) می‌سازد، بنابراین می‌تواند ادغام دو فایل .dtb را از O(N^ 2 ) به O(N) بهبود بخشد، که در آن N تعداد گره‌های موجود در درخت است.

تست عملکرد

در آزمایش داخلی گوگل، استفاده از libufdt روی گره‌های .dtb و .dtbo DT منجر به اندازه فایل‌های 70618 و 8566 بایت پس از کامپایل می‌شود. در مقایسه با پیاده‌سازی DTO منتقل شده از FreeBSD (زمان اجرای 124 میلی‌ثانیه)، زمان اجرای DTO libufdt 10 میلی‌ثانیه است.

تست عملکرد برای دستگاه‌های پیکسل در مقایسه با libufdt و libfdt . تأثیر تعداد گره‌های پایه مشابه است، اما شامل تفاوت‌های زیر می‌شود:

  • ۵۰۰ عملیات همپوشانی (اضافه کردن یا لغو کردن) ۶ تا ۸ برابر اختلاف زمانی دارند
  • ۱۰۰۰ عملیات همپوشانی (اضافه کردن یا لغو کردن) ۸ تا ۱۰ برابر اختلاف زمانی دارند

مثال با تعداد افزودن مقدار X:

شکل ۱. تعداد الحاقات X است.

مثال با تعداد نادیده گرفته شده روی X:

شکل ۲. تعداد تکرارشونده X است.

libufdt با برخی از APIها و ساختارهای داده libfdt توسعه داده شده است. هنگام استفاده از libufdt ، باید libfdt وارد و پیوند دهید (با این حال، در کد خود می‌توانید از API libfdt برای کار با DTB یا DTBO استفاده کنید).

رابط برنامه‌نویسی کاربردی توسعه‌یافته توسط libufdt

API اصلی برای DTO در libufdt به شرح زیر است:

struct fdt_header *ufdt_apply_overlay(
        struct fdt_header *main_fdt_header,
        size_t main_fdt_size,
        void *overlay_fdt,
        size_t overlay_size);

پارامتر main_fdt_header فایل DT اصلی و overlay_fdt بافری است که حاوی محتویات یک فایل .dtbo است. مقدار بازگشتی یک بافر جدید حاوی فایل DT ادغام شده (یا در صورت خطا null ) است. فایل DT ادغام شده به صورت FDT قالب‌بندی شده است که می‌توانید هنگام شروع هسته به هسته ارسال کنید.

بافر جدید از مقدار برگشتی توسط dto_malloc() ایجاد می‌شود، که شما باید هنگام انتقال libufdt به bootloader آن را پیاده‌سازی کنید. برای پیاده‌سازی‌های مرجع، به sysdeps/libufdt_sysdeps_*.c مراجعه کنید.

محدودیت‌های گره ریشه

شما نمی‌توانید یک گره یا ویژگی جدید را در گره ریشه DT اصلی قرار دهید زیرا عملیات همپوشانی به برچسب‌ها متکی هستند. از آنجا که DT اصلی باید یک برچسب تعریف کند و DT همپوشانی، گره‌هایی را که باید با برچسب‌ها پوشانده شوند، تعیین می‌کند، نمی‌توانید برای گره ریشه برچسبی تعیین کنید (و بنابراین نمی‌توانید گره ریشه را پوشش دهید).

فروشندگان SoC باید قابلیت همپوشانی DT اصلی را تعریف کنند؛ ODM/OEMها فقط می‌توانند گره‌هایی را که برچسب‌های آنها توسط فروشنده SoC تعریف شده است، اضافه یا لغو کنند. به عنوان یک راه حل، می‌توانید یک گره odm را زیر گره ریشه در DT پایه تعریف کنید و به همه گره‌های ODM در DT پوششی اجازه دهید گره‌های جدید اضافه کنند. به عنوان یک روش جایگزین، می‌توانید همه گره‌های مربوط به SoC در DT پایه را در یک گره soc زیر گره ریشه قرار دهید، همانطور که در زیر توضیح داده شده است:

فایل اصلی.dts روکش.dts
/dts-v1/;

/ {
    compatible = "corp,bar";
    ...

    chosen: chosen {
        bootargs = "...";
    };

    /* nodes for all soc nodes */
    soc {
        ...
        soc_device@0: soc_device@0 {
            compatible = "corp,bar";
            ...
        };
        ...
    };

    odm: odm {
        /* reserved for overlay by odm */
    };
};
/dts-v1/;
/plugin/;

/ {
};

&chosen {
    bootargs_ex = "...";
};

&odm {
    odm_device@0 {
        ...
    };
    ...
};

از پوشش‌های فشرده استفاده کنید

اندروید ۹ پشتیبانی از استفاده از پوشش‌های فشرده در تصویر DTBO را هنگام استفاده از نسخه ۱ هدر جدول DT اضافه می‌کند. هنگام استفاده از هدر DTBO نسخه ۱، چهار بیت کم‌ارزش‌تر از فیلد پرچم‌ها در dt_table_entry، فرمت فشرده‌سازی ورودی DT را نشان می‌دهند.

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' are used to 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 */
};

در حال حاضر، فشرده‌سازی‌های zlib و gzip پشتیبانی می‌شوند.

enum dt_compression_info {
    NO_COMPRESSION,
    ZLIB_COMPRESSION,
    GZIP_COMPRESSION
};

اندروید ۹ پشتیبانی از تست پوشش‌های فشرده را به تست VtsFirmwareDtboVerification اضافه کرده است تا به شما در تأیید صحت برنامه پوششی کمک کند.

نمونه پیاده‌سازی DTO

دستورالعمل‌های زیر شما را در پیاده‌سازی نمونه‌ای از DTO با libufdt راهنمایی می‌کند (کد نمونه در زیر آمده است).

نمونه دستورالعمل‌های DTO

  1. کتابخانه‌ها را اضافه کنید. برای استفاده از libufdt ، libfdt برای ساختارهای داده و APIها اضافه کنید:
    #include <libfdt.h>
    #include <ufdt_overlay.h>
  2. بارگذاری فایل اصلی (main DT) و فایل پوششی (overlay DT). بارگذاری فایل‌های .dtb و .dtbo از حافظه به حافظه (memory) (مراحل دقیق به طراحی شما بستگی دارد). در این مرحله، باید بافر و اندازه فایل‌های .dtb / .dtbo را داشته باشید:
    main_size = my_load_main_dtb(main_buf, main_buf_size)
    overlay_size = my_load_overlay_dtb(overlay_buf, overlay_buf_size);
  3. DT ها را روی هم قرار دهید:
    1. برای دریافت هدر FDT برای DT اصلی ufdt_install_blob() استفاده کنید:
      main_fdt_header = ufdt_install_blob(main_buf, main_size);
      main_fdt_size = main_size;
    2. برای دریافت یک DT ادغام‌شده در قالب FDT، تابع ufdt_apply_overlay() را در DTO فراخوانی کنید:
      merged_fdt = ufdt_apply_overlay(main_fdt_header, main_fdt_size,
                                      overlay_buf, overlay_size);
    3. برای بدست آوردن اندازه dtc_totalsize() از merged_fdt استفاده کنید:
      merged_fdt_size = dtc_totalsize(merged_fdt);
    4. برای شروع هسته، DT ادغام‌شده را ارسال کنید:
      my_kernel_entry(0, machine_type, merged_fdt);

نمونه کد DTO

#include <libfdt.h>
#include <ufdt_overlay.h>



{
  struct fdt_header *main_fdt_header;
  struct fdt_header *merged_fdt;

  /* load main dtb into memory and get the size */
  main_size = my_load_main_dtb(main_buf, main_buf_size);

  /* load overlay dtb into memory and get the size */
  overlay_size = my_load_overlay_dtb(overlay_buf, overlay_buf_size);

  /* overlay */
  main_fdt_header = ufdt_install_blob(main_buf, main_size);
  main_fdt_size = main_size;
  merged_fdt = ufdt_apply_overlay(main_fdt_header, main_fdt_size,
                                  overlay_buf, overlay_size);
  merged_fdt_size = dtc_totalsize(merged_fdt);

  /* pass to kernel */
  my_kernel_entry(0, machine_type, merged_fdt);
}