Notas para compilar el kernel linux del m740av
a partir de los fuentes proporcionados por Siemens

Versión: 2.0 Diciembre 2006
Autor: Juan Antonio Martínez < jonsito en teleline punto es >

Indice

  1. Copyright. Registro de Cambios
  2. Requisitos
  3. Creando el entorno de compilación
  4. Compilando el kernel
  5. Compilando módulos
  6. Instalando un nuevo kernel en el firmware

Este documento indica todos los pasos que he seguido para compilar el kernel-2.4.21-xfs proporcionado por Siemens para el gigaset m740av en un entorno de desarrollo cruzado bajo Linux Fedora Core 5

Se incluye tambien documentacion sobre cómo compilar módulo adicionales, mediante dos ejemplos: fuse y cddafs, así como una versión preliminar de las instrucciones para incluír un nuevo kernel en la imagen de firmware

Este no es un documento sencillo: se requiere experiencia en el entorno de desarrollo Linux, así como conocimientos sobre cómo compilar un núcleo Linux nativo en un PC.


Copyright. Registro de cambios

Este documento es copyright 2006 de Juan Antonio Martínez Castaño.

Se autoriza su libre copia y distribución en cualquier formato, incluyendo medios electrónicos siempre y cuando se conserve integra su literalidad, especialmente en esta nota de copyright

Se autoriza su modificación, y la distribución de copias modificadas, siempre que dicha copia incluya una cláusula indicando su calidad de trabajo derivado, haga mención al autor original y proporcione un enlace al documento original

Registro de cambios del documento

Versión 2.0 15-Dic-2006

Versión 1.0 15-Nov-2006 La versión 1.0 de documento tiene su origen en unas notas escritas por Miguel A. Díaz
NOTES TAKEN REGARDING THE GIGASET M740AV FIRMWARE DEVELOPMENT

Avisos legales

Volver al índice

Requisitos

Necesitaremos:

Antes de empezar, es recomendable leer en su totalidad el documento, y entender perfectamente qué se hace en cada paso. El lector deberá en su caso adaptar los comandos que se indican, ajustando los directorios y variables a su caso concreto

Volver al índice

Creando el entorno de compilación

En esta primera fase, creamos el espacio de trabajo, descargamos las aplicaciones necesarias, las compilamos e instalamos

Al contrario que en un procedimiento normal para construír una cross-toolchain, para compilar el kernel no es preciso compilar la glibc/uClibc, o compilar el entorno de desarrollo completo C/C++. Recordemos que el kernel está escrito enteramente en C/ensamblador, y no utiliza librerías externas

La pregunta obvia: si ya existe un paquete para desarrollos cruzados para el M740AV, por qué no utilizarlo... Doy fe de que lo he hecho... y no funciona: si bien puedes compilar e instalar tanto el kernel como los diversos módulos, el API binario entre el egcs-1.1.2 y el gcc-3.2 es "ligeramente" distinto, pero lo suficiente como para que no pueda interrelacionar con el kernel que proporciona Siemens.
Es pues preciso utilizar el mismo kernel y el mismo compilador que el que utiliza Siemens, y de ahí el tener que desarrollar una toolchain propia

Veremos un ejemplo de lo anterior a la hora de compilar el módulo fuse (Filesystem in User Space). Esta aplicación tiene dos partes: un módulo del kernel, y una aplicación de usuario, que deben ser compiladas de manera separada y con distintas toolchains

Creamos entorno de trabajo

Seleccionamos un directorio con permisos de escritura y al menos 2 Gigas de disco duro. En nuestro caso lo denominamos "BASEDIR"
root# yum install compat-gcc-32
root# export BASEDIR=/path/al/directorio/base/donde/voy/a/trabajar
root# mkdir -p ${BASEDIR}
root# cd ${BASEDIR}
root# mkdir -p toolchain sources
root# export PREFIX=${BASEDIR}/toolchain
root# export TARGET=mips-linux
root# cd ${BASEDIR}/sources
root# wget http://oasis.dit.upm.es/~jantonio/m740av/egcs-1.1.2.src.tar.bz2
root# wget http://oasis.dit.upm.es/~jantonio/m740av/egcs-1.1.2.diff.gz
root# wget http://oasis.dit.upm.es/~jantonio/m740av/binutils-2.16.1.src.tar.bz2
root# wget http://oasis.dit.upm.es/~jantonio/m740av/depmod.pl
root# wget http://oasis.dit.upm.es/~jantonio/m740av/gigaset_m740av_gplsw_1495_14711CF.tar.bz2

