talk_puzzle-dts_hod2024/slides/index.md
2024-12-01 21:45:25 +01:00

15 KiB

Racconto di un ciappino su un router

Puzzle DTS

Come aggiungere il supporto per openwrt ad un dispositivo simile ad uno già supportato?


Premesse

Perché questo talk:

--

Un paio di considerazioni sul perché potrebbe interessarvi questo talk se anche in genere non vi interessa molto l'argomento networking

--

1. L'interesse per i router potrebbe non essere solo relativo al networking

Iniziano a vedersi in giro più spesso router che a livello di prestazioni assomigliano quasi a dei raspberry

Iniziano ad essere dei cosini che qualche sito statico te lo tengono, o varie, in genere li tieni già accesi 24/7/52 e consumano poco (in genere tra i 6 e i 24W)

Per dare un'idea cito il caso di openwrt, che dalla versione 19 (2019) ha smesso di supportare router con meno di 64MB di RAM, e in seguito ha iniziato a consigliare un minimo di 128MB

--

2. Dal momento che parliamo di dispositivi embedded

Cito l'HoD dell'anno scorso che c'è stato un talk interessante sulla storia dell'oggetto furbofono

Nella discussione mi pare si diceva come tra le alternative belle che ci sono una cosa che manca ancora è un framework comune di applicazioni, per cui vai ad apprezzare magari di più un lineageos o cyanogen che comunque è un android, piuttosto che un postmarketos che non ha le app android.

---

Due parole su OpenWrt

openwrt

--

Wiki

openwrt-project

Forum

openwrt-forum

Gitweb

openwrt-gitweb

Github

openwrt-github

--

Downloads Server

openwrt-downloads

--

Elementi che si incontrano in openwrt:

giusto per citarne alcuni

  • UCI/LUCI: Unified Configuration Interface - tutto in '/etc/config/'
  • il thema di default di luci può non piacere ma si può cambiare
  • varie: uci-defaults, rc; iptables-nftables, iw, ubus

--

  • LUCI: dopo una modifica cliccando su 'unsaved changes' vedi a che comandi UCI corrispondono le modifiche. openwrt

--

Elementi in openwrt:

  • memorie flash comuni:
    • NOR più piccole, fino a 128MB:
      • si spaccano dopo 100K-1G cancellazioni
    • NAND, più economiche, più grandi fino al GB e oltre:
      • MLC si spaccano dopo 1K-10K cancellazioni, pure il processo di lettura potrebbe romperle
      • SLC si spaccano dopo 100K-1G cancellazioni

--

  • alcuni router le hanno entrambe e solitamente nella NOR ci vanno bootloader e partizioni con dati che non devono essere persi (*pubblicità openwrt ONE)
  • se il router ha il buco USB esiste ext-root

Altri talks e informazioni utili:

Lista di riferimenti completa a fine slide

  • La wiki di openwrt
  • il forum di openwrt è pieno di informazioni e di persone che hanno documentato le prove che hanno fatto
  • Device Tree for Dummies! - Thomas Petazzoni, Free Electrons (video)
  • hacking-gemtek repo su github, lo stesso autore ha fatto una serie di video, utili perché è un po' come guardarsi il disassembly prima di aprire il router

Racconto

Prima di cominciare

Mi chiedo almeno queste cose:

  • se avrebbe senso e per quanto
  • fattibilità
  • livello di sbatta

--

1. se avrebbe senso e per quanto

  • è supportato il System on Chip? andrebbe il WiFi?
    • cerco il documento FCCID
    • cerco su uno dei wikidevi
  • quanto va il processore? ~800MHz
  • quanta ram? 128MB
  • quanta flash c'ha? 128MB
  • se faccio il porting per quanto tempo potrebbe rimanere supportato in openwrt?

--

uart-aghi

--

Se posso evito di saldare la uart:
C'è l'imbiancatura di stagno?

  • si -> aghi
  • no -> pins pigiati con lo scotch

--

