Устройство игрового OLED-монитора и особенности гейминга на нем

Прокомментировать Просмотры: 4

В этой публикации я делюсь опытом реверс-инжиниринга собственного монитора. Задумывались ли вы, каков объем оперативной памяти вашего дисплея? Сколько вычислительных ядер скрывается под его корпусом? И сколько независимых версий микропрограмм обеспечивают его работу?

Конечно, после прочтения вы вряд ли сразу смените прошивку на своем устройстве. Однако вы приобретете нечто бо́льшее: научитесь подступаться к изучению аппаратной начинки любых гаджетов. А возможно, даже решитесь написать собственный софт для них.

Введение

Меня всегда привлекало понимание того, как устроены окружающие вещи, и при этом я хочу, чтобы техника подчинялась моим правилам. К сожалению, в последние годы наблюдается странная тенденция к деградации пользовательского опыта. Базовые, интуитивно понятные концепции в новых поколениях устройств будто бы специально усложняют, либо разработчики просто изобретают велосипед, игнорируя удачные решения прошлого.

Ностальгическое брюзжание о том, «как было раньше»

Взять хотя бы мою старую микроволновку: всё было элементарно — открыл дверцу, загрузил еду, захлопнул, нажал единственную клавишу, и пошел разогрев. Нынешняя же печь заставляет чувствовать себя пилотом лайнера. Сначала ее нужно разбудить отдельной кнопкой питания, причем с заметной задержкой — устройство зачем-то загружается и демонстрирует приветственный логотип. Только после этого можно открыть дверцу (тоже с лагом), запустить процесс… Кажется мелочь, но почему древняя микропечь справлялась с этим мгновенно и без лишних церемоний?

Разумеется, большинство подобных раздражающих факторов можно было бы устранить корректировкой программного обеспечения. Но производители наглухо закрывают исходный код. И дело не вредности: выпуск бытового прибора с открытым ПО — задача куда более трудоемкая и дорогая, чем с проприетарным. Требуется согласовывать юридические лицензии для каждой библиотеки, готовить громоздкую документацию, защищать чужую интеллектуальную собственность. К тому же компании часто банально стыдятся показывать внутренний код из-за его низкого качества. В итоге рынок забит дешевым в производстве железом с закрытым, неоптимизированным софтом и полным отсутствием техдокументации.

Я давно лелеял мечту дойти до такого уровня квалификации и свободного времени, чтобы взять прошивку микроволновки, роутера или смартфона и переписать ее под себя. Наверняка подобные дерзкие мысли посещали и вас.

Раньше подобная затея казалась непосильной. Требовалось обладать глубокими экспертными знаниями в самых разных сферах: от системного программирования до схемотехники и чтения даташитов на тысячи электронных компонентов.

Но так было в доискусственно-интеллектуальную эпоху. С появлением продвинутых ИИ-ассистентов моя давняя мечта стала вполне осуществимой.

Помимо микроволновки, у меня есть отличный девайс — широкоформатный игровой OLED-монитор MSI MPG 341CQPX QD-OLED. Полтора года назад профильные издания захлебывались от восторга, расхваливая его великолепную цветопередачу и богатый функционал. Мне безумно нравится картинка, частота обновления в 240 Гц и четыре видеовхода. Меня устраивает в нем практически всё, за исключением мелких нюансов.

Самый очевидный раздражитель — при каждом включении монитор три секунды демонстрирует фирменный логотип MSI ярко-фуксиевого цвета.

Полюбоваться им пару раз забавно. Но спустя полтора года эксплуатации я и так прекрасно осведомлен, кто производитель. Когда в процессе тестирования различных источников приходится подолгу включать и выключать дисплей, эта обязательная заставка начинает изрядно бесить. Хотелось бы полностью убрать анимацию и ускорить старт. Разумеется, в штатном меню такой опции нет. (Спойлер: технически эта возможность в прошивке заложена, просто вендор заблокировал к ней доступ).

Второй момент — коммутация источников сигнала. Переключение между ними превращается в настоящий кошмар крайне утомительную процедуру. Если выбранный порт неактивен, монитор мгновенно уходит в спячку и перестает реагировать на клавиши. Выход из сна занимает те же драгоценные секунды. Ошиблись с выбором входа? Цикл повторяется: засыпание, пауза, попытка проснуться, вывод сообщения «Out of sync» (причем на доли секунды), погасший экран. Хотелось бы большей прозрачности: чтобы устройство честно рапортовало о типе поступающего сигнала и причинах его неприятия, а засыпало исключительно по моей команде, а не по собственному усмотрению.

Последней капелей стало появление у меня MacBook Pro. Предыдущий MacBook Air подключался без проблем: закрыл крышку — и картинка транслируется на внешний экран. С «прошкой» начались фокусы: с открытой крышкой всё отлично, стоит ее закрыть — дисплей выдает «Out of sync», «No signal» либо начинает бешено стробировать основными цветами RGB на максимальной яркости. Наверняка проблему можно раскопать в недрах macOS, но делать это вслепую с заблокированным ноутбуком — то еще удовольствие. Монитор мог бы протянуть руку помощи, но увы. Разработчики явно не стремились сделать его гибким и дружелюбным инструментом.

Поскольку у меня уже накопился удачный опыт применения ИИ для реверс-инжиниринга несложной периферии (вроде кухонного контроллера подсветки или 60 ГГц радара), а также жгучее желание разобраться в анатомии современного дисплея, я дал старт этому увлекательному проекту.

Начало исследования

Логично предположить, что вся логика работы монитора зашита в его управляющей программе. Компания MSI регулярно выкладывает апдейты. На момент старта актуальной была версия FW.037, тогда как в моем экземпляре значилась предыдущая — FW.034. Сохранение старой версии критически важно, так как процесс обновления позволяет проследить логику взаимодействия, а повторить его без исходного файла может не получиться.

Я уже знал, что «сердце» любого монитора — это скалер, специализированный чип, обрабатывающий видеопоток и выводящий картинку на матрицу.

Скачав официальный бинарник прошивки, я скормил его ИИ-агенту со следующим запросом:

Это проект по реверс инжинирингу прошивки (Scaler Firmware) монитора MSI MPG 341CQPX QD-OLED https://www.msi.com/Monitor/MPG-341CQPX-QD-OLED/support. Цель: узнать алгоритмы работы монитора с OLED панелью и возможно улучшить их. Проверить возможность увеличения кадровой частоты. Понять как можно собрать свою прошивку для монитора. Проверить есть-ли в этой прошивке управление кнопками монитора и алгоритмы взаимодействия с HDMI и Display Port входами. Прошивка лежит в файле MSI_MPG_341CQPX_QD-OLED_FW.037_0225.bin . Можно использовать различные внешние тулы типа Ghidra. Проведи начальный анализ задачи и прошивки и напиши план.

Спустя час работы агент выдал вердикт: «Скалер — Novatek NT68503, панель — SDC QMC340CA01_D01». Документация на оба компонента отсутствует в открытом доступе. Внутри кремниевого кристалла скалера уживаются сразу четыре процессорных ядра на совершенно разных архитектурах: один STBC (STandBy Controller) на базе 8051, два ядра Leon2 (SPARC) и один процессор Tensilica Xtensa. И весь этот зоопарк кода упакован в один-единственный файл! Огромное спасибо MSI за то, что прошивка не зашифрована. Нейросеть сразу обратила внимание на обилие отладочной информации и заброшенные UART-консоли с наборами команд — это существенно облегчало понимание внутренних процессов.

Архитектура монитора вырисовывалась следующим образом:

  • Контроллер STBC 8051 — отвечает за холодный старт, инициализацию остальных ядер и опрос периферии (кнопки, джойстик, USB).

  • Leon2 Main — основное «тяжелое» ядро с кодом объемом 1.4 МБ. Управляет OLED-матрицей, задает режимы отображения и рендерит графический интерфейс (OSD).

  • Leon2 Sub — вспомогательное ядро, целиком отданное под видеовходы. Протоколы HDMI и DisplayPort требуют жесткого соблюдения таймингов, обработку которых основное ядро могло бы сорвать.

  • Tensilica Xtensa — специализированный DSP-процессор, судя по всему, отвечающий за анализ яркости кадра и управление токовой подсветкой. На момент написания статьи это наименее изученный узел.

Еще через час ИИ откопал в коде скрытое сервисное меню и комбинацию для его активации (зажать джойстик и подать питание). Я тут же проверил на практике — комбинация сработала безупречно.

Скормив агенту фотографию сервисного меню, я получил сопоставление его пунктов с областями прошивки. Выяснилось, что в памяти монитора хранятся уникальные для каждого экземпляра данные: серийный номер, суммарная наработка панели в часах и калибровочные таблицы. Агент проявил разумную осторожность и автоматически прописал себе правило: категорически запрещать любые попытки записи во флеш-память до тех пор, пока не будет обнаружено точное место хранения этих уникальных параметров и не будет сделан их бэкап. Он даже предположил, что эта область называется FE2P (Flash-emulated EEPROM). Впрочем, позже выяснилось, что конкретно в этой модели всё устроено иначе (но не будем забегать вперед). 🙂

Далее я сфотографировал стандартное OSD-меню. Нейросеть сопоставила пункты интерфейса с сервисными данными и выдала мне готовую карту команд, которые управляющий софт отправляет на OLED-панель.

Стало очевидно, что низкоуровневые алгоритмы обслуживания матрицы зашиты внутри самой панели — наш софт лишь отдает высокоуровневые команды и ждет ответа. Жаль, детали самого процесса регенерации пикселей остались за кадром. Но это также означало, что OLED-модуль оснащен собственным микроконтроллером и автономной прошивкой. Предлагаю по ходу чтения мысленно суммировать количество процессоров и прошивок — в финале сверим результаты.

Следующей задачей было понять принцип опроса элементов управления. Я сформулировал агенту такой запрос (сохраняю оригинальные опечатки из живой сессии):

Попробуй найти в коде обработку нажатий кнопок на мониторе, возможно там есть скрытые комбинации, типа вызова сервисного меню. У монитора 2 конопки, одна из них — это включение монитора и отправка его в сон, а вторая — функциональная с назначаемой функцией. Еще есть джойстик с 4-мя направлениями и возможностью на него нажимать.

Десять минут работы ИИ — и передо мной массив инсайтов. Оказывается, джойстик оцифровывается не через дискретные линии, а через аналоговый вход! Пять позиций управления висят на одной линии скалера, а различаются они по уровню падения напряжения. Ниже приведена примерная схемотехника подобного узла (информация дополнена по сравнению с первыми днями исследований).

Кроме того, код содержал рудименты программной эмуляции нажатий клавиш путем отправки команд в ядро Main. Зачем это заложено — загадка.

На этом моя первая четырехчасовая сессия (включая раздумья и диалоги с Claude Code) подошла к концу из-за исчерпания лимитов. Что мне удалось выяснить?

ИИ построил детальную карту официального бинарника от MSI:

0x000000-0x001900  8051 STBC bootloader (reset vector: LJMP 0x13F7)
0x004000-0x004200  Таблица JEDEC ID SPI-флеша, 57 записей по 6 байт
                   (SST, Macronix, Winbond, GigaDevice, EON, AMIC, ESMT, ISSI, Fudan)
0x006000-0x006048  Таблица разделов, 9 записей по 8 байт
0x010000-0x02E600  8051: основной код, MailBox, ADC-кнопки, отладочная консоль
0x030000-0x03D900  Tensilica Xtensa LE: контур LDC/ABL, своя отладочная консоль
0x050000-0x0A5600  Leon2 Sub, SPARC BE (85 % валидных опкодов)
0x0A6000-0x0A8800  Таблица указателей 0xA00xxxxx (символы/векторы Sub)
0x0B0000-0x0CF500  SPARC BE (81 %)
0x0D0000-0x0D8100  service runtime Leon2 Main @0xA0028000: traps, HAL, mailbox
0x0EC000-0x0F1B00  Инициализированные данные Leon2 Main → RAM 0xA8024000:
                   VERSION=37 @0x0EC020, дескрипторы и указатели на OSD-ресурсы