Compilación de las binutils

Preparamos, compilamos e instalamos as, ld, ar, strip, y demás utilidades
root# tar jxvf sources/binutils-2.16.1.src.tar.bz2
root# cd binutils-2.16.1
root# CC=gcc32 ./configure --target=$TARGET --prefix=$PREFIX --disable-nls
root# CC=gcc32 make all install
root# cd ..

Compilación de egcs-1.1.2

Preparamos, compilamos e instalamos el compilador egcs-1.2
root# tar jxvf sources/egcs-1.1.2.src.tar.bz2
root# cd egcs-1.1.2/
root# zcat ../sources/egcs-1.1.2.diff.gz | patch -p1
root# CC=gcc32 ./configure --target=$TARGET --prefix=$PREFIX --disable-nls \
--enable-languages=c --without-headers --with-newlib --with-gnu-as --with-gnu-ld
root# PATH=$PATH:$PREFIX/bin make all-gcc LANGUAGES="c" CFLAGS=-DSYS_SIGLIST_DECLARED
root# PATH=$PATH:$PREFIX/bin make install-gcc LANGUAGES="c" CFLAGS=-DSYS_SIGLIST_DECLARED
root# cd ..

Con esto ya tenemos preparado el cross-toolchain para poder compilar el kernel

Volver al índice

Compilando el núcleo

En esta fase vamos a extraer los fuentes del kernel de Siemens, instalarlos en nuestro directorio de trabajo, y proceder a compilarlo, generando de paso una serie de módulos que no vienen de serie y que nos pueden ser útiles

En su momento lo volveremos a repetir, pero nunca estará de msáas: NUNCA, NUNCA, BAJO NINGUN CONCEPTO debemos cambiar las opciones que vienen de serie en aquellas partes del kernel que no vengan en la configuración por defecto definidas como módulos. Podemos añadir, reconfigurar y quitar módulos, pero nada más

De no hacerlo así, romperíamos las dependencias de símbolos que el kernel precompilado que ofrece Siemens incluye, y no podríamos hacer insmod de nuestros módulos. O mucho peor aún: si cambiáramos el kernel que ofrece Siemens, no funcionarían los módulos propietarios que Siemens ha compilado... con lo que nuestro gigaset se convertiría en una chatarra muy cara....

Por ejemplo: podemos añadir como módulo el soporte para una webcam, pero no podemos INCLUIR dicho soporte en el kernel. Del mismo modo, el soporte SCSI viene incluído en el kernel, por lo que no podemos extraerlo y ponerlo como módulo

Otro detalle adicional: aunque podemos compilar muchos drivers como módulos, no siempre podremos utilizarlos.... pues es necesario que exista una entrada /dev en el root filesystem para acceder a ellos

Por ejemplo: podemos añadir el módulo iso9660 para soporte de sistema de ficheros ISO9660 ( CD-Rom ), con lo que podrémos montar imágenes ISO... en modo loop. Pero si queremos montar un CD-ROM, necesitaremos el módulo cdrom... que necesita a su vez e módulo sr_mod, y que a su vez necesita la entrada /dev/scd0 en el root filesystem

Se sugiere pues, conocimientos sobre generación de nuevos firmwares y cambios del rootfs en el gigaset...

Pasos previos:

Crear un directorio de trabajo
Descomprimir y extraer los fuentes del kernel

root# mkdir -p toolchain/usr/src
root# tar jxvf sources/gigaset_m740av_gplsw_1495_14711CF.tar.bz2
root# ( cd gigaset_m740av_gplsw/linux-2.4-xfs ; tar cfBp - linux ) | ( cd toolchain/usr/src; tar xfBp - )

Nos vamos al directorio de trabajo y ajustamos los nombres con el convenio "estandard"

root# cd ${BASEDIR}/toolchain/usr/src
root# mv linux linux-2.4-xfs && ln -s linux-2.4-xfs linux
root# cd linux

Preparación

