2016-01-15

Патчинг андройдовской либы liboemcamera.so для корректной работы камеры

В данном руководстве попробую описать патчинг ARM-либы liboemcamera.so, которая была допилена и скомпилирована программистами Huawei для аппарата Ascend Y300 (платформа msm8x25).


Целевым аппаратом для использования пропатченной либы является китайский смартфон Innos D9 (в простонародье Highscreen Boost или DNS s4502), для которого производитель зажал исходники (таже платформа msm8x25). Для этого аппарата решил сделать прошивку СМ11 на основе ядра chil360-kernel (это ядро создано для Huawei Y300/G510). Прошивку СМ11 успешно собрал и установил в свой китайский аппарат.

После первичного тестирования прошивки СМ11 решил заняться "поднятием" камеры. Драйвера использующихся камер добавил в ядро и пересобрал прошивку СМ11. Так же добавил в прошивку СМ11 нужные для камер libchromatix-либы, взятые со стоковой прошивки (в том числе и стоковую версию liboemcamera.so). При тестировании камеры демон камеры (mm-qcamera-daemon) падал в том месте, в котором идёт обработка результата команды get_capabilities (внутренняя функция liboemcamera). Пробовал много разных вариантов решения сей траблы, но ничего не помогало. Так же выяснил, что либа liboemcamera скомпилирована без опции USE_ION, которая необходима при использовании ядра chil360-kernel (данное ядро вовсю использует функционал MSM ION). Поэтому решил попробовать взять все либы камер от Huawei Ascend Y300.

Тут возникла небольшая сложность, т.к. в Innos D9 используется камера ov8825_truly_cm8313, поддержка которой отсутствует в сторонней либе liboemcamera. Так же заметил, что оба варианта либы liboemcamera имеют поддержку камеры ov8825 (эта камера присутствует в стандартных исходниках проприетариев от Qualcomm). По этой причине решил для начала протестировать камеру ov8825_truly_cm8313, используя libchromatix-либы от ov8825 камеры. Для этого пришлось в ядре изменить название камеры на ov8825. Тестирование прошло на отлично, т.к. даже фотки удалось сделать. Но для меня использование неродных настроек для камеры является совсем нежелательным решением. Да и из названия камеры видно, что используется нестандартная оптика от Truly Opto-Electronics.

Запустил IDA и начал изучать содержимое стоковой либы liboemcamera. В дизасме стоковой либы liboemcamera сразу увидел, что именно присутствием особых настроек линзы и отличается камера ov8825_truly_cm8313 от камеры ov8825. Поэтому твёрдо решил добавить в стороннюю либу liboemcamera поддержку камеры ov8825_truly_cm8313.

