2016-05-14

LLCON - низкоуровневый вывод ядерных логов на дисплей Android устройства

После завершения проекта Interactive Bootloader пришла идея, что за место логотипа бутлоадера и бутанимации можно на экран выводить ядерные логи. Причём вывод этих логов можно реализовать на самом раннем этапе работы Linux-ядра из-за чего время показа логотипа бутлоадера будет совсем ничтожным.

Перед началом рассказа о LLCON стоит упомянуть о FRAMEBUFFER_CONSOLE. Данная опция Linux-ядра включает функционал по выводу ядерных логов на экран устройства. Но данный функционал начинает свою работу только после инициализации видео-драйверов и драйвера самой FRAMEBUFFER консоли. И поэтому большинство ядерных логов просто напросто не отображается, а логотип бутлоадера отображается очень значительное время. Поэтому на стандартную FRAMEBUFFER консоль даже и не стоит смотреть, т.к. время её работы довольно короткое.

Т.к. функционал низкоуровневого отображения символов мне уже приходилось реализовывать в IBL, то данный функционал частично был перенесён в LLCON.

Для работы LLCON достаточно в командной строке Linux-ядра указать следующее:
androidboot.llcon=<mode>,<delay>,<textwrap>,<fb_addr>,<fb_bpp>,<fb_height>,<fb_width>,<fb_stride>,<font_size>,<font_color>

Расшифровка параметров:

mode:
    0 = LLCON отключён
    1 = синхронный вывод логов (постраничный скроллинг)
    2 = асинхронный вывод логов (построчный скроллинг)

delay:
    Задержка в милисекундах.
    Данная задержка используется в потоке, выводящем графику на экран.
    Рекомендуемое значение: 100.

textwrap:
    0 = перенос текста на новые строки запрещён
    1 = перенос текста на новые строки разрешён

fb_addr:
    Физический адрес FrameBuffer. Узнать этот адрес можно в DeviceTree.
    (см. параметр "qcom,memblock-reserve" в ветке "qcom,mdss_fb_primary")

fb_bpp:
    Формат пикселей дисплея.
    Данный параметр не используется.

fb_height:
    Высота дисплея в пикселях.

fb_width:
    Ширина дисплея в пикселях.

fb_stride:
    Размер одной строки в пикселях или в байтах.

font_size:
    Размер шрифта. Поддерживаемые значения: 6, 8, 10, 12.
    Каждый шрифт нужно отдельно подключать в def_config.

font_color:
    Цвет символов в HEX формате RGB888.

Пример заполнения параметров:
androidboot.llcon=2,100,0,0x03200000,24,1280,720,720,8,0xFFFFFF

Сразу стоит отметить, что функцинал LLCON позволяет использовать значение fb_addr взятое из DeviceTree. При этом значение из командной строки просто игнорируется. Для этого Linux-ядро нужно пропатчить таким вот образом:
int __init dt_scan_for_memory_reserve(unsigned long node, const char *uname,
    int depth, void *data)
{
  char *memory_name_prop;
  unsigned int *memory_remove_prop;

....
  
mem_reserve:

  if (memory_reserve_prop) {
    if (memory_reserve_prop_length != (2*sizeof(unsigned int))) {
      WARN(1, "Memory reserve malformed\n");
      goto out;
    }

    memory_start = be32_to_cpu(memory_reserve_prop[0]);
    memory_size = be32_to_cpu(memory_reserve_prop[1]);

    ret = memblock_reserve(memory_start, memory_size);
    if (ret)
      WARN(1, "Failed to reserve memory %x-%x\n",
        memory_start, memory_start+memory_size);
    else
      pr_info("Node %s memblock_reserve memory %x-%x\n",
        uname, memory_start, memory_start+memory_size);
#ifdef CONFIG_LLCON
    if (!ret && strcmp(uname, "qcom,mdss_fb_primary") == 0) {
      llcon_set_fb_addr((void *)memory_start, memory_size);
    }
#endif
  }

out:
  return 0;
}

Стоит отметить, что при добавлении LLCON в ядро следует включить следующие опции:
CONFIG_VT=y
CONFIG_LLCON=y
CONFIG_FONTS=y
CONFIG_FONT_6x11=y
CONFIG_FONT_8x16=y
CONFIG_FONT_SUN12x22=y
При этом можно включать только необходимые вам наборы шрифтов.

Для того, что бы LLCON не конфликтовал с MDSS драйвером, занимающимся выводом графики, нужно вовремя этот самый LLCON отключить. Для этого нужно немного пропатчить MDSS драйвер:
static int mdss_fb_ioctl(struct fb_info *info, unsigned int cmd,
       unsigned long arg)
{
  struct msm_fb_data_type *mfd;
  void __user *argp = (void __user *)arg;
  struct mdp_page_protection fb_page_protection;
  int ret = -ENOSYS;
  struct mdp_buf_sync buf_sync;
  struct msm_sync_pt_data *sync_pt_data = NULL;
  unsigned int dsi_mode = 0;

  if (!info || !info->par)
    return -EINVAL;

  mfd = (struct msm_fb_data_type *)info->par;
  if (!mfd)
    return -EINVAL;

  if (mfd->shutdown_pending)
    return -EPERM;

#ifdef CONFIG_LLCON
  if ( cmd != MSMFB_NOTIFY_UPDATE 
    && cmd != MSMFB_OVERLAY_VSYNC_CTRL
    && cmd != MSMFB_METADATA_GET
    && cmd != MSMFB_DISPLAY_COMMIT ) {
    llcon_exit();
  }
#endif

  atomic_inc(&mfd->ioctl_ref_cnt);

  mdss_fb_power_setting_idle(mfd);

....

exit:
  if (!atomic_dec_return(&mfd->ioctl_ref_cnt))
    wake_up_all(&mfd->ioctl_q);

  return ret;
}

Так же стоит отметить, что Android оболочке нужно сообщить о том, что при работе LLCON не следует пытаться выводить на экран устройства бутанимацию. Для этого нужно уже патчить код не ядра, а код init модуля. Ссылка на сам патч: github.com

Ограничения текущей версии LLCON:
  • поддерживаются только дисплеи RGB888 (24-bit)
  • поддерживаются дисплеи с нормальной ориентацией
  • поддерживается только Qualcomm платформа

Исходники LLCON:
  • для ядер версии 3.4: kernel   /   device
  • для ядер версии 3.10: kernel 

Демонстрация работы

LLCON 1 - постраничный режим, шрифт 6x11:

LLCON 2 - построчный режим, шрифт 8x16:


Комментариев нет:

Отправить комментарий