-
Crear una imagen personalizada de Debian para el router BPI-R3
En este artículo crearemos desde un ordenador con Debian una imagen personalizada de Debian 13 «Trixie» para el router Banana Pi BPI-R3. La imagen resultante podrá grabarse directamente en una tarjeta microSD e incluirá el sistema de archivos raíz, un kernel Linux compilado por nosotros, los módulos correspondientes, el Device Tree de la placa y toda la cadena de arranque necesaria.
Este procedimiento está pensado específicamente para la Banana Pi BPI-R3 basada en el SoC MediaTek MT7986A. No debemos utilizarlo sin modificaciones en una BPI-R3 Mini, BPI-R4 u otro modelo. El kernel Linux mantiene tanto el Device Tree base de la BPI-R3 como las superposiciones específicas para SD, eMMC, NAND y NOR. En este caso aplicaremos la superposición correspondiente a la tarjeta SD.
En ARM64 no utilizaremos un archivo zImage. Compilaremos el archivo Image sin comprimir, que puede ser arrancado directamente por U-Boot mediante el comando booti.
Entender la cadena de arranque de la BPI-R3
La BPI-R3 no puede arrancar desde una microSD escribiendo simplemente el archivo u-boot.bin en el sector 2. El arranque se realiza mediante varias etapas:
- BootROM: código incluido en el propio SoC MT7986A.
- BL2: inicializa el hardware básico, incluida la memoria DDR4.
- FIP: contiene las siguientes etapas de Trusted Firmware-A y el binario de U-Boot.
- U-Boot: carga el kernel, el initramfs y el Device Tree.
- Linux: monta el sistema de archivos raíz de Debian.
U-Boot incluye una configuración específica denominada mt7986a_bpir3_sd_defconfig para arrancar la BPI-R3 desde SD. Para generar BL2 y FIP utilizaremos la implementación de Trusted Firmware-A mantenida para los SoC MediaTek empleados por OpenWrt.
No escribiremos directamente sobre una tarjeta durante la construcción. Primero generaremos un archivo debian-bpi-r3.img, lo montaremos mediante un dispositivo loop y, cuando esté terminado, lo grabaremos en la microSD. Así evitaremos destruir por error otro disco del ordenador.
Instalar las herramientas necesarias
Actualizamos la información de los repositorios e instalamos el compilador cruzado para ARM64, las dependencias del kernel, U-Boot, Trusted Firmware-A, debootstrap y las herramientas necesarias para crear la imagen:
sudo apt update sudo apt install -y \ bc \ binfmt-support \ bison \ build-essential \ ca-certificates \ crossbuild-essential-arm64 \ debootstrap \ device-tree-compiler \ dosfstools \ e2fsprogs \ flex \ gdisk \ git \ libelf-dev \ libgnutls28-dev \ libncurses-dev \ libssl-dev \ parted \ pkg-config \ python3 \ python3-dev \ python3-jsonschema \ python3-pyelftools \ python3-setuptools \ python3-yaml \ qemu-user-static \ rsync \ swig \ u-boot-tools \ uuid-dev \ xz-utils
El metapaquete crossbuild-essential-arm64 ya instala el compilador y las binutils para AArch64. No necesitamos instalar el compilador arm-linux-gnueabihf, ya que ese compilador está destinado a ARM de 32 bits.
Definimos las rutas y versiones que utilizaremos. Los siguientes bloques deben ejecutarse desde la misma terminal para conservar las variables:
vProyecto="$HOME/debian-bpi-r3" vRootfs="$vProyecto/rootfs" vKernel="$vProyecto/linux" vUBoot="$vProyecto/u-boot" vTfa="$vProyecto/arm-trusted-firmware" vImagen="$vProyecto/debian-bpi-r3.img" vSuiteDebian="trixie" vRamaKernel="linux-6.12.y" vVersionUBoot="v2025.10" mkdir -p "$vProyecto" rm -rf "$vKernel" rm -rf "$vUBoot" rm -rf "$vTfa" rm -f "$vImagen" rm -f "$vImagen.xz" sudo rm -rf "$vRootfs"
Utilizaremos Debian 13 Trixie para el sistema ARM64.
Compilar el kernel Linux
Clonamos la rama estable 6.12 del kernel:
git clone \ --depth 1 \ --branch "$vRamaKernel" \ https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git \ "$vKernel" cd "$vKernel"
Partimos de la configuración genérica de ARM64. Es preferible hacer esto en lugar de desactivar todas las demás familias de SoC desde menuconfig, ya que podríamos eliminar dependencias necesarias para controladores compartidos.
make \ ARCH=arm64 \ CROSS_COMPILE=aarch64-linux-gnu- \ defconfig
Nos aseguramos de que el soporte necesario para arrancar desde la microSD, montar ext4 y utilizar la consola serie quede integrado directamente en el kernel y no dependa de módulos que todavía no podrían cargarse:
scripts/config --enable ARCH_MEDIATEK scripts/config --enable BLK_DEV_INITRD scripts/config --enable DEVTMPFS scripts/config --enable DEVTMPFS_MOUNT scripts/config --enable EXT4_FS scripts/config --enable FAT_FS scripts/config --enable VFAT_FS scripts/config --enable MMC scripts/config --enable MMC_BLOCK scripts/config --enable MMC_MTK scripts/config --enable SERIAL_8250 scripts/config --enable SERIAL_8250_CONSOLE scripts/config --enable SERIAL_OF_PLATFORM make \ ARCH=arm64 \ CROSS_COMPILE=aarch64-linux-gnu- \ olddefconfig
Si queremos añadir o quitar controladores, abrimos la configuración interactiva:
make \ ARCH=arm64 \ CROSS_COMPILE=aarch64-linux-gnu- \ menuconfig
Para mantener la funcionalidad del router conviene conservar los controladores de red de MediaTek, DSA, el switch MT7530/MT7531, phylink, SFP, PCI Express y los controladores inalámbricos MediaTek.
Compilamos el kernel, los módulos y todos los Device Trees:
make -j"$(nproc)" \ ARCH=arm64 \ CROSS_COMPILE=aarch64-linux-gnu- \ Image \ modules \ dtbs
Obtenemos el identificador exacto de la versión compilada:
vVersionKernel="$( make -s \ ARCH=arm64 \ CROSS_COMPILE=aarch64-linux-gnu- \ kernelrelease )" echo "$vVersionKernel"Generar el Device Tree final para la microSD
El kernel proporciona un Device Tree base para la placa y diferentes superposiciones. Los archivos utilizados en este caso son:
- mt7986a-bananapi-bpi-r3.dtb: descripción base de la BPI-R3.
- mt7986a-bananapi-bpi-r3-sd.dtbo: configuración adicional que habilita el uso de la tarjeta SD.
Aunque U-Boot puede aplicar superposiciones en tiempo de arranque, generaremos previamente un DTB completo. De esta forma no dependeremos de que la configuración concreta de U-Boot aplique automáticamente el overlay correcto.
vDtbBase="$vKernel/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3.dtb" vDtboSd="$vKernel/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-sd.dtbo" vDtbFinal="$vProyecto/mt7986a-bananapi-bpi-r3-sd.dtb" test -f "$vDtbBase" test -f "$vDtboSd" fdtoverlay \ -i "$vDtbBase" \ -o "$vDtbFinal" \ "$vDtboSd" fdtdump "$vDtbFinal" > /dev/null
El último comando comprueba que el archivo generado puede ser interpretado correctamente por las herramientas de Device Tree.
Compilar U-Boot para arrancar desde la microSD
Clonamos una versión estable de U-Boot y seleccionamos la configuración específica de la BPI-R3 para SD:
git clone \ --depth 1 \ --branch "$vVersionUBoot" \ https://source.denx.de/u-boot/u-boot.git \ "$vUBoot" cd "$vUBoot" make \ CROSS_COMPILE=aarch64-linux-gnu- \ mt7986a_bpir3_sd_defconfig make -j"$(nproc)" \ CROSS_COMPILE=aarch64-linux-gnu- test -f "$vUBoot/u-boot.bin"
El archivo u-boot.bin todavía no es una imagen arrancable por sí mismo. Debemos introducirlo como etapa BL33 dentro del FIP de MediaTek.
Generar BL2 y FIP con Trusted Firmware-A
Clonamos la implementación de Trusted Firmware-A utilizada para los SoC MediaTek MT798x:
git clone \ --depth 1 \ https://github.com/mtk-openwrt/arm-trusted-firmware.git \ "$vTfa" cd "$vTfa"
Compilamos una cadena de arranque para SD y memoria DDR4, incluyendo el binario de U-Boot como BL33:
make -j"$(nproc)" \ CROSS_COMPILE=aarch64-linux-gnu- \ PLAT=mt7986 \ BOOT_DEVICE=sdmmc \ DRAM_USE_DDR4=1 \ USE_MKIMAGE=1 \ BL33="$vUBoot/u-boot.bin" \ all \ fip
Localizamos los dos archivos que escribiremos en la zona reservada de la imagen:
vBl2="$( find "$vTfa/build/mt7986" \ -type f \ -name "bl2.img" \ | sed -n '1p' )" vFip="$( find "$vTfa/build/mt7986" \ -type f \ -name "fip.bin" \ | sed -n '1p' )" if [ -z "$vBl2" ] || [ ! -f "$vBl2" ]; then echo "No se ha generado bl2.img" exit 1 fi if [ -z "$vFip" ] || [ ! -f "$vFip" ]; then echo "No se ha generado fip.bin" exit 1 fi echo "BL2: $vBl2" echo "FIP: $vFip"También guardamos los commits exactos utilizados. Esto nos permitirá repetir posteriormente la compilación con las mismas revisiones:
git -C "$vKernel" rev-parse HEAD | tee "$vProyecto/commit-linux.txt" git -C "$vUBoot" rev-parse HEAD | tee "$vProyecto/commit-u-boot.txt" git -C "$vTfa" rev-parse HEAD | tee "$vProyecto/commit-tfa.txt"
Crear el sistema de archivos raíz de Debian
Como el ordenador de construcción normalmente será AMD64 y el sistema de destino es ARM64, realizaremos debootstrap en dos etapas. La primera etapa descarga y desempaqueta Debian. La segunda se ejecuta dentro del sistema ARM64 mediante QEMU y binfmt. Podemos consultar todos los parámetros disponibles en la página del manual de debootstrap.
sudo mkdir -p "$vRootfs" sudo debootstrap \ --arch=arm64 \ --foreign \ "$vSuiteDebian" \ "$vRootfs" \ http://deb.debian.org/debian
Habilitamos el intérprete de binarios AArch64 y copiamos QEMU dentro del sistema:
sudo update-binfmts --enable qemu-aarch64 test -x /usr/bin/qemu-aarch64-static sudo install \ -m 0755 \ /usr/bin/qemu-aarch64-static \ "$vRootfs/usr/bin/qemu-aarch64-static"
Montamos los sistemas virtuales necesarios para configurar correctamente los paquetes:
sudo mkdir -p \ "$vRootfs/dev" \ "$vRootfs/proc" \ "$vRootfs/sys" \ "$vRootfs/run" sudo mount --rbind /dev "$vRootfs/dev" sudo mount --make-rslave "$vRootfs/dev" sudo mount -t proc proc "$vRootfs/proc" sudo mount --rbind /sys "$vRootfs/sys" sudo mount --make-rslave "$vRootfs/sys" sudo mount --rbind /run "$vRootfs/run" sudo mount --make-rslave "$vRootfs/run" sudo rm -f "$vRootfs/etc/resolv.conf" sudo cp --dereference /etc/resolv.conf "$vRootfs/etc/resolv.conf"
Ejecutamos la segunda etapa:
sudo chroot \ "$vRootfs" \ /debootstrap/debootstrap \ --second-stage
Configurar los repositorios de Debian
Eliminamos la configuración que haya creado debootstrap y definimos los repositorios de Debian Trixie, incluidas las secciones necesarias para instalar firmware:
sudo rm -f "$vRootfs/etc/apt/sources.list.d/debian.sources" { echo "deb http://deb.debian.org/debian trixie main contrib non-free non-free-firmware" echo "deb http://deb.debian.org/debian trixie-updates main contrib non-free non-free-firmware" echo "deb http://security.debian.org/debian-security trixie-security main contrib non-free non-free-firmware" } | sudo tee "$vRootfs/etc/apt/sources.list" > /dev/nullEvitamos que los paquetes intenten arrancar servicios dentro del chroot:
{ echo "#!/bin/sh" echo "" echo "exit 101" } | sudo tee "$vRootfs/usr/sbin/policy-rc.d" > /dev/null sudo chmod 0755 "$vRootfs/usr/sbin/policy-rc.d"Entramos en el sistema ARM64:
sudo chroot "$vRootfs" /bin/bash
A partir de este punto, los siguientes comandos se ejecutan dentro del chroot:
export DEBIAN_FRONTEND=noninteractive apt-get update apt-get install -y \ ca-certificates \ cloud-guest-utils \ ethtool \ firmware-mediatek \ gdisk \ initramfs-tools \ iproute2 \ locales \ nftables \ openssh-server \ sudo \ systemd-resolved \ systemd-sysv \ tzdata
No instalaremos linux-headers-$(uname -r). Dentro del chroot, uname seguiría mostrando el kernel AMD64 que está ejecutando el ordenador de construcción, no el kernel ARM64 que acabamos de compilar.
Configurar el sistema básico
Configuramos el nombre del equipo y el archivo hosts:
echo "bpi-r3" > /etc/hostname { echo "127.0.0.1 localhost" echo "127.0.1.1 bpi-r3" echo "::1 localhost ip6-localhost ip6-loopback" } > /etc/hostsConfiguramos el idioma y la zona horaria:
echo "es_ES.UTF-8 UTF-8" > /etc/locale.gen locale-gen update-locale LANG=es_ES.UTF-8 ln -sfn /usr/share/zoneinfo/Europe/Madrid /etc/localtime echo "Europe/Madrid" > /etc/timezone dpkg-reconfigure -f noninteractive tzdata
Definimos los sistemas de archivos que tendrá la imagen:
{ echo "LABEL=BPI-R3-ROOT / ext4 defaults,noatime 0 1" echo "LABEL=BPI-R3-BOOT /boot vfat defaults,umask=0077 0 2" } > /etc/fstabConfigurar provisionalmente la red
Los nombres de las interfaces pueden variar dependiendo de los controladores, del Device Tree y de la versión de systemd. Crearemos una configuración DHCP provisional que coincida con los nombres más habituales. Una vez arrancado el router podremos sustituirla por la configuración definitiva de bridge, VLAN, routing o firewall.
mkdir -p /etc/systemd/network { echo "[Match]" echo "Name=wan lan* eth* end*" echo "" echo "[Link]" echo "RequiredForOnline=no" echo "" echo "[Network]" echo "DHCP=yes" echo "IPv6AcceptRA=yes" } > /etc/systemd/network/20-dhcp.networkHabilitamos la red, la resolución DNS, SSH y la consola serie:
systemctl enable systemd-networkd.service systemctl enable systemd-resolved.service systemctl enable ssh.service systemctl enable serial-getty@ttyS0.service
Establecemos una contraseña para root y creamos un usuario administrativo. Podemos sustituir administrador por el nombre que prefiramos:
passwd root adduser --gecos "" administrador usermod -aG sudo administrador
Eliminamos la política temporal y salimos del chroot:
rm -f /usr/sbin/policy-rc.d exit
Instalar el kernel y los módulos dentro de Debian
Desde el ordenador de construcción instalamos los módulos del kernel dentro del sistema ARM64:
cd "$vKernel" sudo make \ ARCH=arm64 \ CROSS_COMPILE=aarch64-linux-gnu- \ INSTALL_MOD_PATH="$vRootfs" \ INSTALL_MOD_STRIP=1 \ modules_install
Copiamos el kernel, su configuración, el mapa de símbolos y el Device Tree final:
sudo mkdir -p "$vRootfs/boot" sudo mkdir -p "$vRootfs/boot/dtbs/$vVersionKernel/mediatek" sudo install \ -m 0644 \ "$vKernel/arch/arm64/boot/Image" \ "$vRootfs/boot/vmlinuz-$vVersionKernel" sudo install \ -m 0644 \ "$vKernel/.config" \ "$vRootfs/boot/config-$vVersionKernel" sudo install \ -m 0644 \ "$vKernel/System.map" \ "$vRootfs/boot/System.map-$vVersionKernel" sudo install \ -m 0644 \ "$vDtbFinal" \ "$vRootfs/boot/dtbs/$vVersionKernel/mediatek/mt7986a-bananapi-bpi-r3-sd.dtb"
Actualizamos las dependencias de los módulos y generamos el initramfs:
sudo chroot \ "$vRootfs" \ depmod \ -a \ "$vVersionKernel" sudo chroot \ "$vRootfs" \ update-initramfs \ -c \ -k "$vVersionKernel" test -f "$vRootfs/boot/initrd.img-$vVersionKernel"
Limpiar el sistema antes de crear la imagen
Eliminamos los identificadores y claves que deben generarse de forma independiente durante el primer arranque:
sudo chroot "$vRootfs" apt-get clean sudo rm -f "$vRootfs/etc/ssh/ssh_host_"* sudo truncate -s 0 "$vRootfs/etc/machine-id" sudo rm -f "$vRootfs/var/lib/dbus/machine-id" sudo find \ "$vRootfs/var/lib/apt/lists" \ -mindepth 1 \ -delete sudo rm -f "$vRootfs/usr/bin/qemu-aarch64-static" sudo rm -f "$vRootfs/etc/resolv.conf" sudo ln -s \ /run/systemd/resolve/stub-resolv.conf \ "$vRootfs/etc/resolv.conf"
Desmontamos los sistemas virtuales del chroot:
sudo umount -R "$vRootfs/run" sudo umount -R "$vRootfs/sys" sudo umount -R "$vRootfs/proc" sudo umount -R "$vRootfs/dev"
Crear el archivo de imagen
Crearemos una imagen inicial de 4 GiB. La primera partición comenzará en el MiB 64, dejando espacio suficiente para BL2, el entorno de U-Boot, FIP y otras áreas reservadas del arranque.
rm -f "$vImagen" truncate -s 4G "$vImagen" vLoop="$( sudo losetup \ --find \ --show \ --partscan \ "$vImagen" )" echo "$vLoop"Creamos una tabla GPT, una partición FAT32 para el kernel y una partición ext4 para Debian:
sudo parted -s "$vLoop" mklabel gpt sudo parted -s "$vLoop" \ mkpart BPI-R3-BOOT fat32 64MiB 320MiB sudo parted -s "$vLoop" \ mkpart BPI-R3-ROOT ext4 320MiB 100% sudo partprobe "$vLoop" sudo udevadm settle vParticionBoot="${vLoop}p1" vParticionRoot="${vLoop}p2" test -b "$vParticionBoot" test -b "$vParticionRoot"La partición FAT32 es únicamente una partición de arranque para U-Boot. No es una partición EFI ni debemos marcarla como ESP.
Escribir BL2 y FIP en la imagen
Escribimos BL2 a partir del sector 34 y FIP a partir del sector 13312. El tamaño de bloque utilizado es de 512 bytes. La primera partición de datos comienza en el MiB 64, por lo que estas escrituras no la sobrescribirán.
sudo dd \ if="$vBl2" \ of="$vLoop" \ bs=512 \ seek=34 \ conv=notrunc,fsync \ status=progress sudo dd \ if="$vFip" \ of="$vLoop" \ bs=512 \ seek=13312 \ conv=notrunc,fsync \ status=progress
Este paso sustituye al comando incorrecto del borrador original que escribía u-boot.bin directamente mediante seek=2.
Formatear y poblar las particiones
sudo mkfs.vfat \ -F 32 \ -n BPI-R3-BOOT \ "$vParticionBoot" sudo mkfs.ext4 \ -F \ -L BPI-R3-ROOT \ "$vParticionRoot"
Montamos la partición raíz y copiamos Debian conservando propietarios, permisos, ACL, atributos extendidos y UID numéricos:
vMontaje="$vProyecto/mnt" sudo rm -rf "$vMontaje" sudo mkdir -p "$vMontaje" sudo mount "$vParticionRoot" "$vMontaje" sudo rsync \ -aHAX \ --numeric-ids \ --exclude="/boot/*" \ "$vRootfs/" \ "$vMontaje/"
Montamos la partición de arranque dentro del directorio boot de Debian:
sudo mkdir -p "$vMontaje/boot" sudo mount "$vParticionBoot" "$vMontaje/boot" sudo install \ -m 0644 \ "$vRootfs/boot/vmlinuz-$vVersionKernel" \ "$vMontaje/boot/vmlinuz-$vVersionKernel" sudo install \ -m 0644 \ "$vRootfs/boot/initrd.img-$vVersionKernel" \ "$vMontaje/boot/initrd.img-$vVersionKernel" sudo mkdir -p \ "$vMontaje/boot/dtbs/$vVersionKernel/mediatek" sudo install \ -m 0644 \ "$vDtbFinal" \ "$vMontaje/boot/dtbs/$vVersionKernel/mediatek/mt7986a-bananapi-bpi-r3-sd.dtb"
Configurar el arranque mediante Extlinux
U-Boot puede descubrir sistemas arrancables mediante su infraestructura estándar de bootflow y Extlinux. Crearemos una configuración que indique dónde están el kernel, el initramfs, el Device Tree y la partición raíz. La documentación técnica está disponible en el apartado Standard Boot de U-Boot.
sudo mkdir -p "$vMontaje/boot/extlinux" { echo "DEFAULT debian" echo "TIMEOUT 30" echo "MENU TITLE Debian GNU/Linux para Banana Pi BPI-R3" echo "" echo "LABEL debian" echo " MENU LABEL Debian GNU/Linux" echo " LINUX /vmlinuz-$vVersionKernel" echo " INITRD /initrd.img-$vVersionKernel" echo " FDT /dtbs/$vVersionKernel/mediatek/mt7986a-bananapi-bpi-r3-sd.dtb" echo " APPEND root=LABEL=BPI-R3-ROOT rootwait rw console=ttyS0,115200n8 earlycon" } | sudo tee \ "$vMontaje/boot/extlinux/extlinux.conf" \ > /dev/nullAñadir un script de arranque alternativo
Además de Extlinux, añadiremos un archivo boot.scr. Este script nos proporciona una segunda forma de arrancar y puede ejecutarse manualmente desde la consola de U-Boot si el descubrimiento automático no lo encuentra.
{ echo "echo Cargando Debian GNU/Linux..." echo "setenv bootargs root=LABEL=BPI-R3-ROOT rootwait rw console=ttyS0,115200n8 earlycon" echo "load mmc 0:1 \${kernel_addr_r} /vmlinuz-$vVersionKernel" echo "load mmc 0:1 \${ramdisk_addr_r} /initrd.img-$vVersionKernel" echo "setenv vTamanoInitrd \${filesize}" echo "load mmc 0:1 \${fdt_addr_r} /dtbs/$vVersionKernel/mediatek/mt7986a-bananapi-bpi-r3-sd.dtb" echo "booti \${kernel_addr_r} \${ramdisk_addr_r}:\${vTamanoInitrd} \${fdt_addr_r}" } > "$vProyecto/boot.cmd" mkimage \ -A arm64 \ -O linux \ -T script \ -C none \ -n "Debian BPI-R3" \ -d "$vProyecto/boot.cmd" \ "$vProyecto/boot.scr" sudo install \ -m 0644 \ "$vProyecto/boot.scr" \ "$vMontaje/boot/boot.scr" sudo install \ -m 0644 \ "$vProyecto/boot.cmd" \ "$vMontaje/boot/boot.cmd"Finalizar y comprimir la imagen
sync sudo umount "$vMontaje/boot" sudo umount "$vMontaje" sudo losetup -d "$vLoop" cd "$vProyecto" rm -f debian-bpi-r3.img.xz xz \ -T0 \ -6 \ -k \ debian-bpi-r3.img sha256sum \ debian-bpi-r3.img \ debian-bpi-r3.img.xz \ > SHA256SUMS
Al terminar tendremos los siguientes archivos:
- debian-bpi-r3.img: imagen sin comprimir.
- debian-bpi-r3.img.xz: imagen comprimida para almacenarla o distribuirla.
- SHA256SUMS: sumas SHA-256 para verificar la integridad.
- commit-linux.txt, commit-u-boot.txt y commit-tfa.txt: revisiones exactas utilizadas durante la construcción.
Grabar la imagen en una tarjeta microSD
Debemos comprobar con lsblk cuál es el dispositivo correspondiente a la microSD. Escribir sobre el dispositivo equivocado destruirá su tabla de particiones y sus datos.
lsblk \ -o NAME,SIZE,MODEL,TRAN,FSTYPE,MOUNTPOINTS
Definimos el dispositivo completo, no una de sus particiones. En este ejemplo utilizamos /dev/sdX como marcador que debemos sustituir:
vDispositivo="/dev/sdX" lsblk \ -o NAME,SIZE,MODEL,TRAN,FSTYPE,MOUNTPOINTS \ "$vDispositivo"
Desmontamos previamente cualquier partición de la tarjeta y grabamos la imagen:
xz -dc "$vProyecto/debian-bpi-r3.img.xz" \ | sudo dd \ of="$vDispositivo" \ bs=4M \ status=progress \ conv=fsync syncNo debemos utilizar una partición como /dev/sdX1 en el parámetro of. La imagen debe escribirse sobre el dispositivo completo.
Realizar el primer arranque
Colocamos los interruptores físicos de la BPI-R3 en la posición de arranque desde SD indicada en la serigrafía y en la documentación de la placa. Es recomendable realizar el primer arranque mediante la consola UART de 3,3 voltios configurada a 115200 baudios, 8 bits de datos, sin paridad y un bit de parada.
Desde Debian podemos conectarnos mediante picocom:
sudo apt install -y picocom sudo picocom \ -b 115200 \ /dev/ttyUSB0
No debemos conectar la alimentación de 5 voltios del adaptador USB-UART al conector serie del router. Solamente conectaremos tierra, transmisión y recepción, cruzando TX con RX.
Si U-Boot no encuentra automáticamente Extlinux o boot.scr, interrumpimos la cuenta atrás y ejecutamos:
mmc list part list mmc 0 fatls mmc 0:1 / load mmc 0:1 ${scriptaddr} /boot.scr source ${scriptaddr}Una vez arrancado Debian comprobamos el modelo, el kernel, los dispositivos de almacenamiento y las interfaces de red:
cat /proc/device-tree/model echo "" uname -a lsblk ip -br link dmesg \ | grep -Ei "mt7986|mmc|mt753|sfp|firmware|error|fail"
Ampliar la partición raíz al tamaño completo de la tarjeta
La imagen inicial mide 4 GiB. Si la grabamos en una tarjeta mayor, el espacio restante quedará sin utilizar hasta que movamos la copia secundaria de la GPT y ampliemos la segunda partición.
Primero identificamos el dispositivo que contiene la raíz:
findmnt -no SOURCE / lsblk
Si el sistema raíz es /dev/mmcblk0p2, ampliamos la partición ejecutando:
sudo sgdisk -e /dev/mmcblk0 sudo growpart /dev/mmcblk0 2 sudo resize2fs /dev/mmcblk0p2
Si la tarjeta aparece como /dev/mmcblk1, debemos sustituir mmcblk0 por mmcblk1 en los tres comandos.
Diagnosticar problemas de arranque
No aparece ninguna salida de U-Boot
Comprobamos la posición de los interruptores de arranque, la alimentación del router, la configuración UART a 115200 baudios y las conexiones TX, RX y GND. Si la consola serie funciona pero no aparece U-Boot, revisamos especialmente la generación de BL2, el parámetro DRAM_USE_DDR4 y las escrituras en los sectores 34 y 13312.
U-Boot arranca pero no encuentra la partición FAT32
Comprobamos que la tarjeta sea detectada y que la primera partición pueda leerse:
mmc rescan mmc dev 0 part list mmc 0 fatls mmc 0:1 /
El kernel muestra un error VFS unable to mount root fs
Este error suele significar que el kernel no puede acceder a la microSD, no reconoce ext4 o no encuentra la etiqueta BPI-R3-ROOT. Debemos comprobar que MMC_MTK, MMC_BLOCK y EXT4_FS estén compilados como parte del kernel, que hayamos aplicado el overlay SD y que la partición tenga la etiqueta correcta.
Desde otro ordenador podemos comprobar la etiqueta ejecutando:
sudo blkid /dev/sdX2
La salida debe incluir:
LABEL="BPI-R3-ROOT"
Debian arranca pero no aparecen las interfaces de red
Revisamos los mensajes del controlador Ethernet, DSA, el switch y el firmware:
ip -details link dmesg \ | grep -Ei "mediatek|mtk|mt753|dsa|phylink|sfp|firmware"
También comprobamos qué opciones de red quedaron realmente activadas en el kernel:
zgrep -E \ "CONFIG_(NET_MEDIATEK_SOC|NET_DSA|NET_DSA_MT7530|SFP|PHYLINK)" \ /proc/config.gz
Si /proc/config.gz no existe, consultamos el archivo instalado en boot:
grep -E \ "CONFIG_(NET_MEDIATEK_SOC|NET_DSA|NET_DSA_MT7530|SFP|PHYLINK)" \ "/boot/config-$(uname -r)"
Para arrancar desde eMMC, NAND o NOR no debemos reutilizar esta imagen sin cambios. Tendremos que seleccionar la configuración correspondiente de U-Boot, cambiar BOOT_DEVICE al compilar Trusted Firmware-A y generar un Device Tree final aplicando el overlay del medio de almacenamiento elegido.