Перед патчингом сторонней либы нужно исследовать нужные участки кода обоих вариантов либы liboemcamera. Для начала нашёл в сторонней либе liboemcamera функцию, которая занимается загрузкой соответствующего настроечного libchromatix-модуля камеры ov8825 (файлы libchromatix_ov8825*.so). Эта функция имеет название sensor_init и код её примерно таков:
int8_t sensor_init(sensor_ctrl_t *sctrl)
{
  int8_t rc = 1;
  uint8_t cnt;
  int8_t (*sensor_process_start)(void *sctrl);

  sensor_common_parm_init(sctrl);

  rc = ioctl(sctrl->sfd, MSM_CAM_IOCTL_GET_SENSOR_INFO, &sctrl->sinfo);
  ....
  LOGI("kernel returned %s\n", sctrl->sinfo.name);
  
  for (cnt = 0; cnt < (sizeof(hw_sensors) / sizeof(hw_sensors[0])); cnt++) {
    if (!strcmp(sctrl->sinfo.name, hw_sensors[cnt].name_eeprom)) {
      memset(sctrl->sinfo.name, 0, sizeof(sctrl->sinfo.name));
      strcpy(sctrl->sinfo.name, hw_sensors[cnt].name_orig);
      LOGI("kernel returned %s\n", sctrl->sinfo.name);
      break;
    }
  }
  
  for (cnt = 0; cnt < (sizeof(sensors) / sizeof(sensors[0])); cnt++) {
    LOGI("kernel retuned %s, compared to %s\n", sctrl->sinfo.name, sensors[cnt].sname);
    if (!strcmp(sctrl->sinfo.name, sensors[cnt].sname)) {

      strlcpy(sctrl->sensor.sensor_model_no, sctrl->sinfo.name, SENSOR_MODEL_NO);

      /* Load chromatix file from chromatixType variable */
      sctrl->start = &sensors[cnt];
      rc = sctrl->start->s_start(sctrl);
      if (rc < 0) {
          CDBG_ERROR("%s:%d failed\n", __func__, __LINE__);
          return rc;
      }

      sctrl->sensor.out_data.pxlcode = sctrl->sinfo.pxlcode;

      if (sctrl->sensor.out_data.sensor_output.output_format == SENSOR_BAYER) {
        rc = sensor_load_chromatix(sctrl);
        if( rc != 0) {
          CDBG_ERROR("%s:%d:Error:Failed to load chromatix file\n", __func__, __LINE__);
          return rc;
        }
      }

      break;
    }
  }
  ....
  return 0;
}
Кусок кода, который осуществляет поиск по массиву hw_sensors, добавлен программистами Huawei. Этот массив используется для трансляции внутреннего названия модуля камеры, возвращаемое ядром, в название, которое используется либой liboemcamera. К примеру название "23060110FA-SAM-3-Y300" будет транслироваться в "s5k4e1_3_y300". Данная доработка от программистов Huawei может в дальнейшем пригодится, поэтому частично приведу содержание масива hw_sensors:
static struct {
  const char * name_eeprom;
  const char * name_orig;
} hw_sensors[] = {
  { "23060068FA-MT-L",       "mt9e013" },
  ....
  { "23060110FA-SAM-3-Y300", "s5k4e1_3_y300" },
  ....
  { "23060075FF-GC-F",       "gc0313" },
  { "23060075FF-BYD-B",      "bf3905" },
};
После поиска в массиве hw_sensors происходит поиск названия в массиве sensors, в каждом элементе которого есть указатель на функцию инициализации модуля камеры и указатель на структуру, содержащую полные имена настроечных модулей соответствующей камеры. Приведу описание данной структуры, описывающей каждый элемент массива sensors:
typedef struct {
  const char *sname;
  int8_t (*s_start)(void *);
  char **sensor_load_chromatixfile;
} sensor_proc_start_t;  
Частичное содержание массива sensors таково:
static sensor_proc_start_t sensors[] = {
  ....
  { "s5k4e1_3_y300", s5k4e1_3_y300_process_start, s5k4e1_3_y300_load_chromatix },
  ....
  { "ov8825"       , ov8825_process_start       , ov8825_load_chromatix        },
  ....
};

char *s5k4e1_3_y300_load_chromatix[SENSOR_LOAD_CHROMATIX_MAX] = {
  "libchromatix_s5k4e1_3_y300_preview.so",
  "libchromatix_s5k4e1_3_y300_default_video.so",
  NULL, /* HD video recording */
  NULL, /* HFR 60 fps video recording */
  NULL, /* HFR 90 fps video recording */
  NULL, /* HFR 120 fps video recording */
  NULL, /* HFR 150 fps video recording */
  NULL, /* AR */
  "libchromatix_s5k4e1_3_y300_preview.so",
};