Hacemos una copia de seguridad de la configuracion original. De esta manera, ante "desastres" siempre podemos dejarlo como estaba...

root# cp .config config.Siemens

Ponemos el directorio drivers/usb correcto. Parece ser que Siemens utiliza una versión propia de los drivers USB. A la hora de realizar el "make modules_install", el Depmod se encuentra con problemas de dependencias, que se soluciona poniendo los nombres de los subdirectorios correctos:

root# mv drivers/usb drivers/usb.back
root# mv drivers/usb.2.4.21 drivers/usb

Toqueteamos los Makefiles para arreglar los paths, de manera que apunten a nuestra toolchain. Por si acaso, hacemos copias de seguridad

root# cp Makefile Makefile.orig
root# cp arch/mips/Makefile arch/mips/Makefile.orig
root# vi Makefile arch/mips/Makefile

Los cambios son muy simples:

Comprobamos que los includes están correctos. Para ello debemos asegurarnos que el fichero include/asm-mips/setup.h exista ( aunque esté vacío ) y que exista el enlace simbólico include/asm apuntando a include/asm-mips

root# [ -f include/asm-mips/setup.h ] || touch include/asm-mips/setup.h
root# ln -sfn include/asm-mips include/asm

Editamos configuración del linker para adaptarlo a nuestras binutils

root# vi arch/mips/ld.script.in

Donde pone 'OUTPUT_FORMAT("elf32-bigmips")' ( primera linea )
debe poner 'OUTPUT_FORMAT("elf32-big")'

Con esto ya tenemos preparados los fuentes para empezar a trabajar. En sentido estricto alguno de estos cambios no son necesarios ( en concreto el enlace simbólico asm -> asm-mips ), pero dado que venían en la documentación original, he preferido mantenerlos....

Modificacion de configuracion estandard

Ahora es cuando de verdad vamos a empezar a trabajar:
Vamos a compilar el kernel, añadiendo varios módulos nuevos:

Para ello, seguimos el procedimiento estandard que ya conocen todos aquellos que alguna vez han compilado un kernel linux

Volvemos a recordar: NUNCA SE DEBE MODIFICAR LA CONFIGURACION ESTANDARD, sino solamente añadir o borrar módulos

Hacemos limpieza y restauramos la configuración que nos da Siemens:

root# make distclean
root# cp config.Siemens .config

Lanzamos "make menuconfig" y ajustamos las nuevas opciones:

root# make menuconfig

Activar "keyboard", "mouse" y "event interface" como módulos
Activación del input layer (/dev/input)

Input core support -> ( activar como módulo )
  <M> Input core support
  <M>   Keyboard support
  <M>   Mouse support
  (720)    Horizontal screen resolution (NEW)
  (576)    Vertical screen resolution (NEW)
  < >   Joystick support
  <M>   Event interface support 

Activación de dispositivos HID por USB

Usb support -> ( buscar USB Human Interface Devices ) y habilitar:
  ....
  --- USB Human Interface Devices (HID)
  <M>   USB Human Interface Device (full HID) support 
  [*]     HID input layer support
  [*]     /dev/hiddev raw HID device support
  <M>   USB HIDBP Keyboard (basic) support
  <M>   USB HIDBP Mouse (basic) support
  ....  

Por último añadimos el soporte para iso9660 y UDF

--- File systems
....
 <M> Journalling Flash File System v2 (JFFS2) support
 (0) JFFS2 debugging verbosity (0 = quiet, 2 = noisy)
 <*> Compressed ROM file system support
 [ ] Virtual memory file system support (former shm fs)
 <M> ISO 9660 CDROM file system support
 [*]   Microsoft Joliet CDROM extensions
 [ ]   Transparent decompression extension
 < > JFS filesystem support
 < > Minix fs support
....
 < > ROM file system support
 <*> Second extended fs support
 < > System V/Xenix/V7/Coherent file system support
 <M> UDF file system support (read only)
 [ ]   UDF write support (DANGEROUS)
 < > UFS file system support (read only)
 <M> XFS filesystem support
 [ ]   ACL support
....  

Volvemos a insistir: NUNCA marcar con <*> ( insertar en el kernel ) ninguna opción nueva, ni modificar o eliminar ninguna opción así marcada en la configuración que nos ofrece Siemens. Solo se puede añadir/borrar/editar lo marcado con <M> (módulo)

De lo contrario, todo nuestro trabajo no solo no servirá para nada, sino que nos podemos cargar el gigaset...

Guardamos la configuracion por si acaso en un fichero "config.mine" Salimos guardando nueva configuración

Compilación

Por fin: vamos allá:

root# make dep; make clean; 
root# make vmlinux
root# make modules
root# make modules_install

Tras este proceso se obtiene:

El make modules_install nos pone todo en /lib/modules/linux-2.4-xfs.
No obstante falla al hacer el depmod -a, por lo que habrá que hacerlo a mano:

No debe dar ningún error. En caso de que lo dé, (unresolved symbols) es que hemos hecho algo mal.... :-(

Una vez comprobado que no hay errores, lo guardamos en el fichero modules.dep, añadimos el fichero System.map, y creamos un paquete tar.gz con los modulos, listo para ser transferido al Gigaset m740av

root# /tmp/depmod.pl -F System.map -k vmlinux -b /lib/modules/2.4.21-xfs >/lib/modules/2.4.21-xfs/modules.dep
root# cp System.map /lib/modules/2.4.21-xfs/System.map
root# tar zcvf modules-2.4.21-xfs.tar.gz -C / lib/modules/2.4.21-xfs

Evidentemente el directorio /lib/modules/2.4.21-xfs, aunque se ha instalado en el lugar estándar para los módulos del kernel, no es utilizable por nuestro sistema nativo :-), por lo que puede ser borrado

Un problema común relacionado con la aparición de mensajes de unresolved symbols está relacionado con la implementación de Siemens del stack USB: si en "make menuconfig" se habilitan los módulos USB serial devices, dichos módulos mostrarán dependencias fallidas. Por ello es preferible no habilitar dicha opción

Esto es todo amigos. Ahora solo queda copiar el /lib/modules/2.4.21-xfs al disco duro del gigaset, y probar con insmod y rmmod que podemos cargar y descargar dichos modulos sin problemas.

Volver al índice

Compilando módulos externos

Ahora que ya sabemos cómo compilar el kernel, vamos a darle una vuelta de tuerca y aprender a compilar módulos externos. Para ello hemos escogido dos módulos representativos del trabajo y modificaciones que hay que hacer para realizar compilaciones cruzadas

Una observación: para compilar un módulo externo no es estrictamente necesario haber realizado todo el proceso de compilación del kernel: basta con llegar a la ejecución de "make menuconfig", de manera que se hayan creado todos los ficheros de configuración necesarios en el árbol de directorios

Otro detalle: evidentemente, la mayor parte de los módulos externos pueden integrarse sin problemas en el árbol de directorios del fuente del kernel; pero esto violaría nuestra política de "no-intrusión". Por ello en todos los casos vamos a compilarlos de manera separada al kernel

Caso 1: el módulo cddafs

CDDA FS es un módulo que permite montar un CD de manera que cada una de las pistas se ve como un fichero. Es especialmente útil en los discos multisesión, en los que puedes ver cada sesión por separado, o -sobre todo- en los CD's de audio, en los cuales cada canción es vista como un fichero .wav

La página web del proyecto cddafs es
http://www.ii.pw.edu.pl/~borkowsm/cdfs.htm

En este ejemplo nos encontramos con un problema típico: las versiones actualizadas sólo funcionan en el kernel 2.6.X, y no existe una versión para el kernel 2.4.21
Esto significa que deberemos modificar el makefile para engancharlo a nuestro kernel, y que se pueda compilar de forma independiente

Descargamos y descomprimimos el código fuente de cddafs

root# cd ${BASEDIR}/sources
root# wget ftp://ftp.ii.pw.edu.pl/pub/opensource/cdfs/cddafs035.tgz
root# cd ${BASEDIR}
root# tar zxvf sources/cddafs035.tgz
root# cd cddafs-0.35

Hacemos una copia de seguridad del makefile original y creamos el nuestro

root# cp Makefile Makefile.orig
root# cat <<__EOF >Makefile
# KERNEL = /media/disk/m740/kernel-toolchains/toolchain/usr/src/linux

O_TARGET := cddafs.o

obj-y := main.o file.o dir.o
obj-m := $(O_TARGET)
include $(TOPDIR)/Rules.make

clean:
	rm -f *.o

cddafs.o: main.o file.o dir.o
main.o: main.c cddafs.h
file.o: file.c cddafs.h
dir.o: dir.c cddafs.h

__EOF
root# 

La modificación anterior al Makefile, se debe a que estos fuentes están preparados para una versión distinta de kernel, y además presupone que se iba a incluír como parche en los fuentes. Como aplicamos el principio de no intrusión, y vamos a realizar una compilación separada, hay que hacer este cambio, que estandariza el formato del makefile al kernel 2.4.21

Pronunciamos el conjuro mágico, que debería ser el mantra de todo compilador de módulos:

root# make -C ${BASEDIR}/toolchain/usr/src/linux SUBDIRS=$PWD modules

Esto es, le decimos al kernel que compile como módulo... lo que encuentre en nuestro subdirectorio

Tras la compilación, Obtendremos un precioso fichero cddafs.o objeto de nuestros amores :-). Para instalarlo, bien podemos copiarlo directamente al gigaset y hacer un "insmod" a pelo, o mejor, incluirlo en nuestro árbol de módulos que hemos creado bajo /lib/modules/2.4.21-xfs:

root# mkdir -p /lib/modules/2.4.21-xfs/kernel/fs/cddafs
root# cp cddafs.o /lib/modules/2.4.21-xfs/kernel/fs/cddafs/cddafs.o

Ejecutando de nuevo depmod.pl actualizamos la lista de dependencias, que aunque en este caso no es estrictamente necesario, pues nunca está de más

En ocasiones el "make" falla con exóticos mensajes de ficheros no encontrados... En un 99% de los casos, se debe a que no hemos llegado a ejecutar el "make menuconfig" en los fuentes del kernel, o bien hemos hecho un "make distclean"

Esto es todo. Dependiendo del módulo, el trabajo será mas o menos sencillo. lo normal es que haya que editar el Makefile, retocar algún path... y pronunciar las palabras mágicas :-)

Caso 2: el módulo fuse

FUSE ( Filesystem in USEr space ) es un módulo "puente" que permite a aplicaciones que se ejecuten en espacio de usuario "simular" un sistema de ficheros. Aplicación típica es el sistema de ficheros CIFS, una versión mejorada del smbfs ( sistema de ficheros de red que utilizan los entornos windows )

Fuse puede ser obtenido en su página web: http://fuse.sourceforge.net/

Este ejemplo supone un problema añadido:

La solución consiste en realizar la compilación en dos pasos: módulo y aplicaciones

Compilación del módulo del kernel

Descargamos y descomprimimos el codigo fuente:

root# cd ${BASEDIR}/source
root# wget http://puzzle.dl.sourceforge.net/sourceforge/fuse/fuse-2.5.3.tar.gz
root# cd ..
root# tar zxvf sources/fuse-2.5.3.tar.gz
root# cd sources/kernel

Ejecutamos "configure" indicando dónde residen los fuentes del kernel, y habilitando la compilacion del módulo

./configure --with-kernel=${BASEDIR}/toolchain/usr/src/linux --enable-kernel-module

Editamos el Makefile, adaptándolo a las peculiaridades del código fuente de Siemens. Debe quedar de la siguiente manera:

.....
# CC = gcc
# LD = ld
# CFLAGS = -O2 -Wall -Wstrict-prototypes -fno-strict-aliasing -pipe -msoft-float
# CPPFLAGS = -I../../toolchain/usr/src/linux/include -I. -D__KERNEL__ -DMODULE -D_LOOSE_KERNEL_NAMES -DFUSE_VERSION=\"$(VERSION)\"

fuse_objs = dev.o dir.o file.o inode.o compat/parser.o

SUFFIXES = .c .o .s

modules: all-spec
all-spec: fuse.o

.c.o:
        $(CC) $(CFLAGS) $(CPPFLAGS)  -DFUSE_VERSION=\"$(VERSION)\" -c $< -o $@
.....
Los cambios consisten en:

Pronunciamos el conjuro, y se compila el módulo:
make -C ${BASEDIR}/toolchain/usr/src/linux SUBDIRS=$PWD modules

Compilación de las aplicaciones de espacio de usuario

Presuponemos que el lector es ya un experto en compilación cruzada de aplicaciones, y que tiene correctamente instalado el paquete de compilación cruzada para el Gigaset M740AV.
En caso negativo, me temo que esta documentación le será poco mas que inútil....

Supongamos pues que el paquete m740av-xgcc-1.8.2.zip ha sido descargado, e instalado correctamente.
Sea /usr/local/mips-linux el directorio base de instalación del entorno de desarrollo cruzado

Creamos el siguiente script:

#!/bin/bash

export BASE=/usr/local/mips-linux
export PATH=$PATH:${BASE}/bin
# export INSTALL_DIR=/where/to/install/package

AR=mips-uclibc-ar \
AS=mips-uclibc-as \
CC=mips-uclibc-gcc \
CPP=mips-uclibc-cpp \
CXX=mips-uclibc-g++ \
LD=mips-uclibc-ld \
NM=mips-uclibc-nm \
OBJCOPY=mips-uclibc-objcopy \
OBJDUMP=mips-uclibc-objdump \
RANLIB=mips-uclibc-ranlib \
SIZE=mips-uclibc-size \
STRINGS=mips-uclibc-strings \
STRIP=mips-uclibc-strip \
CPPFLAGS="-I${BASE}/usr/include -I${BASE}/include " \
LDFLAGS="-L${BASE}/usr/lib -L${BASE}/lib " \
./configure --host=mips-linux --build=i386-linux \
        --prefix=$INSTALL_DIR/usr \
        --sysconfdir=$INSTALL_DIR/etc \
        --localstatedir=$INSTALL_DIR/var \
        --infodir=$INSTALL_DIR/usr/share/info \
        --mandir=$INSTALL_DIR/usr/share/man \
        $*
y lo guardamos con el nombre de "configure.sh". Este script lo ejecutaremos en lugar del "configure" que nos aparece en el paquete "fuse". Realmente es un wrapper que invoca a éste último, ajustando variables de entorno y directorios de instalació
Recomiendo al lector que guarde este script: le será muy útil para configurar y cross-compilar muchas otras aplicaciones

Ejecutamos nuestro "configure" añadiendo algunos parámetros extras que necesita fuse:

root#  CFLAGS="-D_FILE_OFFSET_BITS=64 -DUSE_UCLIBC" ./configure.sh --disable-kernel-module --enable-lib --enable-util --disable-mtab
Donde se le dice que:

Una vez hecho esto, basta con ejecutar "make"

root# PATH=$PATH:/usr/local/mips-linux/bin make
Se debe compilar sin más problemas

Instalación del módulo fuse

Ya casi hemos acabado. Ahora vamos a generar un paquete que incluya todo lo relacionado con la aplicación fuse. Para ello vamos a crear un directorio temporal donde hacer el "make install", y vamos a generar un tar.gz con el contenido de dicho directorio.

Creamos directorio temporal de instalación: y ejecutamos install

root# mkdir /tmp/packages
PATH=$PATH:/usr/local/mips-linux/bin make DESTDIR=/tmp/packages install

Copiamos al directorio de instalación el módulo del kernel:

root# mkdir -p /tmp/packages/lib/modules/2.4.21-xfs/kernel/fs/fuse
root# cp kernel/fuse.o /tmp/packages/lib/modules/2.4.21-xfs/kernel/fs/fuse/fuse.o

Y !por fin! generamos un tar.gz con el paquete, que podemos descargar e instalar en el gigaset, y borramos directorio temporal:

root# tar cvf fuse-m740av-2.5.3.tar.gz -C /tmp/packages *
root# rm -rf /tmp/packages
El paquete que hemos creado contiene:

El último paso consiste -evidentemente- en transferir este paquete .tar.gz al gigaset, descomprimirlo, y comprobar que "insmod fuse" funciona

Volver al índice

Instalando un nuevo kernel en el firmware

Queda la última parte de la historia: generar un .wsw con nuestro nuevo y flamante kernel, y los nuevos y flamantes módulos que nos interesen pero esa es otra historia que deberá ser contada en su momento... ( cuando aprenda cómo se hace :-)

PENDIENTE DE ESCRIBIR

Volver al índice