0x118000-0x11F800  60 EDID (база + CTA-861 + DisplayID), MSI 0x4DD0 "MPG341CX OLED"
0x11A000-0x128000  Данные (низкая энтропия, H=2.40)
0x128100-0x26A100  Leon2 Main, SPARC BE (73 %) + OSD-ресурсы и языковые строки
  • Контроллер монитора базируется на четырех разнородных ядрах.

  • Каждое ядро имеет собственный UART для отладочного вывода и приема команд.

  • OLED-панель управляется по собственному закрытому протоколу.

  • Где-то в недрах устройства спрятаны уникальные калибровочные данные, которые необходимо вычитать и забэкапить до того, как предпринимать рискованные манипуляции вроде правки сервисного меню.

Стало очевидно: чтобы продвигаться дальше и не превратить дорогой девайс в тыкву, необходимо добраться до платы, найти микросхему флеш-памяти и слить ее дампы. Имея на руках полный бэкап, можно не бояться экспериментов — в случае сбоя всегда удастся вернуть исходное состояние программатором. К тому же дамп поможет понять, как именно прошивка из дистрибутива укладывается на физические чипы памяти.

Вскрытие (монитора)

Главной целью становилось получение физического доступа к потрохам: подключение к UART-портам ядер и считывание флеш-памяти.

У меня имелся богатый опыт разборки ноутбуков и смартфонов, а также софт-аппаратные навыки чтения микросхем прищепкой Pomona. Большинство ноутбучных BIOS записаны в стандартных чипах SOIC8 с торчащими по бокам ножками — их можно запросто охватить прищепкой прямо на плате, даже без подачи питания на устройство.

Анализ кода показал активное использование SPI Flash, а значит, микросхема памяти распаяна где-то на плате, и до нее можно дотянуться. (Аналогичный процесс для других устройств я описывал здесь).

Загвоздка была лишь в том, чтобы этот монитор аккуратно вскрыть.

Вся моя предыдущая практика учила: залог успеха — официальный мануал по разборке (Service Manual). В крайнем случае — гайды энтузиастов или iFixit. Попытки ковырять корпус вслепую почти неизбежно ведут к заломам пластика и повреждению защелок.

А ломать свой прекрасный монитор без единого битого пикселя мне категорически не хотелось.

В Сети ничего по моей модели не нашлось. Зато обнаружилась инструкция от Dell на близкий по духу Alienware AW3423DWF с точно такой же изогнутой OLED-панелью 1800R. В документе рекомендовалось использовать специальную мягкую подушку для защиты матрицы и подробно описывалась карта защелок. Характерно, что на иллюстрациях Dell внутренности платы были заретушированы цветными квадратами. Секретность уровня Госдепа, не иначе.

Вооружившись надеждой, я атаковал техподдержку MSI, сославшись на европейские директивы по утилизации бытовой техники, требующие предоставлять инструкции по разборке. Идея подсказана ИИ, разумеется. 🙂 Предсказуемо получив вежливый отказ под предлогом «наличия опасных высоких напряжений внутри», я решил действовать самостоятельно.

Тут нужно сделать ремарку: я человек увлекающийся. Именно поэтому я обхожу стороной видеоигры — могу просидеть за ними ночи напролет. Подобные технические расследования затягивают ничуть не меньше. Видишь белые пятна на карте неизвестного мира и азартно прокладываешь маршрут, преодолевая препятствия.

Очередной вызов — вскрыть неразборный корпус, сохранив идеальный товарный вид, не оставив царапин и задиров, и при этом не имея фирменной подушки для матрицы. Но сделать это было жизненно необходимо. 🙂

Замену фирменной подушке составила обычная домашняя перинка, расстеленная на мягкой кровати. Монитор лег лицом вниз. Стойка уже была демонтирована — это единственные четыре винта снаружи. Дальше предстояла борьба со скрытыми пластиковыми клипсами.

Сначала я пытался работать традиционными медиаторами от iFixit и тонкими лопатками. Бесполезно. Пластик корпуса оказался высочайшего качества — жесткий, упругий, а защелки держали намертво.

Пример тупикового пути: слишком мягкие медиаторы и недостаточное усилие.

В голове постоянно крутилась мысль: только бы не сломать, иначе весь смысл исследования испарится. Вспоминался классический кадр из фильма:

Казалось, достаточно найти заветную точку, нажать — и крышка сочным щелчком отскочит сама.

Оружием победы стали прочные пластиковые лопатки для демонтажа автомобильного интерьера, армированные стекловолокном.

Суть метода сводилась к отгибанию краев задней крышки наружу, чтобы фиксаторы выскакивали из пазов. Процесс требовал крепких… нет, железных нервов: клипсы расстегивались с оглушительным треском, напоминающим пушечный выстрел. Тем не менее, корпус не пострадал. Теперь в моем репозитории хранится полная схема защелок.

И вот заветный результат:

Что скрывается внутри?

После двух суток борьбы с корпусом возникает ложное чувство, будто основные трудности позади. Но игра только набирает обороты. Внимательно изучаем плату. Вы же догадались, что справа расположена плата скалера, а слева — силовой блок питания?

Визуальный осмотр выявил:

  • Загадочный нераспаянный 14-контактный разъем CN4008.

  • Разъем CN4002, куда заведена плата с кнопками и джойстиком.

  • Разъем CN7003 с пустыми пинами.

  • Кнопку SW4101 неизвестного назначения.

  • Несколько пустых посадочных мест под разъемы. Очень хочется верить, что на каких-то из этих контактов висят те самые UART-консоли.

Не забываем о поисках микросхемы флеш-памяти. На видимой стороне платы обнаруживается пара-тройка микросхем в корпусах SOIC8. Рука уже тянется за прищепкой, но здравый смысл и привычка сверяться с даташитами останавливают. Проверка маркировки показала: видимые на этой стороне чипы памяти к прошивке отношения не имеют. 🙁

Задача усложняется. Придется изучать обратную сторону платы. Откручиваем крепеж (включая стойки видеовходов), аккуратно отсоединяем шлейфы (широкие ленточные разъемы сверху пока трогать боязно), отклеиваем металлизированный скотч — и плата переворачивается.

Ура, здесь обнаружились еще три микросхемы SOIC8. Снова сверка документации. На сей раз две из них действительно микросхемы памяти, но целевая SPI Flash — лишь одна, под индексом U1508. Вторая, U4003, представляет собой EEPROM с интерфейсом I2C, а опыта работы с такими чипами у меня пока не было.