char *ov8825_load_chromatix[SENSOR_LOAD_CHROMATIX_MAX] = {
  "libchromatix_ov8825_preview.so",        /* camera and camcorder preview */ 
  "libchromatix_ov8825_default_video.so",  /* Non HD Video recording */
  NULL, /* HD video recording */
  NULL, /* HFR 60 fps video recording */
  NULL, /* HFR 90 fps video recording */
  NULL, /* HFR 120 fps video recording */
  NULL, /* HFR 150 fps video recording */
  NULL, /* AR */
  "libchromatix_ov8825_preview.so",        /* ZSL */
};
В приведённом листинге функции s5k4e1_3_y300_process_start и ov8825_process_start выполняют инициализацию важных структур либы liboemcamera. Вызываются эти функции сразу после загрузки libchromatix-модуля. Взглянем на содержимое функции ov8825_process_start:
int8_t ov8825_process_start(void *ctrl)
{
  sensor_ctrl_t *sctrl = (sensor_ctrl_t *) ctrl;
  fn_table = &ov8825_func_tbl;
  sensor.inputformat = ov8825_inputformat;
  sensor.crop_info = ov8825_cropinfo;
  sensor.mode_res = ov8825_mode_res;
  sensor.sensor_csi_params.csic_params = &ov8825_csi_params_array[0];

  sensor_util_get_output_info(sctrl);

  sensor.op_mode = SENSOR_MODE_VIDEO;

  sensor.out_data.sensor_output.connection_mode = SENSOR_MIPI_CSI;
  sensor.out_data.sensor_output.output_format = SENSOR_BAYER;
  sensor.out_data.sensor_output.raw_output = SENSOR_10_BIT_DIRECT;

  sensor.out_data.aec_info.max_gain = 8.0;
  sensor.out_data.aec_info.max_linecount =
    sensor.output_info[sctrl->sensor.mode_res[SENSOR_MODE_PREVIEW]].frame_length_lines * 24;
  sensor.snapshot_exp_wait_frames = 1;

  sensor_util_config(sctrl);
  return TRUE;
}
Хочу заметить, что реализации функции ov8825_process_start в обоих версиях либы liboemcamera полностью эдентичные (сравнивал в дизасме IDA).

Теперь снова вернемся к функции sensor_init и подумаем, как же заставить сторонюю либу liboemcamera загружать стороние модули libchromatix для камеры ov8825_truly_cm8313. Первое что приходит в голову - это изменить в массиве sensors содержание элемента с именем "ov8825". Но я не стал так делать по двум причинам: хочется оставить нетронутой реализацию оригинальной камеры ov8825, да и тело функции ov8825_process_start имеет существенные отличия от тела функции ov8825_truly_cm8313_process_start.

Подходящим кандидатом для патчинга является элемент с названием "s5k4e1_3_y300". Для этого есть две причины: имя камеры довольно длиннное и тело функции s5k4e1_3_y300_process_start имеет очень мало отличий от ov8825_truly_cm8313_process_start. Для начала нам нужно пропатчить содержимое структуры hw_sensors, т.к. в массиве sensors отсутствуют элементы с длинными именами.

В IDA переходим к началу массива hw_sensors (адрес 0x00095BFC):
00095BFC 2C E0 08 00   DCD a23060068faMtL      ; "23060068FA-MT-L"
00095C00 3C E0 08 00   DCD aMt9e013            ; "mt9e013"
....
00095C2C B8 E0 08 00   DCD a23060110faSa_0     ; "23060110FA-SAM-3-Y300"
00095C30 CE E0 08 00   DCD aS5k4e1_3_y300      ; "s5k4e1_3_y300"
Двойным кликом по названию a23060110faSa_0 переходим к нужным нам строчкам:
0008E0B8  DCB "23060110FA-SAM-3-Y300",0
0008E0CE  DCB "s5k4e1_3_y300",0
Переключаемся на закладку "Hex View" и находим адрес 0x0008E0B8:
0008E0B8  32 33 30 36 30 31 31 30  46 41 2D 53 41 4D 2D 33  23060110FA-SAM-3
0008E0C8  2D 59 33 30 30 00 73 35  6B 34 65 31 5F 33 5F 79  -Y300.s5k4e1_3_y
0008E0D8  33 30 30 00 32 33 30 36  30 30 37 35 46 46 2D 4D  300.23060075FF-M
Нажимаем F2 и изменяем строку "23060110FA-SAM-3-Y300" на "ov8825_truly_cm8313", а строчку "s5k4e1_3_y300" на "ov8825_truly", не забывая добавлять к конец строк нули. По окончанию редактирования нужно снова нажать F2. Полученный результат таков:
0008E0B8  6F 76 38 38 32 35 5F 74  72 75 6C 79 5F 63 6D 38  ov8825_truly_cm8
0008E0C8  33 31 33 00 00 00 6F 76  38 38 32 35 5F 74 72 75  313...ov8825_tru
0008E0D8  6C 79 00 00 32 33 30 36  30 30 37 35 46 46 2D 4D  ly..23060075FF-M
Хочу заметить, что имя камеры пришлось немного урезать. По этой причине имена оригинальных файлов libchromatix придётся изменить, вырезав из оных подстроку "_cm8313". Зато в ядре название "ov8825_truly_cm8313" изменять не нужно.

