Практический разбор: заводская прошивка Linksys → неудачная установка OpenWrt → UART и U-Boot → загрузка OpenWrt из RAM по TFTP → восстановление UBI-раздела → успешная загрузка OpenWrt 23.05.6.
Область применения. Это описание конкретного случая с Linksys EA4500 на Marvell Kirkwood, имеющим два слота прошивки и NAND с плохим блоком
0x01DE0000. Инструкции не являются универсальными для всех EA4500, особенно для аппаратной ревизии v3, использующей другую платформу. Перед записью NAND обязательно сверяйте вывод/proc/mtdи фактическую разметку. Неверный раздел может лишить устройство даже заводской резервной прошивки.Статус системы. Восстановлена и успешно загружается OpenWrt 23.05.6. Эта серия OpenWrt уже завершила жизненный цикл и не получает исправлений безопасности. Здесь она используется как проверенная промежуточная точка восстановления, а не как рекомендация для долгосрочной эксплуатации на внешнем WAN.
Что было на старте
В наличии был Linksys EA4500 с оригинальной прошивкой Linksys Smart Wi-Fi (2.1.41.162351). Цель — заменить заводскую систему на OpenWrt. Описываемая статья посвящена именно установке и восстановлению OpenWrt, не настройке обхода блокировок.
Устройство оснащено SoC Marvell Kirkwood 88F6282 (ARMv5, архитектура OpenWrt arm_xscale), примерно 128 МиБ оперативной памяти и NAND на 128 МиБ с блоками стирания по 128 КиБ. На плате доступна последовательная консоль UART. Питание — 12 В; при работах с UART используйте логический уровень 3,3 В, не подключайте к плате 5-вольтовый TTL и обычно не соединяйте VCC USB–UART адаптера с роутером. Нужны общая земля, TX↔RX и RX↔TX. Параметры терминала: 115200, 8N1.
Важная особенность EA4500 — двухслотовая прошивка: при обновлении через штатный интерфейс новый образ попадает в неактивный слот, после чего загрузчик пытается переключиться на него. Это полезно при восстановлении, но не отменяет необходимости беречь рабочий слот.
Шаг 1. Попытка обычной установки из заводского интерфейса
Сначала был загружен официальный файл:
openwrt-23.05.6-kirkwood-generic-linksys_ea4500-squashfs-factory.bin
Это правильный тип файла для первоначальной установки через веб-интерфейс Linksys. Образы sysupgrade.bin применяются для обновления уже работающего OpenWrt и не взаимозаменяемы с factory.bin.
После прошивки роутер не загрузился: происходили перезапуски и периоды отсутствия вывода UART. Попытка с OpenWrt 22.03 дала сходный результат. Это выглядело как неудачная прошивка, но причина оказалась более конкретной.
При этом появлялись аппаратные особенности: иногда после перезапуска консоль молчала, а иногда U-Boot стартовал. Причина этой нестабильности не установлена; возможны питание или аппаратные проблемы. Это отдельное наблюдение, которое нельзя путать с диагностированным ниже несовпадением UBI. В случаях нестабильной загрузки лучше сначала проверить блок питания и соединение UART.
Шаг 2. Подключение UART и получение доступа к U-Boot
После подключения UART и остановки автозагрузки стал доступен U-Boot 1.1.4. Через него были проверены переменные окружения:
printenv
Ключевые значения нашего экземпляра:
bootcmd=run altnandboot
boot_part=2
bootdelay=0
auto_recovery=yes
nandboot=nand read.e 0x2000000 0x200000 0x300000; setenv bootargs $(console) $(mtdparts) $(fs_bootargs_root) serial_number=$(sn) uuid=$(uuid) hw_version=$(hw) device_mac=$(mac) factory_date=$(date) wps_pin=$(wps); bootm 0x2000000;
altnandboot=nand read.e 0x2000000 0x1c00000 0x300000; setenv bootargs $(console) $(mtdparts) $(alt_fs_bootargs_root) serial_number=$(sn) uuid=$(uuid) hw_version=$(hw) device_mac=$(mac) factory_date=$(date) wps_pin=$(wps); bootm 0x2000000;
В данном случае nandboot загружает ядро первого слота с 0x00200000, altnandboot — второго с 0x01C00000. Поэтому U-Boot пытался запускать второй, повреждённый с точки зрения загрузки слот.
Вручную проверили первый слот:
run nandboot
Результат: заводская Linksys загрузилась. Значит, U-Boot, основные аппаратные компоненты и первая копия прошивки были живы. Это стало страховкой на протяжении восстановления.
Особенность сетевых настроек заводской прошивки
После входа в штатную Linux-систему обнаружилось, что WAN получает адрес по DHCP (в нашем случае 192.168.1.148), а LAN-мост br0 имел адрес 10.199.36.77/24; привычный DHCP на LAN не заработал. Это затрудняло доступ по сети, но не означало, что роутер аппаратно неисправен. Для дальнейших операций использовали UART и отдельный Ethernet-путь до ПК.
Шаг 3. Чтение NAND и поиск настоящей причины
Через U-Boot и Linux были проверены размеры разделов, плохие блоки и вывод старта ядра.
На данном устройстве обнаружены плохие блоки NAND:
Bad eraseblock 239 at 0x000001de0000
Bad eraseblock 692 at 0x000005680000
Bad eraseblock 985 at 0x000007b20000
Особенно интересен первый из них: 0x01DE0000 расположен внутри области ядра второго слота.
При этом U-Boot успешно считывал ядро командой:
nand read.e 0x2000000 0x1c00000 0x300000
Команда nand read.e пропускает отмеченные плохие блоки. Из-за этого физическое и логическое размещение данных во втором слоте требует особого внимания.
В логах OpenWrt 23.05.6 ядро успешно проходило проверку контрольной суммы и стартовало, но затем не находило UBI:
UBI error: no valid UBI magic found inside mtd6
VFS: Cannot open root device
Kernel panic
То есть сбой происходил не при загрузке ядра, а при подключении корневой файловой системы.
Проверка смещений UBI
Далее в заводской Linux прочитали первые байты последовательных блоков второго слота (размер блока стирания NAND — 0x20000, или 128 КиБ). Получилась следующая картина:
| Физический адрес | Содержимое начала блока |
|---|---|
0x01EE0000 | 00 00 ... |
0x01F00000 | 00 00 ... |
0x01F20000 | 55 42 49 23 = UBI# |
0x01F40000 | UBI# |
0x01F60000 | UBI# |
Но OpenWrt ожидал начало раздела rootfs2 по адресу 0x01F00000, то есть ровно на один eraseblock раньше первой обнаруженной сигнатуры UBI#.
Рабочая гипотеза: штатная прошивка заводского интерфейса разместила UBI с дополнительным смещением в 128 КиБ, вероятно из-за bad block в области ядра второго слота. Это объясняет несовпадение с разметкой OpenWrt. Мы не исследовали реализацию штатного прошивальщика до уровня исходного кода, поэтому конкретный внутренний механизм смещения остаётся предположением. Практическая часть подтверждена: после записи UBI напрямую в правильный MTD-раздел устройство заработало.
Шаг 4. Почему выбрали загрузку OpenWrt из RAM
Вместо ручного изменения дерева устройств или переписывания U-Boot решили использовать официальный OpenWrt initramfs. Он запускается целиком в оперативной памяти, не требует рабочей корневой системы на NAND и содержит утилиты ubiformat, ubiattach, ubinfo.
Так удалось записать корневую файловую систему точно в MTD-раздел rootfs2, не затронув первый слот Linksys.
Нужны два официальных файла OpenWrt 23.05.6:
openwrt-23.05.6-kirkwood-generic-linksys_ea4500-initramfs-uImage— для загрузки в RAM по TFTP;openwrt-23.05.6-kirkwood-generic-linksys_ea4500-squashfs-factory.bin— для извлечения UBI-части.
Они доступны в архиве релиза OpenWrt 23.05.6 для kirkwood/generic.
Проверенные официальные SHA256:
| Файл | SHA256 |
|---|---|
...linksys_ea4500-squashfs-factory.bin | fc368d0f70d4f23b5f84af0a54fab90253dd35f9c20b3fe20d28caa30920191a |
...linksys_ea4500-initramfs-uImage | 7ae7bc6b9f057c614b9011ccd82803fb10ae01deaa16e2ba89c486dcb539b0c2 |
В приложенном архиве есть scripts/prepare_firmware.py, который скачивает файлы, сверяет SHA256 и извлекает rootfs.ubi. Сами бинарные образы в архив не включены, поскольку во время его подготовки официальный сервер не был доступен из среды создания файлов.
Шаг 5. Запуск initramfs по TFTP
На компьютере Windows настроили Ethernet-интерфейс со статическим IPv4 192.168.1.2/24 и запустили TFTP-сервер. Конкретная программа TFTP не принципиальна: достаточно, чтобы сервер выдавал initramfs-uImage из своего каталога. HTTP-сервер Python, который понадобится ниже, не заменяет TFTP-сервер для команды tftpboot.
На приглашении U-Boot:
setenv ipaddr 192.168.1.1
setenv serverip 192.168.1.2
ping 192.168.1.2
tftpboot 0x2000000 openwrt-23.05.6-kirkwood-generic-linksys_ea4500-initramfs-uImage
iminfo 0x2000000
setenv bootargs 'console=ttyS0,115200 root=/dev/ram rw'
bootm 0x2000000
iminfo нужен, чтобы убедиться, что образ загрузился и его заголовок/контрольная сумма корректны. setenv здесь меняет только значения в оперативном окружении U-Boot; команду saveenv мы не выполняли.
Результат: OpenWrt 23.05.6 успешно запустился из RAM. На консоли:
DISTRIB_ID='OpenWrt'
DISTRIB_RELEASE='23.05.6'
DISTRIB_TARGET='kirkwood/generic'
DISTRIB_ARCH='arm_xscale'
Шаг 6. Сверка карты памяти в RAM OpenWrt
Это самый важный шаг перед любой записью NAND. Мы выполнили:
cat /proc/mtd
dmesg | grep -E 'Creating|kernel2|ubi|0x000001f00000|Bad eraseblock'
command -v ubiformat
command -v ubiattach
command -v ubinfo
mount | grep ubi
free
Фактическая карта памяти:
dev: size erasesize name
mtd0: 00080000 00020000 "u-boot"
mtd1: 00020000 00020000 "u_env"
mtd2: 00020000 00020000 "s_env"
mtd3: 01a00000 00020000 "kernel1"
mtd4: 01700000 00020000 "rootfs1"
mtd5: 01a00000 00020000 "kernel2"
mtd6: 01700000 00020000 "rootfs2"
mtd7: 04a00000 00020000 "syscfg"
mtd8: 00140000 00020000 "unused"
Ядро дополнительно подтвердило:
0x000001c00000-0x000003600000 : "kernel2"
0x000001f00000-0x000003600000 : "rootfs2"
Здесь kernel2 (/dev/mtd5) — крупная перекрывающая область второго слота, а rootfs2 (/dev/mtd6) — его файловая система размером 23 МиБ, начинающаяся с 0x01F00000. Для восстановления нужно писать только в /dev/mtd6, а не в /dev/mtd5, /dev/mtd3, /dev/mtd4 или U-Boot.
Инструменты ubiformat, ubiattach, ubinfo, wget оказались уже доступны в initramfs. Это позволило обойтись без установки дополнительных пакетов.
Шаг 7. Извлечение правильного UBI-образа
Для этого конкретного factory-образа OpenWrt 23.05.6 первые 0x300000 байт (3 МиБ) отведены под ядро; далее начинается UBI-образ. Значит, достаточно удалить первые 3 МиБ из файла factory.bin. Не используйте это смещение для OpenWrt 24.10 и новее без дополнительной проверки: там изменена область ядра и загрузочные параметры.
В комплекте есть проверяющий скрипт:
py -3 scripts\prepare_firmware.py
Он проверяет хеши двух исходных файлов и требует, чтобы:
- в смещении
0x300000находилась сигнатураUBI#; - извлечённый файл имел размер 4 456 448 байт (34 блока NAND);
- размер был кратен
0x20000.
Выходной файл: firmware/rootfs.ubi.
Для воспроизводимости минимальный вариант операции выглядит так:
from pathlib import Path
factory = Path('openwrt-23.05.6-kirkwood-generic-linksys_ea4500-squashfs-factory.bin').read_bytes()
ubi = factory[0x300000:]
assert len(ubi) == 4456448
assert ubi[:4] == b'UBI#'
assert len(ubi) % 0x20000 == 0
Path('rootfs.ubi').write_bytes(ubi)
В отличие от минимального примера, приложенный скрипт сначала сверяет официальный SHA256 образа, что необходимо перед прошивкой.
Шаг 8. Передача rootfs.ubi на роутер
На Windows из папки с файлом запустили простой HTTP-сервер:
cd firmware
py -3 -m http.server 8000 --bind 192.168.1.2
В комплекте для этого есть scripts/start_http_server.cmd.
Из OpenWrt, загруженного в RAM:
cd /tmp
wget http://192.168.1.2:8000/rootfs.ubi
ls -l /tmp/rootfs.ubi
sha256sum /tmp/rootfs.ubi
В нашем случае:
rootfs.ubi 4456448 bytes
Проверили также первые четыре байта. В BusyBox не оказалось команды od, поэтому использовали более простой способ:
dd if=/tmp/rootfs.ubi bs=4 count=1 2>/dev/null
echo
Ожидается:
UBI#
В комплекте есть scripts/check_ram_openwrt.sh и scripts/check_rootfs_ubi.sh — дополнительные проверки карты MTD, инструментов, сигнатуры и размера. Их можно отправить на роутер тем же HTTP-сервером или скопировать вручную.
Перед записью обязательно убедитесь, что SHA256 rootfs.ubi совпадает на ПК и роутере.
Шаг 9. Восстановление раздела rootfs2
Опасная команда. Далее происходит перезапись NAND. Она приведена как запись фактически выполненной операции, а не как безусловная рекомендация для любого устройства. Перед запуском убедитесь, что вы работаете из initramfs, что
/dev/mtd6у вас действительноrootfs2размером0x01700000, что файлrootfs.ubiпроверен и что питание стабильно. Если разметка другая — остановитесь.
Мы выполнили:
ubiformat /dev/mtd6 -f /tmp/rootfs.ubi -y
Основные строки фактического вывода:
ubiformat: mtd6 (nand), size 24117248 bytes (23.0 MiB), 184 eraseblocks of 131072 bytes (128.0 KiB), min. I/O size 2048 bytes
libscan: scanning eraseblock 183 -- 100 % complete
ubiformat: 35 eraseblocks have valid erase counter, mean value is 0
ubiformat: 148 eraseblocks are supposedly empty
ubiformat: warning!: 1 of 184 eraseblocks contain non-UBI data
ubiformat: warning!: only 35 of 184 eraseblocks have valid erase counter
ubiformat: erase counter 0 will be used for all eraseblocks
ubiformat: flashing eraseblock 33 -- 100 % complete
ubiformat: formatting eraseblock 183 -- 100 % complete
Предупреждения о старом содержимом и erase counters в данном случае не привели к ошибке. Отформатировался весь mtd6, а UBI был записан с начала нужной области.
Проверка через ubiattach
После успешного ubiformat:
ubiattach -m 6
ubinfo -a
Ключевые строки из результата:
ubi0: attaching mtd6
UBI: EOF marker found, PEBs from 29 will be erased
ubi0: volume 1 ("rootfs_data") re-sized from 9 to 133 LEBs
ubi0: attached mtd6 (name "rootfs2", size 23 MiB)
ubi0: PEB size: 131072 bytes (128 KiB), LEB size: 129024 bytes
ubi0: min./max. I/O unit sizes: 2048/2048, sub-page size 512
ubi0: VID header offset: 512 (aligned 512), data offset: 2048
ubi0: good PEBs: 184, bad PEBs: 0, corrupted PEBs: 0
ubi0: user volume: 2, internal volumes: 1
И ubinfo -a:
| UBI-том | Размер | Состояние |
|---|---|---|
rootfs | 27 LEB / 3 483 648 байт (~3,3 МиБ) | OK |
rootfs_data | 133 LEB / 17 160 192 байта (~16,3 МиБ) | OK |
Это подтвердило правильную структуру UBI. Автоматическое увеличение rootfs_data нормально. Ноль доступных LEB также был ожидаем: свободное пространство распределено между томами и резервом на bad blocks.
Замечание:
ubinfoподтверждает корректность UBI-метаданных и состояние томов, но само по себе не гарантирует, что все файлы внутриrootfsчитаются. Окончательную проверку даёт загрузка OpenWrt с NAND.
Шаг 10. Перезагрузка — и успешный запуск!
После проверки файловой системы отключили UBI из RAM-системы (при наличии ubidetach) и проверили обычную загрузку второго слота:
ubidetach -m 6
Затем роутер был перезапущен. U-Boot использовал ранее существовавший altnandboot; заводской слот мы не трогали.
На этот раз OpenWrt загрузился полностью:
BusyBox v1.36.1 (2025-08-14 18:27:40 UTC) built-in shell (ash)
_______ ________ __
| |.-----.-----.-----.| | | |.----.| |_
| - || _ | -__| || | | || _|| _|
|_______|| __|_____|__|__||________||__| |____|
|__| W I R E L E S S F R E E D O M
-----------------------------------------------------
OpenWrt 23.05.6, r24232-539228933c
-----------------------------------------------------
=== WARNING! =====================================
There is no root password defined on this device!
Use the "passwd" command to set up a new password
in order to prevent unauthorized SSH logins.
--------------------------------------------------
root@OpenWrt:/#
Это уже не initramfs, а установленный OpenWrt, запустившийся из NAND.
Первым действием после восстановления стоит установить пароль:
passwd
Затем проверить постоянный overlay, файловые системы и сеть:
cat /etc/openwrt_release
mount | grep overlay
df -h
ip addr
Почему всё получилось: краткая схема
Заводская Linksys (слот 1) ──────────────┐
│ осталась рабочей
Web-прошивка factory.bin │
│ │
▼ │
Слот 2: kernel2 + rootfs2 │
│ │
├─ ядро грузится │
└─ UBI не найдено │
│ │
bad block 0x01DE0000 │
rootfs2 ожидается 0x01F00000 │
UBI# найдено с 0x01F20000 │
│ │
▼ │
UART → U-Boot │
│ │
TFTP → initramfs (RAM) │
│ │
проверка /proc/mtd │
│ │
извлечение rootfs.ubi │
│ │
ubiformat /dev/mtd6 -f ... │
│ │
ubiattach + ubinfo │
│ │
▼ │
OpenWrt 23.05.6 загружается ◄──────┘
Что важно запомнить
- Не считать отсутствие загрузки ядра равнозначным повреждению ядра. Здесь U-Boot загружал ядро успешно, а отказ происходил на стадии UBI.
- Читать реальные адреса и состояние NAND. Bad block внутри области ядра мог повлиять на разметку при записи прошивки. Совпадение предполагаемой и реальной адресации нужно проверять, а не угадывать.
- Использовать initramfs как спасательный инструмент. Это позволило работать с MTD напрямую, не перезаписывая рабочий первый слот.
- Не путать
mtd5иmtd6. В нашей разметкеmtd5охватывает второй слот, аmtd6— нужную для UBI область его rootfs. - Проверять SHA256 и сигнатуру UBI. Ошибочный образ при прямой записи NAND значительно опаснее штатной установки через GUI.
- Не менять переменные U-Boot без нужды. Для восстановления OpenWrt 23.05.6 не потребовалось выполнять
saveenvили заменять загрузчик. - Не переносить слепо инструкции между версиями OpenWrt. Для OpenWrt 24.10+ на EA4500 в документации описано увеличение размера чтения ядра с
0x300000до0x400000; этот отдельный этап в нашем случае не выполнялся.
Файлы и скрипты, приложенные к статье
ea4500_openwrt_recovery/
├── EA4500_OpenWrt_Recovery.md ← эта статья
├── README.md ← состав комплекта и быстрый старт
├── firmware/
│ └── README_DOWNLOAD.md ← официальные ссылки и SHA256
├── scripts/
│ ├── prepare_firmware.py ← загрузка, проверка SHA256 и извлечение UBI
│ ├── start_http_server.cmd ← HTTP-сервер для передачи UBI
│ ├── check_ram_openwrt.sh ← безопасная проверка MTD из initramfs
│ └── check_rootfs_ubi.sh ← безопасная проверка rootfs.ubi
└── logs/
└── recovery_key_outputs.txt ← сохранённые ключевые логи диагностики
Бинарные файлы прошивки и сгенерированный rootfs.ubi появляются в firmware/ после запуска prepare_firmware.py. В статье намеренно нет универсального автоматического скрипта ubiformat: опасную операцию нужно выполнять только вручную после сверки карты MTD.
Полезные ссылки
- Официальный каталог OpenWrt 23.05.6 / kirkwood/generic
- OpenWrt Wiki: Linksys EA4500 v1/v2, E4200 v2
- OpenWrt 23.05.6: примечания к выпуску и статус EOL