Reverse Engineering ESP8266 — часть 1

Поддавшись общей волне энтузиазма относительно систем «Умный дом», а также имея профильное образование инженера АСУ ТП, с удовольствием занимаюсь данной темой в виде хобби. В этой статье поделюсь с вами своим опытом реверс-инжиниринга популярного модуля ESP8266.


Содержание


  1. Введение
  2. Архитектура ESP8266
  3. Инструменты
  4. Загрузка прошивки для исследования
    • ELF
    • Системная прошивка модуля
    • Пользовательская прошивка
  5. Ассемблер Xtensa
    • Регистры
    • Базовые операторы
    • Функции
    • Условные переходы
  6. Заключение
  7. Ссылки


1. Введение


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

Чтобы систематизировать всю полученную информацию и была написана эта статья.

2. Архитектура ESP8266


Не буду приводить технические характеристики, про это уже много написано, в том числе и на Хабре. Желающие могут ознакомиться, например, здесь.

Начнем с общей архитектуры системы. Модуль представляет собой Soc, в основе которого лежит процессор семейства Xtensa – Tensilica’s L106 Diamond series производства американской компании Cadence, а также микросхему флеш-памяти на 512кБ. Сам модуль разработан китайской компанией Espressif Systems. Таким образом, основная официальная информация по ESP8266 поступает от Espressif (на китайском языке и в переводе), а некоторые общие данные можно получать от Cadence.

Особенностью данного семейства процессоров является то, что они представляют собой конструктор, из которого заказчик с помощью предлагаемого инструмента Xtensa Processor Generator может собрать чип с нужными ему характеристиками и заказать его у производителя. Поэтому различные модификации могут сильно отличаться, например, количеством ядер, дополнительными инструкциями, модулями DSP и так далее.

Карта памяти (адресного пространства)

Как я уже говорил выше, модель состоит из flash ROM размером 512 КБ и SoC, который, по неподтвержденным данным имеет RAM до 248 КБ.

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

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

Внутренняя память:
Диапазон Описание
3FFE8000h — 3FFFBFFFh оперативная память для пользовательских приложений. При старте модуля может инициализироваться значениями из пользовательской прошивки.
3FFFC000h — 3FFFFFFFh системная оперативная память
40000000h — 4000FFFFh системный ROM. Отсюда стартует процессор, загружается пользовательская прошивка и здесь находятся основные системные библиотеки.
40100000h — 4010FFFFh оперативная память, содержит пользовательскую прошивку
40240000h — 40271FFFh вторая часть пользовательской прошивки. Здесь находятся код подключенных библиотек и SDK. Подмаплено к flash по адресу 40000h.

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

Flash:
Диапазон Описание
00000h — 3DFFFh адрес загрузки пользовательской прошивки
40000h — 7BFFFh адрес загрузки библиотек SDK (также может являться частью пользовательской прошивки)

Формат прошивки

Теперь, перед тем, как перейти к процессу запуска модуля, рассмотрим формат прошивки. Для загрузки пользовательской прошивки обычно достаточно записать 2 блока данных: по адресу 00000h и 40000h. Остальные блоки могут потребовать перепрошивки для сброса конфигурации, например, при заливке новой прошивки с несовместимым форматом данных.

Блок, начинающийся с 40000h содержит простой бинарный код, который загружается и работает в неизменном виде. А вот блок, начинающийся с 00000h, представляет собой структурированные данные о находящихся в нем сегментах и выглядит следующим образом:
Смещение Описание
0 идентификатор прошивки, всегда `0xE9`
1 количество сегментов в прошивке
2,3 параметры SPI Flash
4-7 адрес запуска прошивки (Entry Point)
8... далее идут данные сегментов

Структура сегмента:
Смещение Описание
0-3 адрес для загрузки сегмента
4-7 размер сегмента
8... далее идут данные сегмента

Завершающий блок:

Заполнен нулями для выравнивания до границы 16 байт минус 1 байт. После этого добавляется последний байт, представляющий собой контрольную сумму данных всех сегментов, вычисляемая функцией xor над всеми байтами и константой `0xEF`.

Формат прошивки взят из описания к утилите esptool.

Процесс запуска