Теперь возвращаемся к началу массива массива hw_sensors (адрес 0x00095BFC) и наблюдаем изменения:
00095BFC 2C E0 08 00   DCD a23060068faMtL      ; "23060068FA-MT-L"
00095C00 3C E0 08 00   DCD aMt9e013            ; "mt9e013"
....
00095C2C B8 E0 08 00   DCD a23060110faSa_0     ; "ov8825_truly_cm8313"
00095C30 CE E0 08 00   DCD aS5k4e1_3_y300      ; "ov8825_truly"
Сохранение результатов патчинга в IDA реализовано через диалог "Apply patches to input file" (Edit -> Patch Program), в котором не забудьте поставить галочку на против опции "Create backup".

Теперь нужно пропатчить имена libchromatix-файлов, что бы либа liboemcamera загружала оные при инициализации камеры. Для этого в IDA переходим к содержимому массива sensors (адрес 0x0009BD4C) и ищем в нём указатель на строку "ov8825_truly":
0009BD4C 7D E0 08 00   DCD aS5k4e1                        ; "s5k4e1"
0009BD50 29 C9 05 00   DCD s5k4e1_process_start+1
0009BD54 24 BF 09 00   DCD s5k4e1_load_chromatix

0009BD58 95 E0 08 00   DCD aS5k4e1_3                      ; "s5k4e1_3"
0009BD5C E9 C9 05 00   DCD s5k4e1_3_process_start+1
0009BD60 48 BF 09 00   DCD s5k4e1_3_load_chromatix

0009BD64 CE E0 08 00   DCD aS5k4e1_3_y300                 ; "ov8825_truly"
0009BD68 F3 C9 05 00   DCD s5k4e1_3_y300_process_start+1
0009BD6C 74 BF 09 00   DCD s5k4e1_3_y300_load_chromatix
Двойным кликом по названию s5k4e1_3_y300_load_chromatix переходим к содержимому этой структуры:
0009BF74 16 E2 08 00   DCD aLibchromati_50   ; "libchromatix_s5k4e1_3_y300_preview.so"
0009BF78 3C E2 08 00   DCD aLibchromati_51   ; "libchromatix_s5k4e1_3_y300_default_video.so"
0009BF7C 00 00 00 00   DCD 0
0009BF80 00 00 00 00   DCD 0
0009BF84 00 00 00 00   DCD 0
0009BF88 00 00 00 00   DCD 0
0009BF8C 00 00 00 00   DCD 0
0009BF90 00 00 00 00   DCD 0
0009BF94 16 E2 08 00   DCD aLibchromati_50   ; "libchromatix_s5k4e1_3_y300_preview.so"
От указателей aLibchromati_5x переходим к соответствующим строкам и по аналогии патчим имена libchromatix-файлов. В итоге должно получиться следующее:
0008E216  6C 69 62 63 68 72 6F 6D  61 74 69 78 5F 6F 76 38  libchromatix_ov8
0008E226  38 32 35 5F 74 72 75 6C  79 5F 70 72 65 76 69 65  825_truly_previe
0008E236  77 2E 73 6F 00 00 6C 69  62 63 68 72 6F 6D 61 74  w.so..libchromat

0008E23C  6C 69 62 63 68 72 6F 6D  61 74 69 78 5F 6F 76 38  libchromatix_ov8
0008E24C  38 32 35 5F 74 72 75 6C  79 5F 64 65 66 61 75 6C  825_truly_defaul
0008E25C  74 5F 76 69 64 65 6F 2E  73 6F 00 00 6C 69 62 63  t_video.so..libc

0008E216  DCB "libchromatix_ov8825_truly_preview.so",0
0008E23B  DCB    0
0008E23C  DCB "libchromatix_ov8825_truly_default_video.so",0
0008E267  DCB    0
Но патчингом нескольких строчек дело не обойдётся, т.к. частично процедура инициализации любой камеры выполняется в либе liboemcamera. Если быть точнее, то после произведёного патчинга за инициализацию камеры будет отвечать функция s5k4e1_3_y300_process_start (см. чуть выше адрес 0x0009BD68). Взлянем на код этой функции в дизасме:
0005C9F2                     EXPORT s5k4e1_3_y300_process_start
0005C9F2 08 B5               PUSH       {R3,LR}
0005C9F4 FF F7 98 FF         BL         s5k4e1_process_start
0005C9F8 01 20               MOVS       R0, #1
0005C9FA 08 BD               POP        {R3,PC}