Цепляю прищепку, подключаю Raspberry Pi и утилитой flashrom вычитываю U1508. Объем составляет 256 КБ — явно маловато для основной прошивки, но какая-то служебная часть здесь живет. Отправляю дамп ИИ на анализ и получаю отчет U1508: оказывается, это две разные прошивки USB-хаба VL211. Пока откладываем.

Второй чип, U4003, — это ST M24256 EEPROM на 32 КБ. Прошу агента подготовить почву:

В проекте есть микросхема U4003 типа 24256FP. Ее описание в файле docs/eeprom-u4003.md , а спецификация в datasheets/m24256e-f.pdf. Напиши инструкцию как прочитать данные из этой микросхемы не снимая ее с платы с помощью Raspberry Pi. В файле с описанием уже есть подобная инструкция, но она мне кажется не совсем верной, т.к. ее писали без даташита.

Агент выдал схему коммутации выводов Raspberry Pi с прищепкой и набросал скрипт на Python. На выходе получился 32-килобайтный файл. Беглый взгляд на дамп показал, что полезных данных там от силы килобайт, остальное забито нулями (0xFF).

После анализа ИИ сделал вывод: перед нами те самые уникальные параметры конкретного экземпляра монитора. Содержимое совпало со структурой сервисного меню: здесь прописаны часы наработки OLED-панели и цветовые калибровочные коэффициенты.

Отличные новости: персональный бэкап сохранен, и в случае факапа я смогу вернуть монитор к исходному состоянии. Но где же прячется прошивка скалера? Следующий кандидат на очереди — металлический экран, наглухо припаянный с лицевой стороны платы. И тут я задумываюсь. До сих пор мои действия не нарушали гарантию: корпус и винтики открывались без следов. Но выпайка экранирующего кожуха — это уже жесткое вмешательство. С другой стороны, без этого не добраться до основной памяти, а в случае краха восстановить софт будет нечем. Собравшись с духом, принимаю решение выпаивать экран.

Под экраном

При должной сноровке и терпении выпайка экрана оказалась не столь страшной. Шесть массивных точек припоя по периметру — и кожух снят.

Под ним обнаружился очередной сюрприз: массивный радиатор, укрывающий сам скалер, четыре чипа оперативной памяти DDR3 общей емкостью 1 ГБ и, наконец, искомый чип U4002 — SPI Flash объемом 32 МБ. Вот здесь прошивка точно есть. Но есть нюанс…

Микросхема выполнена в корпусе WSON8. У нее отсутствуют привычные выводы по бокам — контакты в виде миниатюрных пятачков спрятаны под днищем корпуса. Типоразмер чипа — 8×6 мм.

Что делать? Промышленность выпускает спецоснастку для таких корпусов.

Но, во-первых, подобные переходники грешат плохим контактом, а во-вторых, у меня ее нет. Дополнительная сложность — чип памяти расположен впритык к массивному радиатору скалера (зазор всего около 3 мм), так что подлезть туда — отдельное искусство.

Снять сам радиатор тоже заманчиво, чтобы изучить маркировку скалера. Но он не прикручен винтами, а припаян к полигону, и отпаивать его ради праздного любопытства я пока не готов.

Вернемся к флешу. Требуется подпаяться как минимум к шести из восьми выводов микросхемы 8×6 мм, где контакты представляют собой лишь крошечные капли припоя по краям дна. Мастера по ремонту в таких случаях рекомендуют выпаивать чип целиком. Ранее я этого не делал, хотя теория была в голове.

Снова погружаюсь в раздумья. Демонтаж 8-контактного чипа — дело в теории нехитрое. Но это мой рабочий монитор. Перегрею кристалл и спалю флеш ДО того, как изолью дамп — и всё, приплыли. Замена микросхемы не поможет, ведь я еще не знаю точного формата укладки данных. В этом и заключается ловушка закрытых устройств.

Рассуждаю так: если я сейчас откажусь от выпайки (что разумно), придется собирать монитор назад, а когда появится время на вторую попытку — неизвестно. А я, напомню, человек азартный и до жути хочу узнать формат данных. Фен для выпайки у меня под рукой. В конце концов, зачем он тогда нужен?

Вооружившись термофеном, флюсом, пинцетом и защитными экранами для соседних пластиковых разъемов, приступаю к прогреву. Задача — дождаться, пока чип поплывет на шарах. Главное — не пытаться сдвинуть его раньше времени, иначе сорву дорожки с платы, и монитор отправится на помойку. Грею 3-4 минуты — ноль эмоций. Массивный радиатор скалера отбирает всё тепло, обжигая мне пальцы, а флеш сидит как влитой. Дав плате остыть, делаю второй заход — грею дольше, но результат тот же. Здравый смысл побеждает жажду наживы: отмываю плату от флюса и решаю пока отложить силовой метод, занявшись анализом софта.

В поисках UART

Пока идей насчет прямого доступа к флешу нет, переключаюсь на неизведанные разъемы на плате. Напомню про загадочный CN4008 на 14 контактов. Почему бы не проверить его на предмет скрытых консолей? С помощью ИИ составляю план прозвонки. Увы, связи с памятью обнаружить не удалось. Зато выяснилось назначение разъема CN7003 — это отладочный интерфейс ICP/SWD соседнего контроллера Nuvoton NUC1261 (U7005). Через него шьется этот вспомогательный чип, который, как выяснилось позже, работает USB-мостом, обеспечивая связь монитора с ПК под именем «MSI Gaming Controller». Не забывайте вести подсчет процессоров и прошивок!

Тем временем я подключил логический анализатор Saleae (выражаю благодарность Павлу Жовнеру за девайс и Ивану @MErocle за содействие) к разъему CN4008 и обнаружил на нем сразу четыре UART-консоли! Назначение 10 из 14 пинов прояснилось: четыре пары на TX/RX четырех ядер плюс две линии GND. Потребовалась серия экспериментов с переподключением и мониторингом активности при старте. Записав лог загрузки по всем каналам, скормил его ИИ. Агент автоматически определил скорости бодрейта и расшифровал лог, детально расписав назначение каждой консоли (подробности в документе docs/uart-console.md). Ниже приведен типичный вывод консоли STBC при старте и уходе в сон:

------STBC Boot Loader -----
Set Flash to Quad mode!!
Re-booting STBC code...0x4570[5] toggle ==> warm Reset!!

