# Відновлення Edimax OAP1300 через UART + TFTP

Колега приніс мертву точку доступу Edimax OAP1300. Живлення є, на serial-консолі видно U-Boot — і далі нічого. Вона вічно крутилася в TFTP-циклі відновлення. Ось як я оживив її, скопіювавши розділ прошивки з ідентичної робочої точки.

**Залізо:** Edimax OAP1300 — Qualcomm IPQ4018, 256 МБ RAM, Macronix **MX25L25635E 32 МіБ SPI-NOR**, U-Boot 2012.07 ("ELX version: 1.0.0").

* * *

## 1\. Що насправді було не так

Сам U-Boot був цілий. Завантажувачі QCA (SBL1, MIBIB, QSEE) — цілі. Калібрування радіо — ціле. Не стартувала тільки ОС.

На розділі прошивки за адресою `0x180000` лежав **файл оновлення з веб-інтерфейсу Edimax** (`OAP1300_v2.4.2.5.bin`), записаний у флеш «як є». А цей файл — це:

```plaintext
[ заголовок Edimax з рядками версій ][ AES-зашифрований payload ]
```

Ентропія payload — 7.99 біт/байт, тобто він зашифрований. Розшифрувати й покласти його у флеш вміє тільки апдейтер самої прошивки. А `bootipq` в U-Boot чекає на `0x180000` **готовий FIT-образ** (магія `d0 0d fe ed`), бачить `00 00 00 00` — і мовчки виходить.

> **Не повторюйте цього.** Ніколи не робіть `sf write` файлу `.bin` з сайту Edimax напряму на `0x180000`. Він зашифрований. Образ, який ви пишете туди, має починатися з `d0 0d fe ed`.

* * *

## 2\. Що потрібно

**Залізо**

*   Друга, **робоча OAP1300** як донор (ідентичне залізо)
    
*   USB–UART адаптер (CP2102) на serial-хедер — `115200 8N1`
    
*   **Тупий / некерований PoE-свіч** — *не* керований офісний свіч
    
*   Mac або Linux-машина з дротовим Ethernet-портом
    

Тупий свіч — принципово. Керований офісний свіч через STP ізолював порт точки, і **кожна TFTP-передача таймаутила** — це блокувало відновлення тижнями. Некерований PoE-свіч, у якому тільки точка й комп'ютер, без аплінку, просто форвардить кадри й ні в що не втручається.

**Файли**

Роботу робить один файл: `work_hlos_rootfs.bin` — це те, що реально лежить у флеші донора в області HLOS + rootfs (`0x180000`–`0x1000000`, `0xe80000` байт): готовий FIT-ядро (*ARM OpenWrt Linux-3.14.43*), за ним squashfs-корінь. Жодних даних, унікальних для конкретного пристрою, він не містить.

* * *

## 3\. Підключення

```plaintext
 OAP1300 ──PoE+дані── [ тупий PoE-свіч ] ──дані── Mac (en18)
 (мертва точка)          без аплінку              192.168.102.90/25

 serial-хедер OAP1300 ──── CP2102 ──── Mac USB   (115200 8N1)
```

У свічі — тільки точка й Mac. Serial — це окремий шлях.