Можно заметить, что эта функция просто напросто вызывает функцию s5k4e1_process_start, которая и выполняет всю работу.
0005C928                     EXPORT s5k4e1_process_start
0005C928 70 B5               PUSH       {R4-R6,LR}
0005C92A 00 F5 62 44         ADD.W      R4, R0, #0xE200
0005C92E 06 46               MOV        R6, R0
0005C930 29 4B               LDR        R3, =(s5k4e1_func_tbl - 0x5C93C)
0005C932 2A 4A               LDR        R2, =(s5k4e1_inputformat - 0x5C940)
0005C934 03 25               MOVS       R5, #3
0005C936 2A 49               LDR        R1, =(unk_9EF28 - 0x5C946)
0005C938 7B 44               ADD        R3, PC ; s5k4e1_func_tbl
0005C93A 2A 48               LDR        R0, =(s5k4e1_mode_res - 0x5C94C)
0005C93C 7A 44               ADD        R2, PC ; s5k4e1_inputformat
0005C93E C4 F8 E0 31         STR.W      R3, [R4,#480]
0005C942 79 44               ADD        R1, PC ; unk_9EF28
0005C944 C4 F8 14 21         STR.W      R2, [R4,#276]
0005C948 78 44               ADD        R0, PC ; s5k4e1_mode_res
0005C94A C4 F8 18 11         STR.W      R1, [R4,#280]
0005C94E C4 F8 24 01         STR.W      R0, [R4,#292]
0005C952 30 46               MOV        R0, R6
0005C954 FE F7 F4 F9         BL         sensor_util_get_output_info
0005C958 D4 F8 24 21         LDR.W      R2, [R4,#0x124]
0005C95C E5 63               STR        R5, [R4,#0x3C]
0005C95E 00 23               MOVS       R3, #0
0005C960 01 25               MOVS       R5, #1
0005C962 C4 F8 54 31         STR.W      R3, [R4,#0x154]
0005C966 C4 F8 58 51         STR.W      R5, [R4,#0x158]
0005C96A 4F F0 83 4C         MOV.W      R12, #0x41800000   ; {#0x41000000}
0005C96E C4 F8 5C 51         STR.W      R5, [R4,#0x15C]
0005C972 14 21               MOVS       R1, #0x14
0005C974 C4 F8 A0 C1         STR.W      R12, [R4,#0x1A0]
0005C978 90 68               LDR        R0, [R2,#8]
0005C97A 18 22               MOVS       R2, #0x18
0005C97C 01 FB 00 63         MLA.W      R3, R1, R0, R6
0005C980 0F 48               LDR        R0, =0x405F5C29
0005C982 03 F5 62 4C         ADD.W      R12, R3, #0xE200
0005C986 0F 4B               LDR        R3, =0x3FB33333
0005C988 BC F8 7A 10         LDRH.W     R1, [R12,#0x7A]
0005C98C 51 43               MULS       R1, R2
0005C98E C4 F8 C8 01         STR.W      R0, [R4,#0x1C8]
0005C992 C4 F8 A4 11         STR.W      R1, [R4,#0x1A4]
0005C996 C4 F8 CC 31         STR.W      R3, [R4,#0x1CC]
0005C99A 0B 4A               LDR        R2, =0x400CCCCD   ; {#0x4029999A}
0005C99C 0B 49               LDR        R1, =0x3FFC28F6
0005C99E 0C 4B               LDR        R3, =0x422A0000   ; {#0x422ACCCD}
0005C9A0 0C 48               LDR        R0, =0x425B3333   ; {#0x425D999A}
0005C9A2 25 67               STR        R5, [R4,#0x70]
0005C9A4 C4 F8 D0 21         STR.W      R2, [R4,#0x1D0]
0005C9A8 C4 F8 D8 01         STR.W      R0, [R4,#0x1D8]
0005C9AC 30 46               MOV        R0, R6
0005C9AE C4 F8 D4 11         STR.W      R1, [R4,#0x1D4]
0005C9B2 C4 F8 DC 31         STR.W      R3, [R4,#0x1DC]
0005C9B6 FE F7 8B F8         BL         sensor_util_config
0005C9BA 28 46               MOV        R0, R5
0005C9BC 70 BD               POP        {R4-R6,PC}
0005C9BC     ; End of function s5k4e1_process_start
0005C9BC     ; ---------------------------------------------------------------------------
0005C9BE 00 BF                        DCW 0xBF00
0005C9C0 29 5C 5F 40  dword_5C9C0     DCD 0x405F5C29
0005C9C4 33 33 B3 3F  dword_5C9C4     DCD 0x3FB33333
0005C9C8 CD CC 0C 40  dword_5C9C8     DCD 0x400CCCCD
0005C9CC F6 28 FC 3F  dword_5C9CC     DCD 0x3FFC28F6
0005C9D0 00 00 2A 42  dword_5C9D0     DCD 0x422A0000
0005C9D4 33 33 5B 42  dword_5C9D4     DCD 0x425B3333
0005C9D8 5C F6 03 00  off_5C9D8       DCD s5k4e1_func_tbl - 0x5C93C
0005C9DC E0 25 04 00  off_5C9DC       DCD s5k4e1_inputformat - 0x5C940
0005C9E0 E2 25 04 00  off_5C9E0       DCD s5k4e1_cropinfo - 0x5C946
0005C9E4 8C F5 03 00  off_5C9E4       DCD s5k4e1_mode_res - 0x5C94C
Придётся патчить данную функцию, т.к. она немного не соотвутствует оригинальной функции ov8825_truly_cm8313_process_start. При этом мы лишаемся поддержки любой камеры типа s5k4e1, т.к. у них общая функция инициализации.

В приведённом дизасм листинге я в фигурных скобочках указал значения, которые присутствуют в оригинальной функции ov8825_truly_cm8313_process_start. Поэтому для начала нужно пропатчить соответствующие ячейки памяти, что бы изменить эти константы. В результате патча получил следующее:
....
0005C966 C4 F8 58 51         STR.W      R5, [R4,#0x158]
0005C96A 4F F0 82 4C         MOV.W      R12, #0x41000000
0005C96E C4 F8 5C 51         STR.W      R5, [R4,#0x15C]
....
0005C9BE 00 BF                        DCW 0xBF00
0005C9C0 A4 70 9D 40  dword_5C9C0     DCD 0x409D70A4
0005C9C4 33 33 B3 3F  dword_5C9C4     DCD 0x3FB33333
0005C9C8 9A 99 29 40  dword_5C9C8     DCD 0x4029999A
0005C9CC F6 28 FC 3F  dword_5C9CC     DCD 0x3FFC28F6
0005C9D0 CD CC 2A 42  dword_5C9D0     DCD 0x422ACCCD
0005C9D4 9A 99 5D 42  dword_5C9D4     DCD 0x425D999A
....
Кроме отличных констант функция s5k4e1_process_start использует свои структуры s5k4e1_func_tbl, s5k4e1_inputformat, s5k4e1_cropinfo и s5k4e1_mode_res. При изучении этих сруктур стало ясно, что в обоих версиях либы liboemcamera структура s5k4e1_cropinfo эдентична структуре ov8825_truly_cm8313_cropinfo, а структура s5k4e1_mode_res эдентична структуре ov8825_truly_cm8313_mode_res. Поэтому придётся патчить содержимое структур s5k4e1_func_tbl и s5k4e1_inputformat.

При изучении структур так же выяснилось, что структура ov8825_truly_cm8313_inputformat эдентична структуре ov8825_inputformat. Поэтому для достижения цели достаточно в функции s5k4e1_process_start заменить адрес структуры s5k4e1_inputformat на адрес структуры ov8825_inputformat (адрес 0x0009A2FC). Перед патчингом нужно произвести предварительный расчёт:
0x0009A2FC - 0x0005C940 = 0x0003D9BC

Результат патчинга адреса структуры inputformat:
0005C9D8 5C F6 03 00  off_5C9D8       DCD s5k4e1_func_tbl - 0x5C93C
0005C9DC BC D9 03 00  off_5C9DC       DCD ov8825_inputformat - 0x5C940
0005C9E0 E2 25 04 00  off_5C9E0       DCD s5k4e1_cropinfo - 0x5C946
0005C9E4 8C F5 03 00  off_5C9E4       DCD s5k4e1_mode_res - 0x5C94C
Перед патчингом структуры s5k4e1_func_tbl посмотрим на её содержимое:
0009BF98 C9 AD 05 00  s5k4e1_func_tbl DCD sensor_util_set_op_mode+1
0009BF9C C9 B0 05 00                  DCD sensor_util_get_mode_aec_info+1
0009BFA0 3D AF 05 00                  DCD sensor_util_get_dim_info+1
0009BFA4 41 B0 05 00                  DCD sensor_util_get_preview_fps_range+1
0009BFA8 E5 AB 05 00                  DCD sensor_util_set_frame_rate+1
0009BFAC 85 AC 05 00                  DCD sensor_util_get_snapshot_fps+1
0009BFB0 E9 B1 05 00                  DCD sensor_util_set_exposure_gain+1
0009BFB4 D9 B2 05 00                  DCD sensor_util_set_snapshot_exposure_gain+1
0009BFB8 05 C9 05 00                  DCD s5k4e1_register_to_real_gain+1
0009BFBC C5 C8 05 00                  DCD s5k4e1_real_to_register_gain+1
0009BFC0 49 B4 05 00                  DCD sensor_util_get_max_supported_hfr_mode+1
0009BFC4 00 00 00 00                  DCD 0                      ; sensor_util_get_cur_fps
0009BFC8 B9 B1 05 00                  DCD sensor_get_lens_info+1
0009BFCC 00 00 00 00                  DCD 0
0009BFD0 00 00 00 00                  DCD 0
0009BFD4 00 00 00 00                  DCD 0
0009BFD8 00 00 00 00                  DCD 0
0009BFDC 00 00 00 00                  DCD 0
0009BFE0 00 00 00 00                  DCD 0
0009BFE4 00 00 00 00                  DCD 0
0009BFE8 00 00 00 00                  DCD 0
0009BFEC 71 B4 05 00                  DCD sensor_util_set_start_stream+1
0009BFF0 9D B4 05 00                  DCD sensor_util_set_stop_stream+1
0009BFF4 C9 B4 05 00                  DCD sensor_util_get_csi_params+1
При сравнении структур s5k4e1_func_tbl и ov8825_truly_cm8313_func_tbl можно заметить, что в структуре ov8825_truly_cm8313_func_tbl есть ссылки на специфичные функции, коими являются s5k4e1_register_to_real_gain и s5k4e1_real_to_register_gain. Данные функции следует заменить на функции ov8825_register_to_real_gain (адрес 0x00059580) и ov8825_real_to_register_gain (адрес 0x00059510), т.к. они полностью эдентичны функциям ov8825_truly_cm8313_register_to_real_gain и ov8825_truly_cm8313_real_to_register_gain.

Так же при сравнении стало ясно, что в структуру s5k4e1_func_tbl нужно добавить функцию sensor_util_get_cur_fps (адрес 0x0005B138).

В оригинальной структуре ov8825_truly_cm8313_func_tbl отсутствуют следующие функции:
  • sensor_util_get_max_supported_hfr_mode
  • sensor_util_set_start_stream
  • sensor_util_set_stop_stream
  • sensor_util_get_csi_params

Поэтому нужно занулить соответствующие этим функциям ячейки памяти (0x0009BFC0, 0x0009BFEC, 0x0009BFF0, 0x0009BFF4).

После патча структура s5k4e1_func_tbl приняла следующий вид:
0009BF98 C9 AD 05 00  s5k4e1_func_tbl DCD sensor_util_set_op_mode+1
0009BF9C C9 B0 05 00                  DCD sensor_util_get_mode_aec_info+1
0009BFA0 3D AF 05 00                  DCD sensor_util_get_dim_info+1
0009BFA4 41 B0 05 00                  DCD sensor_util_get_preview_fps_range+1
0009BFA8 E5 AB 05 00                  DCD sensor_util_set_frame_rate+1
0009BFAC 85 AC 05 00                  DCD sensor_util_get_snapshot_fps+1
0009BFB0 E9 B1 05 00                  DCD sensor_util_set_exposure_gain+1
0009BFB4 D9 B2 05 00                  DCD sensor_util_set_snapshot_exposure_gain+1
0009BFB8 81 95 05 00                  DCD ov8825_register_to_real_gain+1
0009BFBC 11 95 05 00                  DCD ov8825_real_to_register_gain+1
0009BFC0 00 00 00 00                  DCD 0
0009BFC4 39 B1 05 00                  DCD sensor_util_get_cur_fps+1
0009BFC8 B9 B1 05 00                  DCD sensor_get_lens_info+1
0009BFCC 00 00 00 00                  DCD 0
0009BFD0 00 00 00 00                  DCD 0
0009BFD4 00 00 00 00                  DCD 0
0009BFD8 00 00 00 00                  DCD 0
0009BFDC 00 00 00 00                  DCD 0
0009BFE0 00 00 00 00                  DCD 0
0009BFE4 00 00 00 00                  DCD 0
0009BFE8 00 00 00 00                  DCD 0
0009BFEC 00 00 00 00                  DCD 0
0009BFF0 00 00 00 00                  DCD 0
0009BFF4 00 00 00 00                  DCD 0

Может показаться, что на этом патчинг можно завершить, но это ошибочное чувство. А вся причина кроется в релоках, которые используются для корректировки адресов функций в структуре s5k4e1_func_tbl. Если не отдедактировать эти релоки, то после загрузки либы liboemcamera в память адреса удалённых функций (0x0009BFC0, 0x0009BFEC, 0x0009BFF0, 0x0009BFF4) из нуля превратятся в "мусор", да и при этом адрес добавленной функции sensor_util_get_cur_fps тоже станет "мусором".

Почему то секцию релоков IDA никак не отображает (либо я не знаю как это сделать). Поэтому патчить релоки следует в HEX-редакторе (я использую HexView).

Для патчинга релока для адреса 0x0009BFC0 нужно для начала в HEX-редакторе найти последовательность байт "C0BF090017".
0000A700   B4 BF 09 00 17 00 00 00
0000A708   B8 BF 09 00 17 00 00 00
0000A710   BC BF 09 00 17 00 00 00  
0000A718   C0 BF 09 00 17 00 00 00
0000A720   C8 BF 09 00 17 00 00 00  
0000A728   EC BF 09 00 17 00 00 00
0000A730   F0 BF 09 00 17 00 00 00  
0000A738   F4 BF 09 00 17 00 00 00
0000A740   CC 5D 09 00 15 2D 00 00  
0000A748   80 5E 09 00 16 03 00 00
Хочу заметить, что число 0x17 означает тип релока R_ARM_RELATIVE.
Далее следует заменить найденную последовательность "C0BF0900" на "C4BF0900". Этим самым исправляются "мусорные" указатели по адресам 0x0009BFC0 и 0x0009BFC4, т.к. адрес релока сменяется с функции sensor_util_get_max_supported_hfr_mode на функцию sensor_util_get_cur_fps.

Рядом с найденной последовательность так же находятся релоки для адресов 0x0009BFEC, 0x0009BFF0, 0x0009BFF4. Нужно сделать так, что бы андройдовский линкер при загрузке либы liboemcamera просто игнорировал данные релоки. Для этого нужно просто напросто изменить у этих релоков тип на нулевой.

После патча релоков будем иметь следующий листинг:
0000A700   B4 BF 09 00 17 00 00 00
0000A708   B8 BF 09 00 17 00 00 00
0000A710   BC BF 09 00 17 00 00 00  
0000A718   C4 BF 09 00 17 00 00 00
0000A720   C8 BF 09 00 17 00 00 00  
0000A728   EC BF 09 00 00 00 00 00
0000A730   F0 BF 09 00 00 00 00 00  
0000A738   F4 BF 09 00 00 00 00 00
0000A740   CC 5D 09 00 15 2D 00 00  
0000A748   80 5E 09 00 16 03 00 00

Вот теперь то точно всё готово для тестирования пропатченной либы liboemcamera. Главное не забыть чуточку укоротить имена у двух libchromatix-файлов.

Результатом описанной работы является вот этот коммит в github.

1 комментарий:

  1. Добрый день! А возможно как то для мтк6580 сделать поддержку камера2 апи и с модулем камеры imx164 fm50af сенсор imx179?

    ОтветитьУдалить