------NT68500 MCU Test program -----
Leon2 vs AHB clk is 3:1
Leon2 (Main) RUN...
Leon2 (Sub) RUN...
FE2P_SetLeon2BaseAddress 00108000

[пауза 17,43 с]
FillKeyDetectList (0000) 3500 ff00 1200 100 00 00 00 00 00 00 00 00 00 00 00 00
FillKeyDetectList (0010) 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
FillKeyDetectList (0020) 20 20 20 20 1520 20 20 20 20 20 20 20 20 20 20 20
FillKeyDetectList (0030) 1530 1630 1530 1730 1630 130 1630 30 30 30 30 30
FillTypeCInfo : F6, 60, FF, 80, 00
Enable I2C 7
CMD_SYS_POWERSAVING
Leon2 (Main) STOP...
Leon2 (Sub) STOP...
DP_EnableMRX (0)

Результат великолепный, но неудобство физического подключения к микроскопическим контактам CN4008 тормозило работу. Требовалось цивилизованное решение.

Идентифицируем загадочный разъем CN4008

Ответ нашелся у ИИ, правда, не с первой попытки. После того как я скормил нейросети точные габариты разъема и качественное фото, агент уверенно выдал наименование: Hirose DF11-14DS-2C. Никогда прежде о таких не слышал. Заказываю на AliExpress готовый кабель метровой длины. Получив посылку, разрезаю его пополам и оканчиваю второй конец стандартными пинами Dupont для удобного подключения. Жизнь стала значительно проще.

Теперь для работы с UART любого ядра достаточно подключить мой Flipper Zero, настроенный как UART-терминал, к нужной паре контактов CN4008 плюс земля. Выражаю признательность команде Flipper и Павлу Жовнеру за этот незаменимый в хозяйстве девайс!

Чтение флеша, дубль два

Перед новой попыткой штурма микросхемы я проконсультировался с профессиональным мастером по ремонту ноутбуков (привет, Максим!). Главный его совет отрезвлял: корпуса WSON8 не поддаются простой пайке феном сверху, обязателен нижний подогрев платы. Всё тепло мгновенно уходит в массивный медный полигон платы.

Перспектива возиться с термостолом и отдирать всё лишнее с платы не радовала.

Но Максим подсказал изящную альтернативу: вместо выпайки чипа подпаяться тонкими проводками прямо к его выводам. Всего шесть проводов. Задача ювелирная, но выполнимая. Размеры кристалла помните? 8×6 мм.

Итог: дамп флеш-памяти монитора у меня в кармане! В дальнейшем этот образ фигурирует под именем U4002.

Скармливаю файл агенту и получаю пласт ценных сведений:

  • Во флеше прописаны сразу две версии прошивки: текущая и резервная.

  • Уникальных калибровок здесь нет (они живут в другом месте).

  • Структара памяти один в один повторяет формат официального файла обновления от MSI.

  • Используется лишь около 6 МБ из 32 МБ доступного пространства — простор для творчества колоссальный.

  • В начале образа прописана таблица разделов, описывающая блоки: 0x01 — загрузчик STBC для 8051, 0x10 — ядро Leon2 Main для SPARC и т.д.

  • Самое начало занимает первичный загрузчик (bootloader), стартующий при подаче питания и раздающий задачи остальным ядрам.

Имея на руках полные дампы (как мне казалось), можно было планировать эксперименты.

Как штатно обновляется прошивка

Производитель поставляет утилиту «Gaming Intelligence» для Windows, заливающую апдейты по USB. Любопытная деталь: софт требует, чтобы во время прошивки видеосигнал шел исключительно через DisplayPort. Было бы неплохо отвязаться от этой капризной зависимости и научиться шить устройство из любой ОС.

Сперва я попытался расковырять процедуру прошивки через анализ бинарника. ИИ здесь отработал на славу, отыскав процедуры стирания и записи SPI Flash в образах для контроллера 8051 (разделы 0x01 и 0x02). В первом блоке нужные функции присутствовали, но не вызывались. Во втором они активировались в ходе процедуры обновления с USB-флешки, подключаемой к монитору напрямую. Эту штатную процедуру обновления с флешки я никогда не запускал, так что отложим ее до лучших времен.

В теле прошивки код USB-обновления обнаружен не был. Пришлось зайти с другого фланга — перехватить живой процесс обмена данными по шине USB.

На машине с Windows и установленным MSI Gaming Intelligence запускаем Wireshark в связке с перехватчиком USBPcap. Начинаем штатное обновление на ту же самую версию прошивки, что уже установлена в мониторе (очень удобно, что софт позволяет это сделать без повышения или понижения версии). На выходе получаем лог обмена размером 100 МБ.

Если вы думаете, что я гуру анализа USB-трафика — это заблуждение. Я делал это впервые пошагово под диктовку ИИ-агента, который, не найдя процедуру в коде, сам предложил этот вектор и выдал четкий алгоритм действий. Беспрекословно подчиняюсь. Файл лога отправлен на анализ агенту.