2 fattibilità

  • accedo alla uart?
  • accedo al bootloader (uboot)?
  • riesco a caricargli sopra le immagini initramfs** e fare dei test?

** https://www.kernel.org/doc/html/latest/filesystems/ramfs-rootfs-initramfs.html

Quest ultimo detto in altre parole:
Per installare seguiamo in genere questo processo

dal mio PC -> alla sua RAM -> alla sua FLASH

Per testare facciamo solo i primi due

dal mio PC -> alla sua RAM

--

3 livello di sbatta

  • ho accesso root al dispositivo?
  • riesco a leggere i log del boot del firmware originale?
  • riesco a backuppare tutto prima di testare cose?

Backuppo tutto

-- https://openwrt.org/docs/techref/flash.layout

NOR openwrt-flash-layout-nor

-- https://openwrt.org/docs/techref/flash.layout

NAND openwrt-flash-layout-nand

--

In questo caso è possibile e comodo usare il webserver da firmware originale

  • gli MTDs
cat /proc/mtd
dd if=/dev/mtd7 of=/tmp/eeprom_mtd7.bin
  • i dati di calibrazione delle radio:
    copio anche quelli generici di cui trovo una copia nel dispositivo

--

  • se non fosse stato possibile copiare gli mtd con il firmware originale lo si sarebbe potuto fare da openwrt, caricando una prima initramfs che faccia almeno il boot e parli ad es. via ethernet
  • in questo caso (guida hacking-gemtek) backup completo della flash pagina per pagina in ascii (11 ore), ricomposizione e poi estrazione del filesystem
    • binwalk, firmware-mod-kit

inizio a definire il dispositivo

--

documenti utili

  • datasheet mediatek mt7621
  • programming guide mt7621
  • copia del kernel o documentazione online
  • un IDE per la ricerca nel clone di openwrt nelle cartelle (elenco le più ricercate in questo caso)
    • target/linux
    • target/linux/ramips/
    • target/linux/ramips/image/
    • target/linux/ramips/dts/
    • target/linux/ramips/mt7621/

--

  • mi collego via seriale e copio i log del boot se non li trovo in rete
  • cerco se un wikidevi ha già informazioni sull hardware se no fotografo questo
  • guardo come sono definiti altri dispositivi simili, quali pacchetti per il wireless, o altri driver particolari

--

Esempio di definizione in target/linux/ramips/image/mt7621.mk


define Device/gemtek_wvrtm-1xxacn
  $(Device/nand)
  $(Device/uimage-lzma-loader)
  IMAGE_SIZE := 122368k
  DEVICE_VENDOR := Gemtek
  DEVICE_PACKAGES := kmod-gpio-nxp-74hc164 kmod-spi-gpio \
  kmod-usb3 -uboot-envtools 
endef

define Device/gemtek_wvrtm-127acn
  $(Device/gemtek_wvrtm-1xxacn)
  DEVICE_MODEL := WVRTM-127ACN
  DEVICE_PACKAGES += kmod-mt7603 kmod-mt76x2
endef
TARGET_DEVICES += gemtek_wvrtm-127acn

define Device/gemtek_wvrtm-130acn
  $(Device/gemtek_wvrtm-1xxacn)
  DEVICE_MODEL := WVRTM-130ACN
  DEVICE_PACKAGES += kmod-mt7615-firmware
endef
TARGET_DEVICES += gemtek_wvrtm-130acn


--

Definizione del device di default in target/linux/ramips/image/Makefile

define Device/Default
  PROFILES = Default
  BLOCKSIZE := 64k
  KERNEL := $(KERNEL_DTB) | uImage lzma
  KERNEL_LOADADDR := $(loadaddr-y)
  LZMA_TEXT_START := 0x81800000
  SOC := $(DEFAULT_SOC)
  DEVICE_DTS_DIR := ../dts
  DEVICE_DTS = $$(SOC)_$(1)
  NETGEAR_ENC_MODEL :=
  NETGEAR_ENC_REGION :=
  NETGEAR_ENC_HW_ID_LIST :=
  NETGEAR_ENC_MODEL_LIST :=
  IMAGES := sysupgrade.bin
  COMPILE :=
  sysupgrade_bin := append-kernel | append-rootfs | pad-rootfs
  IMAGE/sysupgrade.bin := append-kernel | append-rootfs | pad-rootfs | check-size | append-metadata
