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
|
# bootloader
|
||||||
|
|
||||||
> Загрузчик MIMXRT1052 — A/Б обновление `tft_app` через microSD (MCUboot,
|
Загрузчик MIMXRT1052: выбирает и запускает приложение `tft_app` из одного из двух слотов
|
||||||
> Direct-XIP). Сам bootloader обновляется только через USB ROM (blhost) или
|
(MCUboot, Direct-XIP), обновляет его с microSD, восстанавливает плату при зависании образа. Сам
|
||||||
> SWD — не в поле. Единственный канал диагностики: USB CDC ACM (JSON-lines,
|
загрузчик прошивается только по USB ROM (blhost) или SWD — в поле не обновляется. Канал диагностики —
|
||||||
> тот же стиль протокола, что у `firmware_test`).
|
USB CDC ACM (JSON-строки).
|
||||||
>
|
|
||||||
> Версия: `0.1.0` | Статус: Фаза 2 (bootutil / MCUboot Direct-XIP) завершена — см. [PLAN.md](PLAN.md)
|
|
||||||
|
|
||||||
---
|
**Принцип работы** (карта памяти, выбор образа, обновление, версии, даунгрейд, recovery) —
|
||||||
|
[BOOT_FLOW.md](BOOT_FLOW.md).
|
||||||
## Содержание
|
|
||||||
|
|
||||||
- [bootloader](#bootloader)
|
|
||||||
- [Содержание](#содержание)
|
|
||||||
- [Быстрый старт](#быстрый-старт)
|
|
||||||
- [1. Сборка](#1-сборка)
|
|
||||||
- [2. Прошивка](#2-прошивка)
|
|
||||||
- [3. Подключение](#3-подключение)
|
|
||||||
- [4. Отладка](#4-отладка)
|
|
||||||
- [Архитектура](#архитектура)
|
|
||||||
- [Карта Flash](#карта-flash)
|
|
||||||
- [Протокол](#протокол)
|
|
||||||
- [Roadmap](#roadmap)
|
|
||||||
- [Версионирование](#версионирование)
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Быстрый старт
|
## Быстрый старт
|
||||||
|
|
||||||
### 1. Сборка
|
### Сборка
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
just build::build-bootloader-debug
|
just build::build-bootloader-debug # bootloader.elf/.bin
|
||||||
just build::hab-bootloader-debug
|
just build::hab-bootloader-debug # HAB-контейнер bootloader_hab.bin
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. Прошивка
|
### Прошивка
|
||||||
|
|
||||||
Для итеративной разработки — SWD (не требует смены boot-режима платы):
|
SWD (для итеративной разработки, не требует смены boot-режима платы):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
just host::flash-swd-bootloader-debug
|
just host::flash-swd-bootloader-debug
|
||||||
# обязателен power cycle платы после прошивки
|
# после прошивки обязателен power cycle платы
|
||||||
```
|
```
|
||||||
|
|
||||||
Через USB ROM (SDP, плата в режиме Serial Downloader):
|
USB ROM (SDP, плата в режиме Serial Downloader):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
just host::flash bootloader debug
|
just host::flash bootloader debug
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3. Подключение
|
### Подключение
|
||||||
|
|
||||||
CDC поднимается, только если в обоих слотах (A/Б) нет валидного образа — иначе
|
|
||||||
bootloader сразу выбирает слот и прыгает в `tft_app` (Direct-XIP), не поднимая
|
|
||||||
USB вообще. Для проверки диагностического режима слоты должны быть пустыми
|
|
||||||
или содержать только невалидные образы.
|
|
||||||
|
|
||||||
USB CDC ACM (тот же порядок, что у `firmware_test`):
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# macOS
|
screen /dev/cu.usbmodemXXXX # macOS; порт свой на каждое подключение
|
||||||
screen /dev/cu.usbmodemXXXX
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Проверка связи:
|
|
||||||
|
|
||||||
```json
|
```json
|
||||||
→ {"type":"cmd","cmd":"ping"}
|
→ {"type":"cmd","cmd":"ping"}
|
||||||
← {"type":"pong"}
|
← {"type":"pong"}
|
||||||
|
|
@ -74,125 +48,103 @@ screen /dev/cu.usbmodemXXXX
|
||||||
← {"type":"version_response","fw":"0.1.0"}
|
← {"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`), но вместо
|
Загрузчик работает **без SDRAM** (SEMC поднимает само приложение в своём раннем startup) и без
|
||||||
тестового раннера — сразу попытка выбрать и запустить `tft_app` из одного из
|
дисплея/RTOS: инициализация, доступ к QSPI-flash, чтение FatFS с SD, проверка и выбор образа, прыжок.
|
||||||
двух слотов (MCUboot Direct-XIP, `bootutil`), и только если валидного образа
|
Линкер жёстко ограничивает код бюджетом области загрузчика (256 КБ) с `ASSERT` на границу Slot A —
|
||||||
нет ни в одном слоте — диагностический CLI:
|
превышение становится ошибкой сборки, а не тихим заездом в чужую область.
|
||||||
|
|
||||||
```bash
|
```text
|
||||||
firmware/bootloader/
|
firmware/bootloader/
|
||||||
├── CMakeLists.txt
|
├── src/
|
||||||
├── mcuboot_port/ — интеграция bootutil (MCUboot) с bsp_qspi_flash
|
│ ├── main.c — точка входа: инициализация → одна попытка загрузки
|
||||||
│ ├── flash_map_backend.c — flash_area_* поверх bsp_qspi_flash (2 слота)
|
│ │ (SD-скан + recovery-гейт + прыжок) → цикл ожидания
|
||||||
│ ├── keys.c — публичный ключ ECDSA-P256 для imgtool-подписи
|
│ ├── boot_select.* — выбор валидного слота и прыжок в выбранный образ
|
||||||
│ ├── bootutil_sources.cmake — общий список исходников bootutil+TinyCrypt+
|
│ ├── slot_version.* — read-only проверка и чтение версии слота (без побочных
|
||||||
│ │ ASN.1 (используется и host-тестами)
|
│ │ эффектов на flash)
|
||||||
│ └── mcuboot_config/, sysflash/, flash_map_backend/, keys/ — конфиг-заголовки
|
│ ├── update_policy.* — чистая логика «ставить/пропустить» + целевой слот
|
||||||
|
│ ├── recovery.* — чистая логика решения recovery (порог / фолбэк / режим)
|
||||||
|
│ ├── sd_update.* — оркестрация: смонтировать SD, найти TFT_APP.BIN,
|
||||||
|
│ │ установить в целевой слот с потоковой verify-записью
|
||||||
|
│ ├── cli.* — построчный IO + диспетчеризация команд
|
||||||
|
│ ├── protocol.* — сериализация исходящих событий
|
||||||
|
│ └── version.h.in — шаблон версии (CMake → generated/version.h)
|
||||||
│
|
│
|
||||||
└── src/
|
├── mcuboot_port/ — интеграция bootutil (MCUboot) поверх bsp_qspi_flash:
|
||||||
├── main.c — board_hw_init → led/tick/qspi init →
|
│ flash_area_* на 2 слота, конфиг, публичный ключ ECDSA-P256
|
||||||
│ boot_select_and_jump() (при успехе не
|
├── fatfs/ — read-only FatFS для чтения TFT_APP.BIN с карты
|
||||||
│ возвращается) → иначе usb_cdc init → ожидание
|
└── test_stub/ — самостоятельный подписанный образ-заглушка вместо
|
||||||
│ CDC (LED_HEARTBEAT мигает) → LED_APP on →
|
tft_app для аппаратной проверки загрузчика
|
||||||
│ главный цикл (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()
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Bootloader **без SDRAM** — DCD не используется (`bsp_boot_xip_no_dcd` вместо
|
`update_policy` и `recovery` — чистые функции без доступа к железу, целиком покрыты host-тестами.
|
||||||
`bsp_boot_xip`). `tft_app` инициализирует SEMC сама в своём раннем startup
|
`boot_select`, `sd_update`, `flash_map_backend` — тонкий аппаратный слой поверх них.
|
||||||
(см. [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` | остальное (рантайм) |
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Протокол
|
## Протокол
|
||||||
|
|
||||||
Транспорт и фреймирование — как у `firmware_test`
|
USB CDC ACM, JSON-строки, максимум 128 байт на строку.
|
||||||
([firmware/test/README.md](../test/README.md#протокол-v2)): USB CDC ACM,
|
|
||||||
JSON-lines, максимум 128 байт на строку.
|
|
||||||
|
|
||||||
**Реализовано (Фаза 1):**
|
**Команды хоста:**
|
||||||
|
|
||||||
| Команда хоста | Ответ |
|
| Команда | Ответ |
|
||||||
| ------------------------------------ | ------------------------------------------ |
|
| ------------------------------------ | ------------------------------------------------------------------------------------- |
|
||||||
| `{"type":"cmd","cmd":"ping"}` | `{"type":"pong"}` |
|
| `{"type":"cmd","cmd":"ping"}` | `{"type":"pong"}` |
|
||||||
| `{"type":"cmd","cmd":"get_version"}` | `{"type":"version_response","fw":"X.Y.Z"}` |
|
| `{"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`-события
|
**Ошибки** `{"ok":false,"error":"…"}`: `SD_CANDIDATE_INVALID`, `SD_INSTALL_WRITE_FAILED`,
|
||||||
(`waiting_for_sd`, `installing`, `smoke_pass`/`smoke_fail`, `booting`) —
|
`SD_INSTALL_REJECTED`, `SD_DOWNGRADE_ERASE_FAILED`, `PARSE_ERR`, `UNKNOWN_CMD`, `LINE_TOO_LONG`.
|
||||||
Фазы 3-4.
|
|
||||||
|
Событие `wdog` эмитится также автоматически один раз на старте, если предыдущий сброс был по
|
||||||
|
watchdog (`recovered:true`).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Roadmap
|
## Тесты
|
||||||
|
|
||||||
Полный план по фазам с целями и критериями верификации — [PLAN.md](PLAN.md).
|
**Host** — вся логика без железа (выбор слота, сравнение версий, политика установки, решение
|
||||||
|
recovery, протокол, CLI) на in-memory flash-фейках:
|
||||||
|
|
||||||
| Фаза | Что делает |
|
```bash
|
||||||
| ---- | ---------------------------------------------------------------- |
|
just build::test-host
|
||||||
| 0 ✅ | Карта Flash, регистрация в сборке |
|
```
|
||||||
| 1 ✅ | Скелет: bring-up, USB CDC, ping/get_version, LED heartbeat |
|
|
||||||
| 2 ✅ | bootutil (MCUboot Direct-XIP) — выбор слота, верификация подписи |
|
**Аппаратный стенд** — сборка и подпись образов-заглушек, замещающих `tft_app` при ручной проверке
|
||||||
| 3 | Установка образа с microSD, состояние "нет валидного слота" |
|
на плате (здоровые образы + варианты с зависанием на разных стадиях для проверки восстановления):
|
||||||
| 4 | SDRAM/W25Q smoke-test, словарь LED-паттернов |
|
|
||||||
| 5 | HAB Release, интеграция в service-tui |
|
```bash
|
||||||
|
just build::build-mcuboot-stub
|
||||||
|
```
|
||||||
|
|
||||||
|
Чек-листы ручной проверки лежат рядом со стендом в `test_stub/`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Версионирование
|
## Версионирование
|
||||||
|
|
||||||
Версия задаётся `project(bootloader VERSION X.Y.Z)` в `CMakeLists.txt`,
|
Версия задаётся `project(bootloader VERSION X.Y.Z)` в `CMakeLists.txt` и прокидывается через
|
||||||
прокидывается через `configure_file(src/version.h.in → generated/version.h)`
|
`configure_file(src/version.h.in → generated/version.h)` в строку, которую возвращает
|
||||||
в `BOOTLOADER_VERSION_STR` — тот же механизм, что у `firmware_test`
|
`get_version`. `version.h` генерируется, вручную не редактируется.
|
||||||
(см. [firmware/test/README.md#версионирование](../test/README.md#версионирование)).
|
|
||||||
|
|
||||||
`version.h` генерируется, не редактируется вручную.
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue