Actualizado. Hace unos días encontré una página sobre discos duros multimedia basados en procesador MIPS. Aunque no es sobre el mismo modelo que mi disco, sí tiene cosas lo suficientemente parecidas como para que funcione. Una de ellas es la idea de utilizar una Debian para MIPS mediante chroot para poder añadir cosas extra.
Aunque la idea es buena, por cuestiones personales prefería utilizar Gentoo, así que me bajé la stage3 para MIPS, la copié en el disco duro e intenté hacer un chroot. Pero como siempre, las cosas nunca son sencillas: decía que no podía ejecutar bash. Extrañado, copié el ejecutable a mi equipo de sobremesa y lo analicé con GHex, comparándolo con el ejecutable de BusyBox.
El problema resultó ser que los stages de Gentoo para MIPS están en formato big-endian, mientras que mi disco duro trabaja en little-endian (parece ser que los procesadores MIPS, aunque pueden trabajar con ambos formatos, no pueden utilizarlos a la vez, sino que se escoge a nivel hardware durante el arranque). Cuando un sistema trabaja en little-endian se dice que es un MIPSel.
Rebuscando encontré unos stages para MIPSel, pero eran del año 2005. Intenté usarlos y, aunque funcionaban, en cuanto intentaba actualizar el sistema al más reciente, fallaba (todo apuntaba a la versión de python, que era demasiado vieja para ejecutar el último portage). Seguí buscando y encontré que las estaciones de trabajo Cobalt trabajaban en little-endian, así que probé de nuevo con unos stages diseñados para ellas, pero seguía fallando.
Decidí entonces probar con la Debian de la página inicial, pero al hacer un dist-upgrade volvía a fallar.
Ante esto, decidí que sólo tenía dos opciones: o utilizaba sólo cross-compiling, o intentaba generar yo mismo un stage de Gentoo para MIPSel. Como no podía ser de otra manera, tiré por la segunda 🙂 Por supuesto, es la primera vez que lo hago, así que, aunque me ha funcionado, puede ser que haya metido la pata en algo, o que alguna cosa se pueda hacer mejor, así que los comentarios están abiertos para cualquier sugerencia o corrección.
AVISO: a partir de aquí empiezo a tocar en el sistema operativo del disco duro multimedia, lo que significa que estas acciones sólo las deben realizar aquellos que sepan muy bien lo que hacen. Si alguien se carga su disco, será el único responsable.
Avisados estáis.
Lo primero que hice fue instalar una Gentoo para x86 en mi sistema. Pero como no quería formatear mi actual Ubuntu, decidí hacer una instalación virtual. Veamos como:
Para empezar, descargamos las versiones más recientes del stage3 y el portage de Gentoo, y las descomprimimos en un directorio (el portage se descomprime dentro del directorio /usr del stage3), en mi caso llamado gentoo:
mkdir /home/raster/gentoo sudo tar -xjvf stage3-i686-20090915.tar.bz2 -C /home/raster/gentoo/ sudo tar -xjvf portage-lastest.tar.bz2 -C /home/raster/gentoo/usr/
La razón de utilizar sudo es que, si no, no podrá crear algunos ficheros especiales en el directorio.
A continuación montamos una copia de los sistemas de archivos especiales de Linux (/proc, /dev, /dev/pts y /sys), además de copiar el fichero resolv.conf para poder conectarnos a Internet. Sin ellos no podríamos hacer muchas cosas básicas:
sudo mount -o bind /proc /home/raster/gentoo/proc sudo mount -o bind /dev /home/raster/gentoo/dev sudo mount -o bind /dev/pts /home/raster/gentoo/dev/pts sudo mount -o bind /sys /home/raster/gentoo/sys sudo cp /etc/resolv.conf /home/raster/gentoo/etc/resolv.conf
Notar el parámetro -o bind en mount: lo que hace es coger un sistema de archivos ya montado y montarlo también en el nuevo directorio, de manera que esté disponible en ambos a la vez.
Por último, hacemos un chroot para entrar en el sistema:
sudo chroot /home/raster/gentoo/ /bin/bash
Ya estamos dentro de nuestra Gentoo, pero antes de empezar tenemos que cargar el entorno:
env-update source /etc/profile
Con ésto ya podemos empezar a trabajar. Lo primero es actualizar todo el sistema a los últimos paquetes, para lo que hacemos:
emerge --sync emerge --update --deep world
Y ya podemos empezar a crear nuestro stage. Lo primero es instalar crossdev, un paquete que automatiza la generación de entornos de compilación cruzada (la documentación oficial está aquí y aquí):
emerge portage-utils crossdev
A continuación, editamos el fichero /etc/make.conf y añadimos la línea PORTDIR_OVERLAY=/usr/local/portage (podemos utilizar el editor nano, o vi) y, opcionalmente, la línea MAKEOPTS=»-jX» (siendo X el número de procesadores más 1; yo, como tengo un doble núcleo, uso -j3). Por último, creamos el directorio /usr/local/portage, y ya podemos generar un compilador para MIPSel, linux, y uclibc:
crossdev -v --target mipsel-unknown-linux-uclibc
Las distintas combinaciones de procesadores, núcleos y bibliotecas están en la documentación de crossdev, en una tabla.
Se tirará un buen rato compilando, tras el cual podemos comprobar si todo fue correctamente con:
gcc-config -l
En mi caso devuelve:
[1] i686-pc-linux-gnu-4.3.2 * [2] mipsel-unknown-linux-uclibc-4.3.4 *
Con este toolchain podremos compilar cosas de manera nativa pra el disco duro. Para probarlo escribimos el típico Hola mundo y lo compilamos con:
mipsel-unknown-linux-uclibc-gcc -o holamundo holamundo.c
lo copiamos al disco duro multimedia y probamos a ejecutarlo. Debería funcionar a la primera.
Una vez que tenemos el toolchain para compilación cruzada, vamos a crear nuestra stage. Para ello tenemos que instalar el paquete crossdev-wrappers, tal y como se explica en su página, e inicializarlo. Por desgracia, por defecto está enmascarado, así que tenemos que desenmascararlo para que podamos instalarlo. Para ello escribimos:
echo "sys-devel/crossdev-wrappers ~* *" >> /etc/portage/package.keywords/i686-unknown-linux-gnu
Asumiendo, por supuesto, que /etc/portage/package.keywords es un directorio. Si es un fichero, entontes sería
echo "sys-devel/crossdev-wrappers ~* *" >> /etc/portage/package.keywords
Ahora ya podemos instalar crossdev-wrappers:
emerge crossdev-wrappers emerge-wrapper --init
Este paquete nos permite instalar cualquier paquete de Gentoo, pero compilándolo para el sistema para el que tenemos compilador cruzado, e instalando el sistema de archivos en un directorio aparte (por defecto en /usr/arquitectura; o sea, /usr/mipsel-unknown-linux-uclibc en este caso), que podremos comprimir con tar e instalar en el sistema destino. Pero antes de empezar a utilizarlo tenemos que configurarlo adecuadamente. Lo primero es editar el fichero /usr/mipsel-unknown-linux-uclibc/etc/make.conf y ajustarlo a nuestros intereses. En mi caso, por defecto estaba así:
CHOST=mipsel-unknown-linux-uclibc CBUILD=i686-pc-linux-gnu ARCH=mips HOSTCC=i686-pc-linux-gnu-gcc E_MACHINE=EM_MIPS ROOT=/usr/${CHOST}/ ACCEPT_KEYWORDS="mips ~mips" USE="${ARCH} zlib bindist make-symlinks minimal" #MARCH_TUNE="-march=armv4t -mtune=arm9tdmi" #arm-softfloat-linux-uclibc #MARCH_TUNE="-march=armv5t -mtune=xscale" #armv5teb-softfloat-linux-gnueabi CFLAGS="-Os -pipe ${MARCH_TUNE} -fomit-frame-pointer -I${ROOT}usr/include/ -I${ROOT}include/" CXXFLAGS="${CFLAGS}" LDFLAGS="-L${ROOT}lib -L${ROOT}usr/lib" FEATURES="-collision-protect sandbox buildpkg noman noinfo nodoc" # Be sure we dont overwrite pkgs from another repo.. PKGDIR=${ROOT}packages/ PORTAGE_TMPDIR=${ROOT}tmp/ ELIBC="glibc" PKG_CONFIG_PATH="${ROOT}usr/lib/pkgconfig/" #PORTDIR_OVERLAY="/usr/portage/local/" LIBDIR_${ARCH}="lib" LIBDIR_amd64=lib64 MAKEOPTS=-j2
Hay varios cambios a realizar. Para empezar, hay que añadir MARCH_TUNE=»-march=4kec», de manera que optimicemos para el procesador específico de mi disco duro (esto hay que cambiarlo para el modelo específico del procesador del disco duro que se quiera utilizar). Por otro lado, hay que cambiar MAKEOPTS=-j2 por MAKEOPTS=-j3, porque yo tengo dos núcleos. Al final tenemos:
CHOST=mipsel-unknown-linux-uclibc CBUILD=i686-pc-linux-gnu ARCH=mips MARCH_TUNE="-march=4kec" HOSTCC=i686-pc-linux-gnu-gcc E_MACHINE=EM_MIPS ROOT=/usr/${CHOST}/ ACCEPT_KEYWORDS="mips ~mips" USE="${ARCH} zlib bindist make-symlinks minimal" CFLAGS="-Os -pipe ${MARCH_TUNE} -fomit-frame-pointer -I${ROOT}usr/include/ -I${ROOT}include/" CXXFLAGS="${CFLAGS}" LDFLAGS="-L${ROOT}lib -L${ROOT}usr/lib" FEATURES="-collision-protect sandbox buildpkg noman noinfo nodoc" # Be sure we dont overwrite pkgs from another repo.. PKGDIR=${ROOT}packages/ PORTAGE_TMPDIR=${ROOT}tmp/ ELIBC="glibc" PKG_CONFIG_PATH="${ROOT}usr/lib/pkgconfig/" #PORTDIR_OVERLAY="/usr/local/portage" LIBDIR_${ARCH}="lib" LIBDIR_amd64=lib64 MAKEOPTS=-j3
También hay que ajustar el perfil deseado. Por defecto nos ha puesto embedded, que es perfecto para nuestro caso; pero si queremos cambiarlo basta con borrar /usr/mipsel-unknown-linux-uclibc/etc/make.profile y enlazarlo al perfil deseado de los disponibles en /usr/portage/profiles.
Y ya sólo queda por compilar todos los paquetes que queramos, utilizando el comando emerge-mipsel-unknown-linux-uclibc. Así, el primero que, probablemente, queramos instalar será system.
emerge-mipsel-unknown-linux-uclibc system
que instalará BusyBox con todas las librerías de uClinux. Una vez hecho esto sólo tenemos que crear los directorios que faltan con:
cd /usr/mipsel-unknown-linux-uclibc mkdir dev proc root sys
y ya tendremos un sistema de ficheros que podremos probar. Para ello basta con empaquetarlo con tar (no comprimirlo, porque al menos mi disco duro no tiene ni gzip ni bzip2), descomprimirlo en el disco duro, montar proc, dev, dev/pts y sys como al principio de esta entrada, copiar /etc/resolv.conf y hacer un chroot, aunque esta vez con /bin/ash, porque busybox no dispone de bash.
Otra cosa que podemos hacer es añadir en/usr/mipsel-unknown-linux-uclibc/etc/make.conf una línea USE con las opciones que nos interesen de cara a compilar (opciones que se pueden consultar aquí).