endef

--

  • negli MTD backuppati, mi cerco i macaddress, confrontando l'etichetta sul dispositivo
  • faccio una prima definizione minimale in cui imposto almeno
  • le partizioni della eeprom e l'image_size
  • i driver necessari per la radio
  • possibilmente i macaddress e la calibrazione delle radio
  • uno schema per le porte ethernet o lascio il default

Device Tree

  • .dtb - File name suffix for compiled devicetree.
  • .dts - File name suffix for devicetree source.
  • .dtsi - File name suffix for devicetree source to be included by a .dts or .dtsi file.

--

Dal Device/Default vedevamo

  KERNEL := $(KERNEL_DTB) | uImage lzma

--

device tree

Una struttura ad albero, organizzata per nodi, che fornisce al kernel una descrzione dell'hardware

Realizzata con un 'linguaggio di template' che permette di inclusioni di file o di parziali.
È possibile definire ancore 'phandle' e modificare o ampliare i nodi tramite queste.

--

device tree

i nodi sono caratterizzati da delle 'compatible' strings

ognuna di queste servirà da riferimento per l'esecuzione di un modulo del kernel se questo è installato, che andrà a leggere e utilizzare le informazioni contenute nel nodo

--

device tree

Questa è la parte del processo che più di tutte somiglia ad un puzzle

Perché confronteremo ogni riga con dispositivi simili

Usando l'ide, gitweb e github per trovare informazioni e discussioni sui vari nodi e le loro proprietà

--

Device Tree: Esempi

https://github.com/openwrt/openwrt/pull/16074#issuecomment-2272124140

Code like: ``` &state_default { gpio { groups = "i2c", "uartf", "ephy", "rgmii2"; function = "gpio"; }; }; ``` define which outputs are to be switched to GPIO type outputs. This is necessary if you control something with these outputs, e.g. LEDs, buttons, other chips etc.

setup di buildroot

openwrt-menuconfig

--

setup di buildroot

immagine

con initramfs

CONFIG_TARGET_ROOTFS_INITRAMFS=y

pacchetti

mi aggiungo alcuni pacchetti di utilities di default

lspci, diffutils, libgpiod (o gpioctl-sysfs)

CONFIG_PACKAGE_libgpiod=y
CONFIG_PACKAGE_gpiod-tools=y
CONFIG_PACKAGE_diffutils=y
CONFIG_PACKAGE_pciutils=y

--

setup di buildroot

Se voglio modificare delle configurazioni senza stare ad aprire il menuconfig

posso fare così

echo '# CONFIG_PACKAGE_disabilitato is not set' >> .config
echo '# CONFIG_PACKAGE_abilitato=y' >> .config

e poi applicare con

make defconfig

--

setup di buildroot

files

Creo la cartella /files e gli scripts sulla reference di openwrt per le gpio e i led o altri script per esempio per spegnere e riaccendere le radio, es:

uci set wireless.radio0.disabled=0; wifi

--

ribuildare

se modifico solo il dts rebuildo con

make -j4 target/linux/install

se ho modificato anche altri files

make -j4

se ho modificato altro, tipo il kernel

make clean

Primi test

caricata l'immagine come prima cosa guardo i log di boot e mi salvo un dmesg

--

ethernet?

per prima cosa controllo che vadano le porte ethernet (iproute, ethtool), che siano tutte e che macaddress c'hanno associate alle interfacce

Il router è gigabit ma il mio pc ha una porta 100Mbit/s Trovo un altro ciaffo con le porte gigabit per vedere che vada anche quello

--

radio?

Guardo il driver che dovrebbe averci questa radio e aggiungo il nodo al dts e al makefile

Negli MTD trovo la calibrazione unica fatta su questo specifico dispositivo

Cerco dove è collocata e guardando anche altri device già mappati cerco di capire se ha una lunghezza standard

--

radio?

controllo che vadano le radio (iw, iwinfo) e anche qui i macaddress

nel caso di qualche errore nel dts dovrei notarlo dai log di boot

nel caso in cui non siano giusti i dati di calibrazione od il macaddress dovrei notare delle disfunzioni


Cosa rimarrebbe da fare...


1- provare ad individuare la jtag

Dato che non sembra essere usata come gpio potrebbe essere disponibile Senza la jtag non mi arrischierei a cambiare bootloader

--

Cosa rimarrebbe da fare


2- migliorare la gestione della nand

Probabilmente si riesce a utilizzare UBI almeno anche per il kernel: KERNEL_IN_UBI
E l'immagine di tipo uImage.FIT per kernel e device-tree-blob


cfr: altro caso di uboot troppo vecchio
[Q] partition setup: UBI, mtd-concat, U-Boot, FIT #9550 https://github.com/openwrt/openwrt/issues/9550

--

Cosa rimarrebbe da fare...


3- mettergli sopra un bootloader U-Boot aggiornato

Che supporti del tutto immagini di tipo FIT (Flattened Image Tree).
In poche parole una immagine con un header all'inizio che descrive a uboot quali sono i volumi da usare all'interno dell'immagine

E quindi si riesca ad avere un volume per ogni parte della flash eccetto il bootloader: KERNEL_IN_UBI, UBOOTENV_IN_UBI (partizioni di environment di uboot), e il resto (rootfs) Il che sarebbe nell'insieme una gestione il più possibile cauta di una memoria NAND (cfr riferimenti 'Best-practice for NAND-based firmware using UBI') --

Cosa rimarrebbe da fare...


4- varie
  • un led ballerino
  • usb regulator che non fa il fast-charge (vabbé neanche con firmware OEM lo faceva ma durante il boot lo fa')

--

Cosa rimarrebbe da fare...


5- generare una factory

trovare il firmware, o innescare il download dell'update dall 'ACS e sniffarlo, e capire come generare una factory


Altri Esempi

ubootmenu e caricamento firmware originale

Please choose the operation: 
   1: Load system code to SDRAM via TFTP. 
   2: Load system code then write to Flash via TFTP. 
   3: Boot system code via Flash (default).
   4: Entr boot command line interface.
   9: Load Boot Loader code then write to Flash via TFTP. 

Check image2 validation:
Image Header Magic Number --> OK
Image Header Checksum --> OK
Image Data Checksum --> OK
   
3: System Boot system code via Flash.
## Booting image at 81000000 ...
   Image Name:   =01.01.02.163
   Image Type:   MIPS Linux Multi-File Image (lzma compressed)
   Data Size:    17174476 Bytes = 16.4 MB
   Load Address: 80001000
   Entry Point:  8000f540
   Contents:
   Image 0:  1966004 Bytes =  1.9 MB
   Image 1: 15208448 Bytes = 14.5 MB
   Verifying Checksum ... OK
   Uncompressing Multi-File Image ... OK
## Transferring control to Linux (at address 8000f540) ...
## Giving linux memsize in MB, 128

Starting kernel ...


LINUX started...

--

altri esempi

Caricamento del kernel via tftp dopo aver interrotto il bootloader

MT7621 # tftpboot 81000000 test.bin; bootm

Oppure carica dalla memoria flash

MT7621 # nand read 800000 2000000 81000000; bootm

Riferimenti

- OpenWrt Flash Layout https://openwrt.org/docs/techref/flash.layout

--

Riferimenti

- gpio, leds, buttons https://openwrt.org/docs/techref/hardware/port.gpio - buttons https://openwrt.org/docs/guide-user/hardware/hardware.button