Результаты разбора легли в основу документа usb-isp-protocol.md. Если опустить технические дебри, протокол выглядит так:

  1. По USB летит команда 580040:, в ответ на которую скалер переключает внутренний UART (служащий мостом между скалером и USB-контроллером) в режим I2C, переводя себя в режим ISP (In-System Programming) — прямого доступа к памяти по I2C.

  2. Следующей посылкой 01 e0 01 в тот же режим переводится сам USB-мост.

  3. Далее ПК начинает швырять команды I2C напрямую кремнию скалера. Протокол детально документирован по ссылке выше, но оцените глубину матрешки:

    • Хост шлет по USB пакеты (например, с кодом 0x04), содержащие инкапсулированную команду для USB-моста монитора.

    • Мост распаковывает пакет и транслирует его в I2C-транзакцию с конкретным адресом и телом «посылки».

    • Внутри этой посылки зашита низкоуровневая команда для самого скалера.

    Интерфейс позволяет читать и писать любые регистры скалера, управлять контроллером SPI Flash и совершать массу других деструктивных действий. Ниже представлена лишь часть таблицы команд скалера в ISP-режиме (полная таблица доступна в репозитории).

    Тут стоит заострить внимание: это не просто апдейтер прошивки. Это универсальный инструмент отладки с полным доступом к флешу. Можно в два счета вычитать, стереть или перезаписать любой сектор памяти, включая отправку опасных команд SPI. Становится понятно, почему в теле самой прошивки нет процедур обновления: они там попросту не нужны. Всю логику берет на себя внешнее ПО по USB. Теперь я точно знаю, как скормить монитору кастомную прошивку из-под любой ОС, а не только Windows.

    Разумеется, есть и обратная сторона медали. Если эксперимент со сменой прошивки завершится крахом, аппарат перестанет отвечать по USB, войти в этот сервисный режим не удастся, и монитор превратится в кирпич. Восстановить его можно будет только проверенным хардварным путем: разборка, припайка проводков к флешу и заливка живого дампа U4002 через Raspberry Pi.

    Для меня это тернистый путь, но рассчитывать на повторение фокуса другими энтузиастами пока не приходится.

    Логично предположить, что на заводе в чистые микросхемы как-то заливают первую прошивку. Должен существовать аппаратный способ принудительного перевода скалера в режим ISP независимо от состояния основного софта во флеше.

    Ищем вход в режим ISP

    Задача формулируется просто: отыскать способ перебросить монитор в сервисный ISP-режим без опоры на штатную прошивку.

    Подобный бэкдор обязан существовать в любом микроконтроллере или SoC, так как именно через него на конвейере прошивают пустые кристаллы.

    Схема обычно стандартна: при старте микросхема скалера сперва исполняет зашитый на заводе в кремний первичный загрузчик (ROM Loader). Его задача — прочитать код из внешней SPI Flash и передать управление. Это позволяет легко обновлять софт в полевых условиях: сменил чип памяти — устройство ожило. А сам ROM Loader неизменен.

    Производители кремния закладывают в ROM Loader развилку:

    • В штатном режиме грузим код из флеша.

    • В сервисном режиме ждем команд извне (например, по USB) для программирования памяти. Тот самый ISP-режим.

    Триггером переключения ветки выступает какой-то внешний аппаратный сигнал, опрашиваемый ROM Loader при старте. Осталось выяснить, какой именно. Документации на скалер, напомню, нет.

    В мире встраиваемых систем практикуются разные методы активации:

    • Зажатие определенной физической кнопки или комбинации.

    • Замыкание технологических пятачков (тестпоинтов) на плате.

    • Подача специфической последовательности импульсов на внешние разъемы.

    • <любые другие эзотерические варианты>

    Какой-то из них должен активировать ISP. Или не сработать ни один, но о грустном думать не хотелось.

    Кнопки для ISP

    У нас есть идеальный кандидат — таинственная кнопка SW4101, спрятанная под крышкой. Почему бы ей не переводить чип в сервисный режим? Агент набросал план проверок: вешаем логический анализатор на UART, пишем лог и жмем кнопку во всех вариациях (короткий тап, удержание, комбинации с подачей питания).

    Проделав это и скормив логи ИИ, получаю вердикт: это банальная аппаратная линия Reset. Любое нажатие приводит лишь к холодному ресету и штатной загрузке. Никаких намеков на сервисный режим в консолях не появилось.

    Почему бесполезно терзать внешние кнопки монитора? Кнопки на лицевой панели завязаны на периферийную логику MSI. Схема опроса известна. Сам скалер понятия не имеет об их физическом расположении и не опрашивает их на этапе первичного ROM-загрузчика.

    Версия с кнопками отпала.

    Тестпоинты и дорожки на плате

    На плате присутствуют два незадействованных в штатной работе разъема: CN4008 (14 pin) и CN7003 (6 pin).

    Логично предположить, что на конвейере к ним подключаются шлейфы для заливки фабричного дампа и последующей отладки через UART.

    Про CN7003 уже говорилось — это отладка USB-моста, к скалеру она отношения не имеет.

    Остается CN4008. Назначение 10 контактов из 14 мы уже выяснили (это UART-консоли). Была надежда, что ROM Loader слушает какой-то входящий порт в момент старта, ожидая символ вроде Enter или пробела. Правда, для этого ROM Loader должен заранее сконфигурировать UART (на неизвестной скорости). Я предположил, что слушать могут порт ядра STBC, так как именно оно просыпается первым.

    Безуспешно пробовал слать мусор на скорости 4800 бод (стандартная скорость этого UART) в момент подачи питания. Шансов изначально было мало: между снятием сигнала Reset и началом вывода загрузчика проходит всего 0.1 секунды. Маловероятно, что за этот миг можно успеть что-то передать. А через 0.1 секунду инициализация прошивки уже идет полным ходом.

    Версия с UART отпала.

    Оставались 4 неизвестных пина на CN4008. Наверняка они несут сакральный смысл, но выудить его мне не удалось. В штатном режиме на них тишина. Попытки подавать туда тактовые импульсы разной частоты привели лишь к спонтанным перезагрузкам монитора при высоких частотах, но стабильной зависимости выявить не удалось.

    Потратив несколько вечеров на эти пляски с бубном, я понял, что внешними воздействиями перевести девайс в сервисный режим не удастся. Следовательно, при любом сбое во флеше спасти железо сможет лишь припайка программатора к выводам чипа памяти.

    Или же стоило поискать обходной путь для упрощения экспериментов?

    Компромиссное решение

    Требовалось сделать процесс восстановления прошивки максимально безболезненным, чтобы не ходить по минному полю при каждом заливе тестового кода. Поскольку аппаратную кнопку ISP обнаружить не удалось, нужно было организовать удобный доступ к программатору.

    Первые тонкие проводки держались хлипко, и я их демонтировал. На сей раз я закупил ультратонкий многожильный провод в силиконовой изоляции 30 AWG, нарезал отрезки по 15 см и ювелирно подпаял к выводам микросхемы U4002.

    Идея заключалась в том, чтобы вывести жгут наружу корпуса, завести на разъем и закрыть заднюю крышку. В любой момент можно выключить монитор, подключить программатор и перешить чип. Звучит заманчиво. А что на практике?

    Первым делом я снял логическим анализатором Saleae дамп обмена по шине SPI Flash в момент старта. Подпаял каналы к ножкам флеша, параллельно зацепился к UART STBC, подал питание и… уперся в циклические перезагрузки. Поймать стабильный старт удалось лишь с нескольких попыток.

    Верхние четыре графика — шина SPI Flash, нижний — UART STBC.

    На скриншоте видна подача питания, уход в дежурный режим, ожидание нажатия кнопки Power (спустя 5 секунд я её нажал), инициализация ядер и появление картинки. В конце — повторное нажатие для выключения.

    Скормив этот 75-мегабайтный лог ИИ, я стал размышлять, почему монитор стал сбоить. Ответ лежал на поверхности: во всем виноваты те самые длинные проводки, догадался Штирлиц. Они работали как антенны, ловя наводки. Вывод очевиден: либо укорачивать до минимума, либо выпаивать.

    Тем временем агент выдал глубокий анализ загрузки.

    Процесс стартует с того, что ROM-загрузчик вычитывает первые 64 КБ из SPI Flash на скромной частоте 12 МГц. Это и есть загрузчик (bootloader). Исполнив его, ROM-загрузчик передает бразды правления ядру 8051. Теперь мы можем сопоставлять дизассемблированный код бутлоадера 8051 с живыми осциллограммами на шине SPI.

    Далее штатный бутлоадер определяет модель чипа памяти и переводит его в высокоскоростной режим: тактовая частота взлетает до 48 МГц, а передача данных переключается с однобитного режима на четырехбитный (Quad SPI). Я даже не подозревал о существовании таких режимов. Поскольку у меня были подпаяны лишь 6 проводов из 8, половина линий Quad SPI осталась в воздухе, и анализатор видел лишь часть обмена. ИИ учел этот нюанс и скорректировал выводы.

    Раскрутив работу бутлоадера на высокой скорости, чип запускает код STBC 8051, который последовательно инициализирует остальные ядра.

    Анализ трафика показал, что все ядра, кроме Leon2 Main, распаковываются во внутреннюю SRAM скалера и крутятся там. Но Leon2 Main весит 1.4 МБ, поэтому его код исполняется напрямую из внешней флеш-памяти на лету. Каждая инструкция вычитывается по SPI! Этим объясняется странная разбивка Leon2 Main на три сегмента в таблице разделов: первый — основной код, читаемый из флеша (медленно), второй — критически важные обработчики прерываний (выделенные в быстрый буфер), третий — блок оперативных переменных.

    Детали расписаны по ссылке выше, но суть ясна: старт базируется на 64-килобайтном бутлоадере.

    Главный вывод: пока я не уберу сопли из проводов, монитор будет сбоить из-за помех на 48 МГц шине.

    Идея: написать собственный кастомный бутлоадер, который не только умеет поднимать STBC, но и принудительно переводит монитор в ISP-режим для беспроводной (по USB) заливки любых образов.

    Пишем свой бутлоадер

    Для начала нужно создать аналог родного бутлоадера с открытым исходным кодом. Раньше на это ушли бы месяцы, но теперь у нас есть ИИ:

    Я считаю, что в репозитории собрано достаточно материала, чтобы написать свой собственный bootloader на C, например на SDCC. Это позволит легко добавлять в него необходимые для дальнейшего исследования функции. Он должен быть полностью совместим с вендорским bootloader, чтобы монитор не потерял свои текущие функции. Софт для разработки должен быть Open Source и доступен широкому кругу разработчиков. Разработку нужно вести в отдельном подкаталоге с именем bootloader-<какая-то добавка, которая означает, что это open source bootloader>. Напиши такой bootloader сохраняя текущий функционал, без дополнительных функций, но не повторяй строки вендора при печати в UART, чтобы не возникло конфликта с вендором по поводу прав.

    Название для кастомного загрузчика я тоже делегировал нейросети.

    Спустя 25 минут на руках была первая версия бутлоадера, написанная на чистом C и компилируемая в SDCC. Агент посредством USB-моста залил ее прямо в начало флеш-памяти монитора. Теперь в случае неудачи спасти устройство мог только внешний программатор.

    Смотрю на UART STBC, жму кнопку питания…

    Впрочем, можно даже не смотреть на консоль: если замигал светодиод дежурного режима, значит, кастомный загрузчик успешно отработал и передал эстафету дальше.

    Загрузчик завелся с пол-оборота!

    Правда, отладочный вывод в UART молчал, но это дело наживное.

    Всего через час после постановки задачи мой монитор стабильно стартовал на самописном открытом бутлоадере.

    Мелкие огрехи вроде пропавшего UART-вывода агент оперативно поправил в следующих итерациях.

    Прокачиваем бутлоадер

    Дальше — больше. В документации уже имелись сведения о том, как считывать состояние аналогового джойстика. Почему бы не встроить эту логику прямо в загрузчик?

    Формулирую задачу, ИИ пишет код, компилируем. Теперь на этапе старта бутлоадер опрашивает джойстик и рапортует в UART о направлении отклонения стика.

    Вот пример лога при отклонении джойстика вверх:

    bootloader-libre: start
    libre: joystick direction 4 adc CA
    libre: quad read verified
    

    Аппетиты растут. Во флеше зашиты две копии прошивок (особенность штатного обновления). Но штатный механизм не позволяет выбирать, какую из них грузить. Исправим это. Пусть при отклонении стика вверх загружается образ из верхней половины флеша, а вниз — из нижней. Если стик не трогать — дефолтный банк.

    Пасхалка 🪄, четыре минуты работы ИИ — и готово! Теперь у меня есть мультизагрузчик. В активном банке живет стабильная заводская прошивка, в резервный можно заливать безумные эксперименты, а при включении выбирать источник простым движением джойстика. Если тестовая прошивка уходит в бесконечный цикл, достаточно перезагрузить монитор и качнуть стик вниз. Главное — случайно не затереть банковский сектор с рабочей версией.

    Момент загрузки из неактивного банка:

    bootloader-libre: start
    libre: joystick direction 4 adc CA
    libre: quad read verified
    libre: flash bank 01
    libre: starting stbc-main from table 7000
    

    Но можно пойти еще дальше. Почему бы не научить бутлоадер принудительному переходу в ISP-режим? Алгоритм взаимодействия со скалером уже раскопан. Загвоздка в том, что для обмена по ISP требуется активный стек USB. В штатном режиме его инициализирует операционная система монитора после полной загрузки. В фазе же работы бутлоадера USB мертв. Требовалось найти регистры инициализации USB-хаба и моста и прописать их инициализацию прямо в теле кастомного бутлоадера.

    Поиски заняли некоторое время. В мониторе помимо моста живет USB-хаб, к которому тот и подключен. Оба узла управляются дискретными линиями GPIO, а даташитов, напомню, нет. ИИ методично перебирал гипотезы: генерировал патчи, я шил их во флеш, перезагружал монитор, отклонял джойстик вправо (вызывая новую ветку загрузчика) и смотрел, появятся ли устройства в списке подключенных к моему MacBook Pro. Метод научного тыка в тандеме с нейросетью творит чудеса. Искомые пины были найдены.

    Более того, теперь я веду документацию по GPIO (наглядный ответ на вопрос «как поднять хаб и мост»):

    Ставлю агенту задачу: «При отклонении джойстика вправо переводить монитор в сервисный ISP-режим».

    Итоговый кастомный бутлоадер обрел следующие скиллы:

    • Джойстик вправо — перевод в ISP. Можно заливать новые образы с ПК по USB. Правда, экран при этом полностью гаснет, выглядя мертвым (надо бы доработать индикацию, да руки не доходят).

    • Джойстик вверх/вниз — выбор банка памяти. По умолчанию грузится родная прошивка MSI из нижнего банка, по движению вверх — мой экспериментальный бинарник. Учитывая размеры микросхемы, туда можно загнать хоть десяток альтернативных сборок, но зачем? Нужны здравые идеи.

    Добвбив эти фичи, я наконец демонтировал длинные сопли проводов от флеша, вернув монитору заводскую стабильность питания, и продолжил ковырять софт. Вы думаете, мне хоть раз пригодился внешний программатор для восстановления? Ни единого раза. Весь код, сгенерированный ИИ, компилировался и работал с первого раза. Мелкие баги вроде отвалившегося UART погоды не делали.

    Почти заключение

    Статья разрастается до неприличных размеров, пора подводить промежуточные итоги.

    Исследование проприетарной электроники с помощью ИИ-агентов превратилось из удела затворников-одиночек в увлекательный квест. Если вас цепляет тема — попробуйте повторить, я намеренно приводил формулировки своих промптов для старта.

    Моя сверхзадача — полностью заменить прошивку монитора открытым ПО, получив полный контроль над функциями.

    На текущий момент уже написаны и выложены в открытый доступ кастомные бутлоадеры для скалера и USB-моста (SergeyZh/mpg-341cqpx-qd-oled-re). Код USB-моста содержит приятный бонус — возможность считывать дамп памяти без вскрытия корпуса (детали опишу позже).

    Параллельно готовы наброски прошивок для STBC и Leon2 Main. Именно их вы можете наблюдать на заглавном фото статьи с кастомным OSD-интерфейсом. Правда, выкладывать их в публичный доступ пока рано: в коде еще слишком много заимствований из оригинального софта вендора, а цель состоит в чистом переписании логики.

    Часто задаваемые вопросы

    Зачем всё это?

    Это безумно увлекательно. В процессе работы я узнал массу фундаментальных вещей:

    • SPI Flash умеет отдавать данные по четырем линиям одновременно (Quad SPI), ускоряя чтение вчетверо.

    • Классическая адресация SPI ограничена 24 битами (16 МБ). Для преодоления этого лимита инженеры внедрили регистр страничного переключения: запись единицы переключает верхнюю и нижнюю половины чипа. Именно так реализована схема с дублированием прошивок в моем 32-мегабайтном чипе.

    • В контроллере USB-моста живут две независимые прошивки: APROM (основное приложение) и LDROM (загрузчик для обновления первой). Я могу подменять обе, но пока переписал лишь APROM.

    • В недрах монитора распакован целый гигабайт оперативной памяти, позволяющий программно дампить картинку с экрана.

    • Я научился перехватывать и парсить низкоуровневый USB-трафик.

    • <и многое другое>

    Сколько же процессоров внутри монитора?

    Точного ответа на этот вопрос я пока не дам, но давайте суммируем то, что уже найдено:

    • Четыре процессорных ядра внутри основного кристалла скалера.

    • Контроллер USB-моста U7005 (Nuvoton NUC1261).

    • Контроллер USB-хаба VL211 (VIA Labs) со своей прошивкой во флеше U1508.

    Итого — шесть штук.

    Не стоит забывать про собственный мощный микроконтроллер OLED-панели Samsung, общающийся со скалером по шине I2C. Скорее всего, он прячется под центральным массивным экраном. Это отличный кандидат на отдельный проект по реверсу.

    Кроме того, в процессе анализа обновления выяснилось, что второй раздел прошивки (0x02) исполняется на отдельном, неиспользуемом в штатном режиме ядре 8051. То есть кремний содержит не четыре, а как минимум пять ядер.

    Какие функции хочется внедрить в первую очередь?

    Главная цель — снизить порог входа для кастомизации. Не просто внести разовую правку, а сделать создание модификаций доступным для любого владельца.

    Планы:

    • Заменить назойливый логотип при включении на кастомную картинку (несмотря на желание вообще его вырубить).

    • Перерисовать дизайн OSD-меню и внедрить кастомные шрифты. Вернем золотую эру скинов Winamp!

    • Реализовать модульную локализацию интерфейса.

    • Добавить функцию дампа framebuffer в файл.

    • Встроить ретро-игры (Тетрис, Doom…).

    • Режим текстового терминала, задействующий два OSD-плана с сеткой 12×18 пикселей.

    • Поддержка плагинов на Lua (или другом легковесном интерпретаторе, портируемом на архитектуру SPARC).

    • Вывод расширенной телеметрии видеосигнала в реальном времени.

    • Создание «минималистичной» прошивки-ядра с подгрузкой цветовых профилей, шрифтов, языков и скинов меню с USB-флешки на лету.

    • <Ваши идеи?>

    Я отдаю себе отчет в том, что могу остаться единственным пользователем всех этих извращений, но процесс того стоит. 🙂

    Я продолжу публиковать заметки о ковырянии монитора — материала накопилось с избытком, но объем статьи пора ограничивать.

    Спасибо всем, кто осилил этот лонгрид до конца!

     

    Источник

Похожие статьи

Поиск по играм, новостям и статьям…

Введите не менее двух символов

Введите не менее двух символов