Теперь, вооружившись этими знаниями, рассмотрим процесс старта модуля ESP8266 с точки зрения инициализации и запуска прошивки.

При подаче питания или поступлении сигнала сброса процессор начинает выполнение инструкций с адреса 40000080h (системный ROM). По адресу 40001308h располагается процедура, которая считывает блок 00000h flash и копирует сегменты, хранящиеся в ней по заданным адресам.


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

После всех инициализаций управление передается по адресу, указанному в заголовке прошивки. Обычно это адрес пользовательского кода 40100000h.

3. Инструменты


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

Для проектирования, разработки и отладки продуктов на базе SoC Xtensa существует пакет Xtensa Xplorer от производителя процессора, в состав которого входит множество утилит, включая TurboXIM – симулятор SoC. Теоретически, эта утилита могла бы быть полезной, но даже бесплатная версия требует лицензионных ключей, выдаваемых по запросу. Написав такой запрос я не получил ответа, поэтому воспользоваться симулятором не удалось. Скачать весь набор инструментов можно здесь, возможно, вам повезет больше.

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

Из традиционных инструментов воспользуемся IDA Pro и HIEW.

Для изучения кода процессора Xtensa необходимо использовать IDA Pro версии 6.6 и выше со встроенным интерпретатором питона для выполнения скриптов. В перечень стандартно поддерживаемых процессоров Xtensa не входит, поэтому каждый раз при запуске IDA Pro перед открытием исследуемого файла необходимо загружать скрипт “xtensa.py”, который можно взять здесь.

Также для автоматического создания сегментов и наименования функций системного ROM нам понадобится скрипт для IDA Pro. Скрипт и дамп системной прошивки можно скачать здесь.

HIEW будет полезен для исследования структуры ELF- и готовых двоичных файлов прошивки.

В следующей части мы рассмотрим процесс загрузки прошивки для исследования.