![Адаптер CP2102 USB-UART, підключений до serial-хедера TX / GND / RX на платі OAP1300](https://cdn.hashnode.com/uploads/covers/643661078c876776a479a254/e04fa8ec-85c2-4f00-8340-5501e568889f.jpg align="center")

*Три перемички йдуть на пади* `TX` */* `GND` */* `RX` *поряд з U13 на платі.*

* * *

## 4\. Підготовка хоста (macOS)

```bash
# en18 = дротовий порт Mac
sudo ifconfig en18 inet 192.168.102.90 netmask 255.255.255.128 up
sudo arp -s 192.168.102.9 00:03:7f:ba:db:ad
sudo python3 tftp_recv.py
# TFTP server listening on 0.0.0.0:69  dest=/private/tftpboot
# waiting for tftpput from U-Boot...
```

Лишіть це працювати. Покладіть `work_hlos_rootfs.bin` у `/private/tftpboot/`.

> Вбудований `tftpd` у macOS часто не відповідає. `tftp_recv.py` — це маленька заміна (~150 рядків), яка обробляє обидва напрямки й опції `blksize`, які узгоджує U-Boot.

* * *

## 5\. Відновлення мертвої точки

### Крок 1 — зловити U-Boot prompt

Подайте живлення на точку, бомблячи `Ctrl-C` на serial-консолі.

```plaintext
U-Boot 2012.07  ·  ELX version: 1.0.0
Hit any key to stop autoboot:  2  1  0
(IPQ40xx) #
```

### Крок 2 — направити U-Boot на хост

```plaintext
setenv ethaddr 00:03:7f:ba:db:ad
setenv ipaddr 192.168.102.9
setenv serverip 192.168.102.90
sf probe 0
# SF: Detected MX25L25635E with page size 4 KiB, total 32 MiB
ping 192.168.102.90
# host 192.168.102.90 is alive
```

`ethaddr` виставлено в SROM MAC, щоб запис ARL внутрішнього свіча й статичний ARP на хості збігалися.

**Якщо ping не проходить — зупиніться тут.** Полагодьте лінк, перш ніж чіпати флеш.

### Крок 3 — завантажити образ у RAM

```plaintext
tftpboot 0x84000000 work_hlos_rootfs.bin
# ...
# Bytes transferred = 15204352 (e80000 hex)
```

Переконайтеся, що розмір рівно `0xe80000`. Недотягнута передача тут перетворюється на биту прошивку.

### Крок 4 — стерти й записати розділ прошивки

Тільки від `0x180000`. ART на `0x170000`, U-Boot і environment не чіпаємо.

```plaintext
sf erase 0x180000 0xe80000      # ~60 с
sf write 0x84000000 0x180000 0xe80000     # ~60 с
```

### Крок 5 — перевірити зворотним читанням

```plaintext
sf read 0x86000000 0x180000 0xe80000
cmp.b 0x84000000 0x86000000 0xe80000
(IPQ40xx) #      # тиша = ідентично. будь-яке "differ" = переписати.
```

### Крок 6 — перезавантажити й дати відпрацювати `bootipq`

Просто `reset`. **Не** запускайте вручну `bootm 0x84000000#config@4`. Тільки `bootipq` робить правку device-tree, яка каже ядру, що флеш — 32 МіБ; без неї розділ `/factory` (він лежить вище 16 МіБ) не монтується, і точка падає в режим калібрування ("ART").

```plaintext
reset
## Booting kernel from FIT Image at 84000000 ...
   Using 'config@4' configuration
   Verifying Hash Integrity ... crc32+ sha1+ OK
   Uncompressing Kernel Image ... OK
Starting kernel ...
```

### Крок 7 — переконатися, що вона піднялась як AP

```plaintext
Configuring QCA WiFi device[0] ... Wlan is in AP Mode
 DES SSID SET=OAP1300-ECB828_A
CMD[led_ctl 5g off]
cmd>  WAL channel change freq=2427 ... rx_ok=1 tx_ok=1
```

Радіо сканує, VAP піднятий, немає `art mode`, немає I/O-помилок `mtdblock11`. Збирайте пристрій і налаштовуйте через веб-інтерфейс як нову точку.

* * *

## 6\. Карта флешу

З `smeminfo` в U-Boot. Відновлення чіпає один рядок.

| Розділ | Початок | Розмір | Роль |
| --- | --- | --- | --- |
| SBL1 | `0x000000` | `0x040000` | первинний завантажувач QCA |
| MIBIB | `0x040000` | `0x020000` | таблиця розділів |
| QSEE | `0x060000` | `0x060000` | secure world |
| CDT | `0x0c0000` | `0x010000` | конфіг борду |
| DDRPARAMS | `0x0d0000` | `0x010000` | тайминги RAM |
| APPSBLENV | `0x0e0000` | `0x010000` | environment U-Boot |
| APPSBL | `0x0f0000` | `0x080000` | U-Boot 2012.07 |
| ART | `0x170000` | `0x010000` | калібрування радіо — унікальне, **не чіпати** |
| **HLOS + rootfs** | `0x180000` | `0xe80000` | FIT-ядро + squashfs — **пишемо з донора** |
| /factory + config | `0x1b80000` | — | squashfs + JFFS2, верхня частина флешу |

* * *

## 7\. Як зняти образ з донора

Якщо у вас немає `work_hlos_rootfs.bin`, зніміть його з робочої точки в її U-Boot prompt. Тільки читання — на донор нічого не пишеться.

```plaintext
setenv ipaddr 192.168.102.9
setenv serverip 192.168.102.90
sf probe 0
sf read 0x84000000 0x180000 0xe80000
tftpput 0x84000000 0xe80000 work_hlos_rootfs.bin
# Bytes transferred = 15204352 (e80000 hex)
bootipq        # відправити донор назад у продакшн
```

> Передача 15 МБ друкує ~20 с `#` у консоль. Якщо відкрити нову serial-сесію, поки це ще «стікає», ви прочитаєте застарілі байти. Натисніть `Ctrl-C` кілька разів і зачекайте 2–3 с, перш ніж довіряти тому, що читаєте далі.

* * *

## 8\. Глухі кути, для протоколу

*   **Відновлення по UART.** У цьому U-Boot немає `loadb` / `loadx` / `loady`. TFTP — єдиний спосіб залити байти у флеш.
    
*   **OpenWrt EAP1300 initramfs.** Вантажиться, потім плата робить хардовий ресет на ~1.5 с — апаратний watchdog OAP1300 цим образом не «гладиться».
    
*   **Клонування ART чи всіх 32 МіБ.** Не потрібно й не бажано — власне калібрування й MAC мертвої точки були цілі. Битим був тільки розділ FIT.
    
*   **«**`bootipq` **не працює».** Працює. Ранні логи виглядали як збій через проблему з serial-буфером вище; ручний обхід `bootm ...#config@4` потім давав симптом режиму калібрування. Щойно на місці валідний FIT, звичайний через `bootipq` працює.
