Update README.md
This commit is contained in:
parent
8cb1cb143c
commit
12bb949834
1 changed files with 84 additions and 132 deletions
|
|
@ -1,71 +1,45 @@
|
|||
# bootloader
|
||||
|
||||
> Загрузчик MIMXRT1052 — A/Б обновление `tft_app` через microSD (MCUboot,
|
||||
> Direct-XIP). Сам bootloader обновляется только через USB ROM (blhost) или
|
||||
> SWD — не в поле. Единственный канал диагностики: USB CDC ACM (JSON-lines,
|
||||
> тот же стиль протокола, что у `firmware_test`).
|
||||
>
|
||||
> Версия: `0.1.0` | Статус: Фаза 2 (bootutil / MCUboot Direct-XIP) завершена — см. [PLAN.md](PLAN.md)
|
||||
Загрузчик MIMXRT1052: выбирает и запускает приложение `tft_app` из одного из двух слотов
|
||||
(MCUboot, Direct-XIP), обновляет его с microSD, восстанавливает плату при зависании образа. Сам
|
||||
загрузчик прошивается только по USB ROM (blhost) или SWD — в поле не обновляется. Канал диагностики —
|
||||
USB CDC ACM (JSON-строки).
|
||||
|
||||
---
|
||||
|
||||
## Содержание
|
||||
|
||||
- [bootloader](#bootloader)
|
||||
- [Содержание](#содержание)
|
||||
- [Быстрый старт](#быстрый-старт)
|
||||
- [1. Сборка](#1-сборка)
|
||||
- [2. Прошивка](#2-прошивка)
|
||||
- [3. Подключение](#3-подключение)
|
||||
- [4. Отладка](#4-отладка)
|
||||
- [Архитектура](#архитектура)
|
||||
- [Карта Flash](#карта-flash)
|
||||
- [Протокол](#протокол)
|
||||
- [Roadmap](#roadmap)
|
||||
- [Версионирование](#версионирование)
|
||||
**Принцип работы** (карта памяти, выбор образа, обновление, версии, даунгрейд, recovery) —
|
||||
[BOOT_FLOW.md](BOOT_FLOW.md).
|
||||
|
||||
---
|
||||
|
||||
## Быстрый старт
|
||||
|
||||
### 1. Сборка
|
||||
### Сборка
|
||||
|
||||
```bash
|
||||
just build::build-bootloader-debug
|
||||
just build::hab-bootloader-debug
|
||||
just build::build-bootloader-debug # bootloader.elf/.bin
|
||||
just build::hab-bootloader-debug # HAB-контейнер bootloader_hab.bin
|
||||
```
|
||||
|
||||
### 2. Прошивка
|
||||
### Прошивка
|
||||
|
||||
Для итеративной разработки — SWD (не требует смены boot-режима платы):
|
||||
SWD (для итеративной разработки, не требует смены boot-режима платы):
|
||||
|
||||
```bash
|
||||
just host::flash-swd-bootloader-debug
|
||||
# обязателен power cycle платы после прошивки
|
||||
# после прошивки обязателен power cycle платы
|
||||
```
|
||||
|
||||
Через USB ROM (SDP, плата в режиме Serial Downloader):
|
||||
USB ROM (SDP, плата в режиме Serial Downloader):
|
||||
|
||||
```bash
|
||||
just host::flash bootloader debug
|
||||
```
|
||||
|
||||
### 3. Подключение
|
||||
|
||||
CDC поднимается, только если в обоих слотах (A/Б) нет валидного образа — иначе
|
||||
bootloader сразу выбирает слот и прыгает в `tft_app` (Direct-XIP), не поднимая
|
||||
USB вообще. Для проверки диагностического режима слоты должны быть пустыми
|
||||
или содержать только невалидные образы.
|
||||
|
||||
USB CDC ACM (тот же порядок, что у `firmware_test`):
|
||||
### Подключение
|
||||
|
||||
```bash
|
||||
# macOS
|
||||
screen /dev/cu.usbmodemXXXX
|
||||
screen /dev/cu.usbmodemXXXX # macOS; порт свой на каждое подключение
|
||||
```
|
||||
|
||||
Проверка связи:
|
||||
|
||||
```json
|
||||
→ {"type":"cmd","cmd":"ping"}
|
||||
← {"type":"pong"}
|
||||
|
|
@ -74,125 +48,103 @@ screen /dev/cu.usbmodemXXXX
|
|||
← {"type":"version_response","fw":"0.1.0"}
|
||||
```
|
||||
|
||||
### 4. Отладка
|
||||
USB поднимается на каждой загрузке до обращения к SD, поэтому статусы видны, даже если подключиться
|
||||
заранее.
|
||||
|
||||
VSCode → `🐛 Debug: bootloader` (`.vscode/launch.json`) — пересобирает через
|
||||
`build:bootloader-debug`, подключается к GDB-серверу (`just host::debug-server`
|
||||
должен быть запущен), останавливается на `main`.
|
||||
### Отладка
|
||||
|
||||
VSCode → `🐛 Debug: bootloader` — пересобирает, подключается к GDB-серверу
|
||||
(`just host::debug-server` должен быть запущен), останавливается на `main`. Под отладчиком аппаратный
|
||||
watchdog приостановлен, пошаговая отладка сбросами не сбивается.
|
||||
|
||||
---
|
||||
|
||||
## Архитектура
|
||||
|
||||
Bring-up идентичен `firmware_test` (`firmware/test/src/main.c`), но вместо
|
||||
тестового раннера — сразу попытка выбрать и запустить `tft_app` из одного из
|
||||
двух слотов (MCUboot Direct-XIP, `bootutil`), и только если валидного образа
|
||||
нет ни в одном слоте — диагностический CLI:
|
||||
Загрузчик работает **без SDRAM** (SEMC поднимает само приложение в своём раннем startup) и без
|
||||
дисплея/RTOS: инициализация, доступ к QSPI-flash, чтение FatFS с SD, проверка и выбор образа, прыжок.
|
||||
Линкер жёстко ограничивает код бюджетом области загрузчика (256 КБ) с `ASSERT` на границу Slot A —
|
||||
превышение становится ошибкой сборки, а не тихим заездом в чужую область.
|
||||
|
||||
```bash
|
||||
```text
|
||||
firmware/bootloader/
|
||||
├── CMakeLists.txt
|
||||
├── mcuboot_port/ — интеграция bootutil (MCUboot) с bsp_qspi_flash
|
||||
│ ├── flash_map_backend.c — flash_area_* поверх bsp_qspi_flash (2 слота)
|
||||
│ ├── keys.c — публичный ключ ECDSA-P256 для imgtool-подписи
|
||||
│ ├── bootutil_sources.cmake — общий список исходников bootutil+TinyCrypt+
|
||||
│ │ ASN.1 (используется и host-тестами)
|
||||
│ └── mcuboot_config/, sysflash/, flash_map_backend/, keys/ — конфиг-заголовки
|
||||
├── src/
|
||||
│ ├── main.c — точка входа: инициализация → одна попытка загрузки
|
||||
│ │ (SD-скан + recovery-гейт + прыжок) → цикл ожидания
|
||||
│ ├── boot_select.* — выбор валидного слота и прыжок в выбранный образ
|
||||
│ ├── slot_version.* — read-only проверка и чтение версии слота (без побочных
|
||||
│ │ эффектов на flash)
|
||||
│ ├── update_policy.* — чистая логика «ставить/пропустить» + целевой слот
|
||||
│ ├── recovery.* — чистая логика решения recovery (порог / фолбэк / режим)
|
||||
│ ├── sd_update.* — оркестрация: смонтировать SD, найти TFT_APP.BIN,
|
||||
│ │ установить в целевой слот с потоковой verify-записью
|
||||
│ ├── cli.* — построчный IO + диспетчеризация команд
|
||||
│ ├── protocol.* — сериализация исходящих событий
|
||||
│ └── version.h.in — шаблон версии (CMake → generated/version.h)
|
||||
│
|
||||
└── src/
|
||||
├── main.c — board_hw_init → led/tick/qspi init →
|
||||
│ boot_select_and_jump() (при успехе не
|
||||
│ возвращается) → иначе usb_cdc init → ожидание
|
||||
│ CDC (LED_HEARTBEAT мигает) → LED_APP on →
|
||||
│ главный цикл (poll + cli_process)
|
||||
│
|
||||
├── boot_select.c/.h — обёртка над bootutil: `boot_go()` (выбор
|
||||
│ валидного слота по подписи/версии) + прыжок в
|
||||
│ выбранный образ (`jump_to_image`)
|
||||
│
|
||||
├── version.h.in — шаблон версии (CMake → generated/version.h)
|
||||
│
|
||||
├── cli.h / cli.c — IO-слой: буферизация строк, парсинг "type"/"cmd"
|
||||
│ (урезанное подмножество firmware_test/src/cli.c)
|
||||
│
|
||||
└── protocol.h / .c — сериализация исходящих событий → cli_send()
|
||||
├── mcuboot_port/ — интеграция bootutil (MCUboot) поверх bsp_qspi_flash:
|
||||
│ flash_area_* на 2 слота, конфиг, публичный ключ ECDSA-P256
|
||||
├── fatfs/ — read-only FatFS для чтения TFT_APP.BIN с карты
|
||||
└── test_stub/ — самостоятельный подписанный образ-заглушка вместо
|
||||
tft_app для аппаратной проверки загрузчика
|
||||
```
|
||||
|
||||
Bootloader **без SDRAM** — DCD не используется (`bsp_boot_xip_no_dcd` вместо
|
||||
`bsp_boot_xip`). `tft_app` инициализирует SEMC сама в своём раннем startup
|
||||
(см. [BOOTLOADER_FLASH_MAP.md](../../docs/mimxrt1052/BOOTLOADER_FLASH_MAP.md)).
|
||||
|
||||
Линкер: `cmake/linker/MIMXRT1052xxxxx_bootloader_flexspi_nor.ld` — `m_text`
|
||||
жёстко ограничен 247 КБ, с `ASSERT` на границу Slot A.
|
||||
|
||||
Верификация образов — подпись ECDSA-P256 (bootutil/TinyCrypt), два независимых
|
||||
слота (A/Б) по 2 МБ каждый, без swap/scratch (Direct-XIP). Аппаратно
|
||||
верифицировано все 5 сценариев чек-листа (единственный валидный слот, выбор
|
||||
более новой версии, откат при повреждении, оба слота пусты, revert
|
||||
неподтверждённого образа)
|
||||
|
||||
---
|
||||
|
||||
## Карта Flash
|
||||
|
||||
Полная карта, обоснование размеров и принцип "один bootloader на любую
|
||||
ёмкость чипа" — в
|
||||
[docs/mimxrt1052/BOOTLOADER_FLASH_MAP.md](../../docs/mimxrt1052/BOOTLOADER_FLASH_MAP.md).
|
||||
|
||||
| Область | Смещение | Размер |
|
||||
| --------------------------- | ------------ | ------------------- |
|
||||
| Bootloader | `0x60000000` | 256 КБ |
|
||||
| Slot A (tft_app) | `0x60040000` | 2 МБ |
|
||||
| Slot Б (tft_app) | `0x60240000` | 2 МБ |
|
||||
| ФС ассетов (спрайты/музыка) | `0x60440000` | остальное (рантайм) |
|
||||
`update_policy` и `recovery` — чистые функции без доступа к железу, целиком покрыты host-тестами.
|
||||
`boot_select`, `sd_update`, `flash_map_backend` — тонкий аппаратный слой поверх них.
|
||||
|
||||
---
|
||||
|
||||
## Протокол
|
||||
|
||||
Транспорт и фреймирование — как у `firmware_test`
|
||||
([firmware/test/README.md](../test/README.md#протокол-v2)): USB CDC ACM,
|
||||
JSON-lines, максимум 128 байт на строку.
|
||||
USB CDC ACM, JSON-строки, максимум 128 байт на строку.
|
||||
|
||||
**Реализовано (Фаза 1):**
|
||||
**Команды хоста:**
|
||||
|
||||
| Команда хоста | Ответ |
|
||||
| ------------------------------------ | ------------------------------------------ |
|
||||
| Команда | Ответ |
|
||||
| ------------------------------------ | ------------------------------------------------------------------------------------- |
|
||||
| `{"type":"cmd","cmd":"ping"}` | `{"type":"pong"}` |
|
||||
| `{"type":"cmd","cmd":"get_version"}` | `{"type":"version_response","fw":"X.Y.Z"}` |
|
||||
| `{"type":"cmd","cmd":"wdog"}` | `{"type":"wdog","armed":…,"timeout_s":…,"recovered":…,"reset_count":…,"threshold":…}` |
|
||||
|
||||
Ошибки: `{"ok":false,"error":"PARSE_ERR"}` / `"UNKNOWN_CMD"` / `"LINE_TOO_LONG"`.
|
||||
**Исходящие статусы** `{"type":"status","state":"…"}`:
|
||||
|
||||
Без `session_start` — в отличие от `firmware_test`, bootloader не шлёт
|
||||
приветствие автоматически; живость проверяется явным `ping` (тот же паттерн,
|
||||
что использует HIL-фикстура `firmware_cdc` для `firmware_test`).
|
||||
| Состояние | Когда |
|
||||
| ---------------- | ------------------------------- |
|
||||
| `waiting_for_sd` | нет валидного слота, ждём карту |
|
||||
| `installing` | идёт запись образа в слот |
|
||||
| `update_skipped` | кандидат отклонён по версии |
|
||||
| `recovery_mode` | плата в режиме восстановления |
|
||||
|
||||
**Появится в следующих фазах** (см. [PLAN.md](PLAN.md)): `status`-события
|
||||
(`waiting_for_sd`, `installing`, `smoke_pass`/`smoke_fail`, `booting`) —
|
||||
Фазы 3-4.
|
||||
**Ошибки** `{"ok":false,"error":"…"}`: `SD_CANDIDATE_INVALID`, `SD_INSTALL_WRITE_FAILED`,
|
||||
`SD_INSTALL_REJECTED`, `SD_DOWNGRADE_ERASE_FAILED`, `PARSE_ERR`, `UNKNOWN_CMD`, `LINE_TOO_LONG`.
|
||||
|
||||
Событие `wdog` эмитится также автоматически один раз на старте, если предыдущий сброс был по
|
||||
watchdog (`recovered:true`).
|
||||
|
||||
---
|
||||
|
||||
## Roadmap
|
||||
## Тесты
|
||||
|
||||
Полный план по фазам с целями и критериями верификации — [PLAN.md](PLAN.md).
|
||||
**Host** — вся логика без железа (выбор слота, сравнение версий, политика установки, решение
|
||||
recovery, протокол, CLI) на in-memory flash-фейках:
|
||||
|
||||
| Фаза | Что делает |
|
||||
| ---- | ---------------------------------------------------------------- |
|
||||
| 0 ✅ | Карта Flash, регистрация в сборке |
|
||||
| 1 ✅ | Скелет: bring-up, USB CDC, ping/get_version, LED heartbeat |
|
||||
| 2 ✅ | bootutil (MCUboot Direct-XIP) — выбор слота, верификация подписи |
|
||||
| 3 | Установка образа с microSD, состояние "нет валидного слота" |
|
||||
| 4 | SDRAM/W25Q smoke-test, словарь LED-паттернов |
|
||||
| 5 | HAB Release, интеграция в service-tui |
|
||||
```bash
|
||||
just build::test-host
|
||||
```
|
||||
|
||||
**Аппаратный стенд** — сборка и подпись образов-заглушек, замещающих `tft_app` при ручной проверке
|
||||
на плате (здоровые образы + варианты с зависанием на разных стадиях для проверки восстановления):
|
||||
|
||||
```bash
|
||||
just build::build-mcuboot-stub
|
||||
```
|
||||
|
||||
Чек-листы ручной проверки лежат рядом со стендом в `test_stub/`.
|
||||
|
||||
---
|
||||
|
||||
## Версионирование
|
||||
|
||||
Версия задаётся `project(bootloader VERSION X.Y.Z)` в `CMakeLists.txt`,
|
||||
прокидывается через `configure_file(src/version.h.in → generated/version.h)`
|
||||
в `BOOTLOADER_VERSION_STR` — тот же механизм, что у `firmware_test`
|
||||
(см. [firmware/test/README.md#версионирование](../test/README.md#версионирование)).
|
||||
|
||||
`version.h` генерируется, не редактируется вручную.
|
||||
Версия задаётся `project(bootloader VERSION X.Y.Z)` в `CMakeLists.txt` и прокидывается через
|
||||
`configure_file(src/version.h.in → generated/version.h)` в строку, которую возвращает
|
||||
`get_version`. `version.h` генерируется, вручную не редактируется.
|
||||
|
|
|
|||
Loading…
Reference in a new issue