Conversión de CIT a Linux
Para poder usar un router Atlas 50 con todas las funcionalidades de Linux tenemos que convertirlo, aplicando unas modificaciones hardware y por supuesto software.
Arquitectura
A continuación se describe la arquitectura hardware del sistema:
- Microprocesador Motorola MPC 8272.
- Memoria Caché L1 16KB instrucciones/16KB datos.
- Memoria SDRAM 64 MB.
- Memoria FLASH 16 MB.
- Criptoprocesador integrado.
- Ranuras de expansión:
- 1x Ranura de expansión externa PMC-PCI
- 1x Ranura de expansión interna miniPCI
- 9 LEDs indicadores de estado
Interfaces ETHERNET
- 2x Fast-Ethernet 10/100 RJ-45 H
- Detección automática 10/100 BASE-T
- Negociación automática Half/Full Duplex
- Ethernet V2/IEEE 802.3
- IEEE 802.1Q (VLAN)
- 2 LEDs de estado por puerto
Interfaz RDSI
- 1x BRI-RDSI (2B+D) RJ-45
Conversión Hardware
Para solventarlo, hay que enviar el router en cuestión a Teldat y ellos lo arreglan. Después de arreglarlo, lo devuelven con un bootloader del tipo CIT y un software CIT. Para conseguir la funcionalidad Linux hay que actualizar el bootloader CIT a un bootloader Linux, proporcionado por Teldat.
Adicionalmente se comenta el funcionamiento de alguno de los jumpers de la inferior.
- Jumper 1 : Test del sistema.
- Jumper 2 : Actualización del bootloader.
Test del sistema
El jumper 1 realiza un test del sistema, en el cual comprueba que los dispositivos hardware funcionan bien.
En caso de hacerlo, saldrá el siguiente mensaje:
UNEXPECTED RESET DURING WARM-UP PROCESS. EQUIPMENT LOCKED. !!! === INITIAL MENU === a) Change Time b) Change Date c) Change Code to Run d) Change Licence e) Load from console (pc_load) f) Disk menu g) Set default name for file loaded from console h) Change BIOS licence l) Load from lan v) Change version control for loading x) Load from console (xmodem) z) Change command line (Linux) r) Reset lram) Load from lan and run without saving lk) Load kernel from lan lf) Load file system from lan 0) Exit >>
Para desbloquearlo hay que introducir la opción 3 (está oculta).
Conversión Software
Actualizar el bootloader
El jumper 1 permite la actualización del bootloader mediante la consola RS-232 del router. Para ello deberemos colocar el jumper 2 en modo on. Nos saldrá la pantalla de una bios mínima con las siguientes opciones:
BOOT CODE VERSION: 01.07 Nov 23 2007 17:42:31 gzip Nov 23 2007 17:42:31 P.C.B.: 93 MASK:0C10 Microcode:00E1 START FROM EPROM BY SWITCH BIOS CODE DUMP.... BIOS DATA DUMP. End of BIOS dump BIOS CODE VERSION: 01.07 CLK=262144 KHz BUSCLK=65536 KHz SDRAM size: 64 Megabytes BANK 0: 64 Megabytes detected FLASH: 16 Mb. BIOS MAC Add: 00-A0-26-90-FF-FF >> .... e) Load from console (pc_load) x) Load from console (xmodem) l) Load from lan m) RTC menu 0) Reset >>
Introducimos la opción x, que nos permite la actualización
Xmodem whith chk transfer. Default baud rate: 115200 Press any key to change the baud rate .......... Set baud rate to 115200 and send the file with Xmodem with chk protocol. When the transfer finish, reset baud rate to 9600. e) Load from console (pc_load) x) Load from console (xmodem) l) Load from lan m) RTC menu 0) Reset >>
Una vez realizada la actualización realizamos una actualización del kernel siguiendo los pasos de la sección kernel. A continuación instalamos el sistema de ficheros siguiendo los pasos de la sección de sistema de ficheros.
Kernel de recuperación
Durante el proceso de reparación se pensó crear un kernel con las mínimas funcionalidades para tener un sistema base sin red, sólo para acceder a las particiones de disco y tener comunicación al exterior por consola. Para ello se utilizó initramfs, una evolución del sistema initrd, el cual utiliza un disco ram virtual para inicializar el sistema de ficheros. Se puede encontrar más información al respecto en estas direcciones:
Para utilizar este sistema comprimimos un directorio contenedor del sistema de ficheros básico en un archivo cpio. A continuación, en el menuconfig le indicamos la ruta del archivo cpio que contendrá el sistema de ficheros.
Creación del sistema de ficheros
Para que un sistema Linux funcione es necesario un kernel y un sistema de ficheros. En esta parte nos vamos a encargar de crear un sistema básico de ficheros. Para ello vamos a utilizar las librerías compiladas anteriormente con Builroot en la sección Instalación.
Primero, creamos una carpeta raíz.
>mkdir initramfs >cd initramfs
A continuación recreamos las carpetas básicas de un sistema de ficheros:
>mkdir -p bin dev etc home lib mnt newroot proc root sbin sys
Copiamos las librerías necesarias para el correcto funcionamiento del sistema. En este caso necesitaremos ld-uClibc, libcrypt, libuClibc, libdl, libm, libncurses, libnsl, libpthread, libresolv, librt, libthread_db, libuClibc, libutil.
<librería>-<x>.<y>.so → <librería>-<x>.<y>.[<z>].so
<librería>-<x>.so → <librería>-<x>.<y>.[<z>].so
<librería>→ <librería>-<x>.<y>.[<z>].so
Estos enlaces pueden apuntar a cualquier versión de la librería, pero se suele apuntar a la última versión.
Una vez copiadas las librerías pasamos a poblar la carpeta /dev. Esta tiene que ser copiada mediante el comando *cp -R* (copia recursiva), ya que el algoritmo normal del cp para copia de ficheros lo hace mediante un read/write. Estas llamadas aplicadas a un fichero de tipo dispositivo lo que hacen es leer los datos de ese dispositivo, y copiarlos al destino en forma de fichero normal con *los datos leidos del dispositivo*. Para hacerlo correctamente lo hacemos mediante el siguiente comando:
>cp -R /dev/ ../initramfs
El siguiente paso es crear los ejecutables necesarios para el funcionamiento del sistema. Para ello usamos Busybox. A busybox lo podríamos llamar “la navaja suiza de los sistemas empotrados”. Nos provee de las herramientas básicas necesarias en cualquier sistema Linux, tales como ls, cp, mkdir, etc.
Esta utilidad es ideal para un sistema empotrado ya que reduce considerablemente el número de líneas de código usadas para las herramientas básicas. Está concebido de tal manera que las funciones comunes a estas herramientas se implementan usa sóla vez y se sabe que función usar mediante un enlace simbólico que apunta al ejecutable de busybox con el nombre de la llamada. Por ejemplo, si tuviéramos instalado busybox con las llamadas ls y cp, existirían dos enlaces simbólicos (ls y cp) que apuntarían a busybox de esta manera:
>ls -l /bin cp -> busybox ls -> busybox
Una vez instalado podemos ver que herramientas incluye mediante la siguiente llamada
>busybox --help
Para esta versión del sistema de ficheros hemos usado la versión 1.14.1 de busybox. La descargamos mediante el siguiente comado:
> wget http://www.busybox.net/downloads/busybox-1.4.1.tar.bz2
Una configuración básica de las herramientas a usar está en el siguiente archivo de configuración de busybox. Este tiene que ser renombrado a '.config' e incluirlo en el directorio raíz donde se va a compilar busybox.
Definimos el directorio de instalación donde se efectuará la recreación de enlaces simbolicos. Para ello hacemos:
>make CROSS_COMPILE="powerpc-linux-" menuconfig
Ahora nos vamos a las secciones:
Busybox Settings ---> Installation Options ---> (./_install) BusyBox installation prefix
Y cambiamos el directorio ”./_install al directorio raíz de nuestro sistema de ficheros, por ejemplo '../initramfs'
Ahora lo compilamos con la herramienta make de la siguiente manera:
>make CROSS_COMPILE="powerpc-linux-"
Hacemos la instalación:
>make CROSS_COMPILE="powerpc-linux-" install
Por último cambiamos el bit 'suid' del ejecutable busybox.
>sudo chmod +s initramfs/bin/busybox
El siguiente paso es construir el xmodem. Para ello usamos lrzsz, una versión de xmodem que incluye además ymodem y zmodem. Nos descargamos la versión 0.12.20 de la web oficial. Una vez descargado y descomprimido, ejecutamos los siguientes pasos:
>./configure --host=powerpc-linux- --target=powerpc-linux- --build=powerpc-linux- --disable-nls >make CC=powerpc-linux-gcc CPP=powerpc-linux-gcc RANLIB=powerpc-linux-ranlib LDFLAGS=-s > cp {lsz,lrz} ../initramfs/bin
Faltan aún un último detalle, y este es el init. Cuando un sistema Linux se inicia, necesita ejecutar un proceso inicial. Pues bien, este va a ser nuestro fichero init, en forma de un script sh. En esta versión del sistema, tendremos que incluir adicionalmente un fichero en /etc llamado inittab, que indica que otros procesos se requiere iniciar al iniciar el sistema.
Lo creamos y le damos permisos de ejecución:
>touch initramfs/init >chmod +x initramfs/init
Modificamos el contenido del fichero con nuestro editor favorito y le añadimos el siguiente contenido:
#!/bin/bash
exec /bin/bash
Ahora modificaremos el fichero /etc/inittab con lo siguiente
null::sysinit:/bin/mount -t proc proc /proc null::sysinit:/bin/mount -o remount,rw / null::sysinit:/bin/mount -a null::sysinit:/bin/hostname -F /etc/hostname # now run any rc scripts ::sysinit:/etc/init.d/rcS # Set up a couple of getty's console::respawn:/sbin/getty -L console 115200 vt100
# Logging junk null::sysinit:/bin/touch /var/log/messages null::respawn:/sbin/syslogd -n -m 0 null::respawn:/sbin/klogd -n tty2::once:/usr/bin/tail -f /var/log/messages # Stuff to do for the 3-finger salute ::ctrlaltdel:/sbin/reboot # Stuff to do before rebooting null::shutdown:/usr/bin/killall klogd null::shutdown:/usr/bin/killall syslogd null::shutdown:/bin/umount -a -r null::shutdown:/sbin/swapoff -a
Por fin podremos crear nuestro sistema de ficheros, no antes sin poner a todos los archivos el propietario de root.
>cd initramfs >chmod -R root:root .
Creamos el sistema de ficheros con los siguientes comandos
> cd initramfs > find . | cpio -H newc -o > ../initramfs.cpio
Por fin hemos creado el initramfs que incrustaremos en nuestro kernel.
Kernel
Para la creación de nuestro kernel vamos a seguir el mismo procedimiento para obtenerlo y parchearlo que en la sección dedicada a ello: Introducción.
Una vez hecho esto, descargamos el archivo de configuración y lo renombramos a '.config', copiándolo al directorio donde hemos descargado y parcheado el kernel. Una vez hecho esto, tenemos que hacer una pequeña modificación en la configuración del kernel para indicarle donde está la imagen de nuestro sistema de ficheros creado para el propósito. Para ello abrimos el menuconfig del kernel:
>make CROSS_COMPILE=powerpc-linux- ARCH=powerpc menuconfig
Una vez hecho esto, accedemos a las siguientes opciones
General setup ---> (../initramfs.cpio) Initramfs source file(s)
En esta opción debemos definir donde se encuentra el archivo contenedor del sistema de ficheros initramfs. Debemos poner la ruta absoluta (empezando por '/') o la ruta relativa al directorio actual.
Una vez hecho esto, compilamos el kernel con:
>make CROSS_COMPILE=powerpc-linux- ARCH=powerpc
Deberemos observar en la traza el siguiente mensaje:
GEN usr/initramfs_data.cpio.gz AS usr/initramfs_data.o
Esto indica la inclusión del fichero que contiene el sistema de ficheros de initramfs dentro del kernel.
Puesta a punto
Una vez que tenemos el kernel, el siguiente paso es transferirlo a nuestro router. Hay que seguir los mismos pasos del documento Instalación
Al iniciarse el router, pulsamos Ctrl + T y tendremos el siguiente menu:
a) Change Time b) Change Date c) Change Code to Run d) Change Licence e) Load from console (pc_load) f) Disk menu g) Set default name for file loaded from console h) Change BIOS licence l) Load from lan v) Change version control for loading x) Load from console (xmodem) z) Change command line (Linux) r) Reset lram) Load from lan and run without saving lk) Load kernel from lan lf) Load file system from lan 0) Exit >>
Pulsamos la x (Load from console) y transferimos el kernel al router. Una vez hecho esto pulsamos la opción z (Change command line) para cambiar la linea de comandos inicial. Esta será una muy básica, la que viene por defecto en el router. Será la siguiente:
console=ttyCPM0,9600n8n
Una vez hecho esto ya podemos inicializar el sistema. Pulsamos 0 para salir.
Manejo de router
Ahora disponemos de nuestro router con una funcionalidad básica podemos leer y escribir en cualquier partición de su memoria.
- Partición 0 (mtdblock0):Bootloader
- Partición 1 (mtdblock1):Kernel
- Partición 2 (mtdblock2):Sistema de ficheros normal (no initramfs)
- Partición 3 (mtdblock3):Reservada para logs en la versión original de CIT
Leer una partición
Este kernel se creó originalmente para leer y escribir en las particiones del router, ya que sin saber que el router no era compatible con Linux a priori, intentamos hacer una conversión de un router CIT a un router Linux. Para comprobar que el bootloader se actualizaba correctamente necesitábamos leer una de las particiones y comprobar que el contenido era el esperado.
Para leer una partición y guardarla en un formato binario se utiliza el mandato dd (data dump). Tiene muchas opciones, muchas de las cuales afectan al rendimiento de la operación, pero las que nos van a interesar son las siguientes:
- if=<origen> : Especifica el origen de donde se va a leer (archivo o dispositivo). Si no se especifica lee de la entrada estándar.
- of=<destino> : Especifica el destino donde se va a escribir (archivo o dispositivo). Si no se especifica escribe en la salida estándar.
- bs=<tamaño> : Especifica el tamaño de bloque para la entrada y la salida.
- count=<destino> : Especifica el numero de bloques que serán leídos y escritos.
En concreto para leer la partición del bootloader lo hacemos con el siguiente comando:
>dd if=/dev/mtdblock0 of=bootloader.bin
Escribir en una partición
Si tenemos una imagen de una partición y volcar byte a byte esa imagen en la partición el procedimiento será el siguiente:
>dd if=imagen.bin of=/dev/mtdblock2
Recepción por consola
Dado que no tenemos activada la funcionalidad de red, no podemos transferir archivos al router por NFS y necesitamos pasar esos archivos por consola. El dispositivo que controla la consola es /dev/console y a priori está configurado para una velocidad de transmisión de 9600 baudios.
El programa lrz es compatible con los protocolos de transferencia xmodem, ymodem y zmodem. En nuestro caso, dado que el minicom acepta los tres protocolos también, utilizaremos el zmodem, por ser el último desarrollado y el más eficiente. La sintaxis del mandato es:
>lrz [opciones] [nombre.del.fichero.si.usamos.xmodem]
Algunas opciones interesantes pueden ser:
- -Z: Se usa el protocolo zmodem.
- –ymodem : Se usa el protocolo ymodem.
- -X: Usa el protocolo xmodem.
- -O : Desactivar los timeouts. Se espera para siempre por datos
- -r : Intenta continuar la transferencia de ficheros desde donde se dejó en una transferencia anterior.
Ahora pongamos por ejemplo que ya hemos dado la órden en nuestra estación de trabajo para transferir el fichero 'file1.bin'. Para la recepción de este fichero en nuestro router usando el protocolo zmodem ejecutamos el siguiente mandato:
>lrz -Z
Este protocolo tiene características interesantes como el autonegocio de la velocidad de tranferencia, comprobación redundante de errores y que no hace falta especificar el nombre del fichero que se va a transferir, ya que mantiene el que se le ha dado en el emisor.
Envío por consola
Ahora se da la situación inversa: queremos enviar un archivo desde nuestro router a nuestra máquina de trabajo. Dado que no están activas las funciones de red, deberemos hacerlo por consola. El dispositivo que controla la consola es /dev/console y a priori está configurado para una velocidad de transmisión de 9600 baudios.
El programa lsz es compatible con los protocolos de transferencia xmodem, ymodem y zmodem. En nuestro caso, dado que el minicom acepta los tres protocolos también, utilizaremos el zmodem, por ser el último desarrollado y el más eficiente. La sintaxis del mandato es:
>lsz [opciones] fichero
Algunas opciones interesantes pueden ser:
- -Z: Se usa el protocolo zmodem.
- –ymodem : Se usa el protocolo ymodem.
- -X: Usa el protocolo xmodem.
- -O : Desactivar los timeouts. Se espera para siempre por datos
- -r : Intenta continuar la transferencia de ficheros desde donde se dejó en una transferencia anterior.
- -8 : Prueba a transferir en bloques de 8k.
Imaginemos que hemos sacado conseguido trasladar la partición del bootloader a un fichero binario. Ahora queremos enviar ese fichero a nuestra máquina para analizarlo. Se haría mediante el siguiente comando:
>lsz -Z8 bootloader.bin
En nuestra máquina deberemos dar la instrucción al minicom de que reciba el fichero por el protocolo zmodem.Se puede observar que indicamos el uso del protocolo zmodem mediante la opción -Z y prueba a enviar bloques de 8 kbytes. Dado que el cable es corto y no se suelen producir muchos errores de transferencia, es recomendable el uso de esta opción para reducir la comprobación de errores de redundancia cíclica.
Desensamblar el bootloader
Como último detalle se ha conseguido desensablar el bootloader del dispositivo. Para ello hay que sacarlo del router con los pasos anteriormente mencionados. Para desensamblar el bootloader se utilizará la utilidad objdump, contenida en el paquete binutils. Este se habrá compilado en la máquina de desarrollo para desarrollo cruzado al crear el toolchain con la utilidad buildroot, tal como se explica en la sección Instalación.
Una vez que tenemos el bootloader vemos que tipo de fichero es con la utilidad file:
> file bootloader.bin bootloader.bin: EST flat binary
Como vemos, es de tipo EST. Este target se llama binary. El mandato objdumpp tiene el siguiente formato:
>objdump <opcion(es)> <archivo(s)>
Vamos a describir ahora las opciones que no serán útiles:
- -a : Muestra las cabeceras del archivo
- -l : Incluye el nombre del archivo y el número de la línea en el dump
- -D : Desensabla todas las secciones.
- -x : Muestra el contenido de todas las cabeceras
- –special-syms : Muestra símbolos especiales
- –target=<target>: Define en que formato está el archivo que queremos convertir. Nos va a interesar la opción binary.
- –architecture=<arq>: Define para que arquitectura está compilado. La nuestra será powerpc:603.
Una vez definidas las opciones, desablaremos nuestro bootloader con el siguiente mandato:
>powerpc-linux-objdump -alxD --special-syms --target=binary --architecture=powerpc:603 bootloader.bin > bootloader.s
El fichero “bootloader.s” es a donde se redirecciona la salida del objdump y contendrá el código en ensamblador del fichero bootloader.bin.
Conversión entre formatos objeto
Nos puede interesar convertir un fichero objeto de un formato a otro (de ELF a EST o viceversa). Para hacer esto tenemos un programa llamado objcopy, que convierte un ejecutable de un formato a otro. La sintaxis de este mandato es:
>objcopy [opcion(es)] archivo(s)_entrada [archivo(s)_salida]
Algunos parámetros que nos interesan son los siguientes:
- –input-target <target> : target (tipo de archivo) de entrada.
- –output-target <target> : target (tipo de archivo) de salida.
Para convertir un ejecutable ejecutamos el siguiente mandato:
>powerpc-linux-objcopy --input-target binary --output-target elf32-powerpc bootloader.bin bootloader_elf.bin