Update. Продолжение здесь.
Метки:
Поделиться публикацией
Похожие публикации
Комментарии 17
  • +1
    Крутая работа. Будет здорово, когда распотрошите и выложите готовую схему для подключения исполнительных устройств или датчиков, чтобы можно было обходиться без ардуины.
    • +5
      Собственно, SDK уже сейчас позволяет писать прошивки с подключением любых устройств — библиотеки для работы с GPIO есть. Только в отличие от Arduino все пишется на С.
      Из готовых проектов можно посмотреть nodeMCU или homes-smart.ru (с их автороми я никак не связан).
      По поводу замены ардуины полностью согласен — функционал гораздо шире.
      • +2
        Только в отличие от Arduino все пишется на С.

        Уже допилили arduino ide для поддержки eps8266 )
        esp8266.ru/arduino-ide-esp8266/
        • +1
          Учитывая качество библиотек в SDK, я бы воздержался от дополнительной прослойки в виде arduino-совместимых библиотек качество которых, тоже часто вызывает вопросы. И так отлаживать креши, которые растут из блобов Espressif'а — то еще удовольствие. В последних SDK стало немного лучше, но все равно далеко не сахар.
      • 0
        Использую вышепредложенное nodeMCU. LUA мне кажется даже более приятным языком, чем предлагает Arduino. И подключать устройства можно уже сейчас.
        • 0
          Ещё есть frankenstein. Находится в стадии допиливания, предоставляет интерфейс командной строки по типу стандартной AT прошивки, но с чуть более широкими возможностями. К консоли так же можно цепляться по сети, обновления прошивки можно заливать по воздуху, есть поддержка нескольких популярных i2c датчиков.
        • 0
          TurboXIM – симулятор SoC. Теоретически, эта утилита могла бы быть полезной, но даже бесплатная версия требует лицензионных ключей, выдаваемых по запросу.

          Xtensa core ISA поддерживается QEMU. Кое-какая моделька для esp8266 лежит здесь. А здесь соответствующий тред на esp8266.com.

          Кроме того, здесь тред про адаптированный для gdb официальный JTAG-монитор xtensa, а здесь тред про адаптированный для 8266 OpenOCD.
          • +1
            Очень интересно услышать продолжение. Китайцы особо не торопятся выкладывать исходники SDK, а не смотря на версию 1.0.0, «Fatal exception» до сих пор случаются, и порой в самых неподходящих местах.
            • 0
              Создатель frankenstein'a в треде, сейчас будем критиковать ;)

              Начнем с карты памяти, ибо указанная автором разбивка частично «предложенная Espressif организация памяти», которую я не могу считать удачной.
              1. 40000000h — 4000FFFFh — Это масочное ПЗУ, заложенное при производстве чипа. Сюда нам ничего нельзя загрузить. В принципе. Оттуда можно только дернуть некоторые функции, адреса которых захардкожены в ld файлике из SDK. Скорость работы кода оттуда должна быть сравнима с работой из RAM.
              2. 0x3FFE8000 — 0x3fffc000 — RAM. Для данных. Я не проверял может ли процессор делать оттуда фетч инструкций. Здесь у нас статические переменные (bss), .data и ВНЕЗАПНО .rodata. По каким-то причинам все начинает рандомно разваливаться (по крайней мере так было на 0.9.2 SDK), если попытаться переложить rodata в irom0_0, что на первый взгляд кажется логичным решением.
              3. 0x40100000 — 0x40107FFF (насколько помню — именно 32k!) IRAM. Оперативная память с фетчем инструкций. Сюда кладется .text и .text.literal.Отсюда должна быть максимальная скорость исполнения кода. Cюда кладутся важные куски из блобов Espressif'а.
              4. 0x40200000 — С этого адреса начинается линейный мэппинг всей SPI флешки. (aka irom0) Отсюда можно исполнять код, есть кеш инструкций неизвестного размера. Все, что не влезает в IRAM кладется сюда. Скорость исполнения отсюда в worst-case случае ниже чем из IRAM

              То, как это все будет разложено задается ld файлом, и то что навязывает Espressif — не закон.
              Благодаря такой «чудной» организации Espressif контузили lwip добавив к каждой функции ICACHE_FLASH_ATTR, который по сути кладет ф-цию в секцию .irom0.text и .irom0.literal.

              Так как контузить свой код ICACHE_FLASH_ATTR'ами не хочется — я сделал вот такой вот хак.
              Фактически, чтобы не добавлять ICACHE_FLASH_ATTR'ы мы
              переименоввываем в собранных .o секции .text -> .irom0.text и .literal -> .irom0.literal.
              Шаманство по ссылке сложнее, так как учитывает случай с -ffunction-sections и -gc-sections, когда у нас каждая функция в своей секции.

              Соответственно, если хотим использовать newlib полноценно, то его тоже надо релоцировать в irom0, iram не резиновый. esp-open-sdk специально готовит нам irom версию libc. Линковаться надо только с -lcirom вместо -lc.

              А вообще ждем полноценного реверс-инженеринга Espressif'овских блобов. В комментариях к их SDK они писали, что не открывают код, т.к. бояться что «people will make device that bring havoc to wireless networks» ©. А это значит, что там есть много любопытных сокрытых возможностей.
              • 0
                0x40100000 — 0x40107FFF (насколько помню — именно 32k!) IRAM

                64К, проверено через JTAG.

                есть кеш инструкций неизвестного размера

                32Кбайта, размер вычислен опытным путём.

                Скорость исполнения отсюда в worst-case случае ниже чем из IRAM

                Точнее, незакешированные инструкции выполняются в 13-14 раз медленнее, закешированные — так же как из IRAM. Проверено опытным путём.
                • 0
                  О, спасибо за подробности. Worst-case даже хуже чем я думал. QSPI по моим прикидкам должно было быть в 7-9 раз медленее.
                • 0
                  Спасибо за дополнение, очень интересно!
                  • 0
                    > А это значит, что там есть много любопытных сокрытых возможностей.
                    Там даже крипта зашита и какие-то куски для SSL.
                  • 0
                    Ну и, если кому надо, вот принципиальная схема и разводка моих ЛУТ-совместимых самодельных отладочных плат для игр с esp8266:
                    Фотография самоделок
                    image
                    • 0
                      А можно первую фотку с другой стороны? ))
                      • 0
                        Подскажите, а есть устройства с GPIO на подобии ESP8266, но исспользуещие BLE вместо WiFi?
                        • 0
                          Bluetooth-модуль HC-05, например.

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