Beyond Logic


uClinux - Setting up the Development Environment
Why Embed Linux?

    Linux is fast proving to be a popular operating system for embedded network devices. Just some of the many advantages are listed below.

      • Royalty free licensing. With traditional off the shelf embedded platforms there would be a significant licensing cost involved in shipping devices with a third party OS. This eats into your margins and contributes to a higher priced device. Linux, on the other hand is free.

      • Reliable IP stack and TCP/IP Applications. Linux comes with some of the most established TCP/IP stacks and applications. Linux has been on some servers and desktops for years. This same code base has now made it to your embedded systems.

      • Source code for the OS Kernel is Open. How many times have you developed software which relies on third party code, only to find the third party code is buggy? When you consult the vendor, they either are not interested or take weeks or months to release a patch. With linux, you have the source code in your hot little hands. You can get in and fix any bugs and recompile it. What more you can contribute your patches to the community which results in a more polished and stable kernel, benefiting everyone involved.

      • Source code for the Toolchains is Open. Toolchains are a name for the development tools which are used to compile the kernel and usermode applications. Once again you have the source code for these applications. While most developers these days expect to have buggy development tools, you have the source to fix it, and the power to fix it.

      • Time to market. With an abundance of open source code and applications aimed at linux, you will find time to market is decreased. Take for example the Memory Fax/Modem products which appeared on the market a couple years back. These units were a fax/modem with memory which allowed it to recieve faxes when your computer was switched off. To place such a product on the market would of required a reasonable amount of work. However with uClinux, the developer can base their product on open source code such as efax. It also allows the ability to include IP Masquerading with little effort, thus adding more functionality to the product.. Linux also supports a large range of peripherals and file systems.

    With all these advantages, there are many target platforms and this is continuing to grow. uClinux now supports the 68328 dragonball series, Coldfire, ARM7TDMI, ETRAX, I960.

uClinux Distribution

    uClinux is the most popular form of embedded linux. uClinux (MicroController Linux) was first ported to the Dragonball 68k series processors in 1998 has since grown exponentially to include a wide range of targets. uClinux differs from its mainstream linux counterparts by having no support for memory management units (MMU). The other important part of uClinux is a small footprint, which is essential for microcontrollers with little resources and it's BFLT (Binary Flat) Executable Format.

Kernel 2.0.38

    The uClinux Kernel is where all the fuss is made. It is based on the 2.0.38 Linux kernel. Linux-2.0.38.tar.gz is the original kernel you would use on your desktop computer. A uClinux patch is applied to bring the kernel up to a level where it can be used on your microcontroller. This typically involves the device support and removing the reliance on the MMU. Download the tarballs and place them in /opt/uClinux. Unpack and patch the kernel. You will need to create the uClinux directory.

    	cd /opt/uClinux
    	tar xzf linux-2.0.38.tar.gz		
    	gzip d uClinux-2.0.38.1pre7.diff.gz
    	cd linux
    	patch -p1 < ../uClinux-2.0.38.1pre7.diff
    

    Once this is done, you now have yourself the code base for the uClinux Kernel. However you will now need to build a compiler which can cross compile the code to M68K. Later in the uC-libc building, it will try to include files in linux/include/asm. "asm" is an symbolic link which points to a folder asm-, where arch is the architecture of the kernel. For example if we configure uClinux for m68k with no mmu, the asm folder will point to asm-m68knommu.

    This is therefore a good place to start by configuring the kernel which can be done without needing the m68k-coff compiler.

    	make menuconfig
    

    The default configuration is for the uCSimm thus if you have other boards will need to configure it for your desired target. There is no need to build the kernel, in fact you can't build the kernel yet due to a lack of development tools. The make config will set up the asm links which are required laterfor the building of the standard c library, uC-libc.

Toolchains

    There are two different tool chains for uCLinux. One is used for the compilation of the kernel and produces 32 bit M68K fixed position executables. The other is used for compilation of user-land binaries and produces 32 bit M68K position independent code (PIC).

    The kernel chain tool is nothing more than the standard run of the mill gcc version 2.7.2.3. The kernel diff makes one small modification to the /config/m68k/t-m68kbare file inserting TARGET_LIBGCC2_CFLAGS = -Dinhibit_libc to prevent it from requiring a libc library.

    The user-land chain tool is a different matter. It has some quite extensive changes. These changes lie with the requirement to have position independent binaries. No direct jumps are used, but instead these are replaced with relative branches. Global data is retrieved relative to the A5 register.

    Two options are given for building the tool chains. You can download uClinuxgcc-kit-160899.tar.gz which contains all the patches and a makefile which automatically builds the binutils and gcc for both the kernel and user environments. The other option is to patch and build the tools yourself and in the process learn what is happing along the way. We detail both methods here.

Building the tool chains the easy way

    Download the following

    Extract uClinuxgcc-kit-160899.tar.gz. The buildtools can be built in any directory, independent of /opt/uClinux

    	tar -xzf uClinuxgcc-kit-160899.tar.gz 
       	cd uclinuxgcc-kit-160899
    

    Edit the Makefile (first line) changing the INSTALLDIR to a suitable destination - /opt/uClinux is recommended. Then make the m68k-coff and m68k-pic-coff tool chains by typing,

    	make
    

    This creates the executables in /opt/uClinux/bin which is not in the current path. Therefore we could either add /opt/uClinux/bin to the path, or link our newly created binaries to /usr/bin.

    	cd /opt/uClinux/bin
    	ln -f * /usr/bin
    

    Now that was easy, wasnt it? Now that we have boosted your confidence, lets walk through what is happing by examining the manual version.

Manually Building the Tool Chains - m68k-coff

    We will start by building the M68K fixed position tools, m68k-coff. Download

    Extract the binutils src tarball to a suitable directory of your choice and enter its directory

    	tar xzf binutils-2.9.1.tar.gz
    	cd binutil-2.9.1
    

    Configure binutils for your target. We have started with m68k-coff first as it requires no patches.

    	./configure -prefix=/opt/uClinux -target=m68k-coff
    

    Then make the m68k-coff bin utilities.

    	make 
    	make install
    

    This will create a directory /opt/uClinux/m68k-coff which will have 5 subdirectories including bin, include, libs, m68k-coff and man. This will contain headers which is needed when we create gcc. Change back to your directory where gcc-2.7.2.3.tar.gz is present

    Extract the gcc src tarball, patch it and then enter the gcc directory

    	tar -xzf gcc-2.7.2.3.tar.gz
    	gzip -d gcc-2.7.2.3.kernel.diff.gz
    	cd gcc-2.7.2.3
    	patch -p1 < ../gcc-2.7.2.3.kernel.diff
    

    Configure gcc for your target. The prefix must be the same than the binutils, as gcc will expect to see the header files previously created by the binutils install.

    	./configure --prefix=/opt/uClinux --target=m68k-coff
    

    Then make the m68k-coff C Cross Compiler. The LANGUAGES=c instructs make only to build the C Compiler and not the C++ Compiler which will cause some unnecessary problems.

    	make LANGUAGES=c
    	make LANGUAGES=c install
    

    You should now have a m68k-pic-gcc compiler capable of building the kernel. The executables should be located in /opt/uClinux/m68k-coff/bin. To continue and build the pic-coff tools we must either delete the working directories or rename them. Renaming them is recommended as one of the reasons why you are building the source from scratch and not downloading an RPM is that you can later apply patches and bug fixes. Rename binutil-2.9.1 to binutil-2.9.1.kernel and gcc-2.7.2.3 to gcc-2.7.2.3.kernel

Manually Building the Tool Chains - m68k-pic-coff (Position Independent Code)

    Now we repeat the process for the m68k-pic-coff compiler. This time the binutils must be patched.

    	tar -xzf binutils-2.9.1.tar.gz
    	gzip -d binutils-2.9.1.pic.diff.gz
    	cd binutils-2.9.1
    	patch p1 < ../binutils-2.9.1.pic.diff
    

    and configure this time for the m68k-pic-coff toolchain.

    	./configure -prefix=/opt/uClinux -target=m68k-pic-coff
    

    Then make the m68k-coff bin utilities.

    	make 
    	make install
    

    This now has us ready to start making the gcc compiler. Extract the src tarball, patch it and then enter the gcc directory.

    	tar xzf gcc-2.7.2.3.tar.gz
    	gzip -d gcc-2.7.2.3.pic.diff.gz
    	cd gcc-2.7.2.3
    	patch -p1 < ../gcc-2.7.2.3.pic.diff
    

    Configure gcc for your target. The prefix must be the same than the binutils, as gcc will expect to see those header files which binutils created.

    	./configure -prefix=/opt/uClinux -target=m68k-pic-coff
    

    Then make the m68k-coff C Cross Compiler.

    	make LANGUAGES=c
    	make LANGUAGES=c install
    

    As neither m68k-pic-coff or m68k-coff is in the current path, most make files will attempt to call gcc using m68k-pic-coff-gcc. We can either place these two directories in our path, or we can create hard links to them in /usr/bin.

    	cd /opt/uClinux/bin
    	ln -f * /usr/bin
    

    Hard links are created instead of soft links. If an attempt is made to create an softlink, gcc/evecvp will complain about "too many levels of symbolic links". The content of /opt/uClinux/bin is soft links which point to the bin directories of the individual compilers.

    At this stage we now have a C Compiler which makes position independent COFF binaries. What we don't have is any standard C or standard maths libraries thus gcc will complain. uClinux also relies on flat binaries and not coff binaries. Therefore we must add a coff to flat converter (coff2flt) which converts the coff images the compiler generates into flat binaries which we can then run on uClinux.

coff2flt (COFF - Common Object File Format to Flat Binary Converter)

    In order to seemlessly create flat binaries with one command, the linker (LD) is replaced with a script which first runs the linker that generates the .coff file, then runs coff2flt utility to generate the flat binary.

    Download the above file and extract it.

    	tar xzf coff2flt-0.5.tar.gz
    	cd coff2flt-0.5
    	make
    

    This builds coff2flt. In the tarball is a script, ld. We must replace the pic-coff-ld with this script which in turns calls coff2flt to create a flat binary from our coff binary. However before we do this, edit the line in LD to set %prefix% to /opt/uClinux/m68k-pic-coff

    	mv /opt/uClinux/m68k-pic-coff/bin/ld /opt/uClinux/m68k-pic-coff/bin/gld
    	install -m 755 coff2flt /opt/uClinux/m68k-pic-coff/bin
    	cp ld /opt/uClinux/m68k-pic-coff/bin
    	chmod 755 /opt/uClinux/m68k-pic-coff/bin/ld
    

Standard C Library

    Two libraries are used when compiling user-land binaries. These are the standard C library and standard math library. These are static libraries which get linked at compilation time.

    The uC Standard C Library has always been plagued with bugs. In particular they have had bad memory leaks relating to their memory allocation functions. Some individuals have patches for the malloc functions which you can manually apply and build.

    The uC-libc is undergoing quite radical changes at the present moment. These experimental changes are available through the uClinux CVS repository. A stable library should be avalible soon which will supersede these early versions of uC-libc and provide a much more stable platform upon which to build your code. On a positive note, the maths library has had little problems.

    Extract the uC-libc tarball into /opt/uClinux.

    	tar xzf uC-libc-310899.tar.gz
    

    The uC-libc library has two symbolic links (include/linux and include/net) which should point to the headers of the uClinux Kernel. These links expect a linux directory to be present in the same tree the uC-libc directory is present in. If one doesn't exist due to a different install location, you may wish to create a link.

    The uC-libc library in its present form has no setjmp or longjmp functions which are later needed by sh. The easiest way to fix this, is to move uC-libc/machine/setjmp.S to uC-libc/sysdeps/ and include it (setjmp.o) to uC-libc/sysdeps/makefile.objs

    	cd uC-libc
    	make
    

    If you receive any errors about missing files typically in the asm, linux or net directories such as "/asm/types.h - No such file or directory," then check that you have configured your kernel (/include/asm links are in place) and that there is either the linux kernel source or a link to linux in the same directory that uC-libc is present in.

    This compiles the uC-libc library (libc.a) and leaves it in the uClibc directory. We now need to make this available to the m68k-pic-coff tools. Either a link can be made or the files copied.

    	cp libc.a /opt/uClinux/m68k-pic-coff/lib/libc.a
    	cp crt0.o /opt/uClinux/m68k-pic-coff/lib/crt0.o
    

    The include/header files also need to be available. The chaintool has already placed assert.h in /opt/uClinux/m68k-pic-coff/include therefore you may wish to rename the present directory.

    	mv /opt/uClinux/m68k-pic-coff/include /opt/uClinux/m68k-pic-coff/include.old
    	ln -sf include /opt/uClinux/m68k-pic-coff/include
    
Standard Maths Library

    The standard maths library is far less problematic. Simply extract it into /opt/uClinux and make,

    	tar xzf uC-libm-0.9.1.tar.gz
    	cd uC-libm
    	make
    

    then create links in the m68k-pic-coff/lib to point to the library and header files. These header files will actually find their way to the uC-libc/include directory by a symbolic link.

    	ln -f libmf.a /opt/uClinux/m68k-pic-coff/lib/libmf.a
    	ln -f libmf.a /opt/uClinux/m68k-pic-coff/lib/libm.a
    	ln -f mathf.h /opt/uClinux/m68k-pic-coff/include/mathf.h
    	ln -f mathf.h /opt/uClinux/m68k-pic-coff/include/math.h
    
genromfs - ROM FileSystem Generation Utility

    Genromfs generates a ROM Filesystem. Extract, patch and build using

    	tar -xzf genromfs-0.3.tar.gz
    	gzip -d genromfs-0.3.diff.gz
    	cd genromfs-0.3
    	patch -p1 <../genromfs-0.3.diff
    	make
    	make install
    

    "make install", will install genromfs in /usr/bin plus put its documentation in usr/man/man8

    Genromfs can then be called on the command line to generate your own romfs.

    	genromfs -v -V "ROM Disk" -f romdisk.img -d romdisk 2> romdisk.map
    

    The genromfs has some bugs relating to device nodes. If your romfs isn't correct, the kernel normally reports problems opening initial console (can't open the device node) and then panics. Often it is useful to mount your newly generated romfs to see if everything is correct. This can be done using

    	mount r o loop t romfs romdisk.img /mnt/romfs
    
ROM Disk FileSystem and Userland Binaries

    The romdisk gziped tarball contains device nodes. As a result this file must be extracted as root into the /opt/uClinux directory.

    	tar -xzf romdisk-0.9.1.tar.gz
    

    The romdisk forms the bases of your embedded systems filesystem. The genromfs utility will create a romfs.img from this tree, thus any changes or files you place in this tree will be present in the uClinux filesystem. The romdisk has the following directories (and file),

    	bin  dev  etc  htdocs  lib  proc  ramfs.img  sbin  tmp  usr  var 
    

    You will notice if you change into the bin directory that precompiled binaries are already present. Their source is installed next.

    	tar -xzf uC-src-0.9.2.tar.gz
    	cd src
    	make
    

    If you experience problems building sh - undefined reference to 'setjmp' or 'longjmp' check that you have included setjmp.S in the uC-libc build.

    Running make will build all the sources listed in the SUBDIR define of the Makefile. Therefore if you add extra sources here you must include them in the Makefile. At the completion of the build process, the binaries will be in the src/bin directories. The deftemplate.sh script will copy the required binaries from /src to /romdisk/bin or sbin.

    	cp deftemplate.sh /opt/uClinux/
    

    One last file is needed. buildenv.sh will set up the build environment from a clean directory, copying the required sources and setting up a Makefile. Copy buildenv.sh to /opt/uClinux/bin and create a link in /usr/bin.

    	cp buildenv.sh /opt/uClinux/bin/
    	ln /opt/uClinux/bin/buildenv.sh /usr/bin/buildenv
    

    and that is it. Now if you create an empty directory somewhere and type buildenv, a makefile will mysteriously appear. Then type make, to see the userland sources, romdisk etc copied over and built.

PIC32 Patch - 32-bit PIC patch for m68k-pic-coff 2.7.2.3

    With the current m68k-pic-coff compiler, a limitation exists which prevents building executables over 32k in size. This size comes about by using 16 bit signed offsets. Erwin Authried has released some patches for m68k-pic-coff-gcc to generate 32 bit offsets which removes this limitation. Code can be built normally with 16 bit offsets without specifying anything special. If your program exceeds 32k, then you can call the compiler with -fPIC which generates 32-bit offsets.

    Code compiled with the -fPIC switch is larger, thus it should only be used where needed. In addition to the compiler patch, a new C Startup file (crt0.S) is needed. This should be compiled and added to m68k-pic-coff/lib. The startup file contains no _cleanup() function thus this must be included elsewhere.

Debugging

    Debugging is an optional extra for the "smarter" uClinux programmers. It consists of two components, gdb-4.18 running on the host configured for m68k-coff and a gdbserver running on your uClinux platform. They talk together over the network (IP). While the gdb client should compile with little effort, the gdb-server requires not only patching but also support from the uClibc library, a debug uClibc library and support from the uClinux Kernel - but don't run away yet.

    gdbserver requires a trap in the uClinux Kernel to operate. The good news is that this has been included in the later kernels and thus in many cases needs no attention. The uClinux-2.0.38.1pre7 kernel detailed here already has this support.

    Download and extract gdb-4.18

    	tar -xzf gdb-4.18.tar.gz
    	gzip -d gdb-4.18-gdbserver.diff.gz
    	cd gdb-4.18
    	patch -p1 <../gdb-4.18-gdbserver.diff
    

    Now configure the gdb client running on the host to debug m68k-coff code and built it.

    	./configure --target=m68k-unknown-coff
    	make
    

    To build gdbserver requires some extra functions not found in the default uC-Libc library. The source is present in the library but is not specified to be built by default. Change into the /uC-libc/sysdeps/m68k and edit ptrace.c so that the ptrace.h path is correct. Change #include <sys/ptrace.h> to #include <linux/ptrace.h>.

    Then add the source to be build by editing /uC-libc/sysdeps/makefile.objs and adding m68k/ptrace.o to the end of the OBJS list, so that it looks like

    	waitpid.o \
    	write.o \
    	m68k/ptrace.o
    

    Then rebuild the uC-libc library and add the new libc.a to /m68k-pic-coff/lib.

    	cd gdb-4.18/gdb/gdbserver
    	../../configure --target=m68k-linux-coff
    

    Then edit the Makefile, changing CC = gcc to CC = m68k-pic-coff-gcc

    	make gdbserver
    	coff2flt -s 32768 -o gdbserver gdbserver.coff
    

    Running make by itself will create a gdbserver flat binary, however it's default stack size is typically around 4k. As a result, gdbserver may crash or fail to connect. Therefore it is recommended you link with a stack size of 32k

CVS Concurrent Version System

    Keeping track of all the changes and providing diff files frequently can cause headaches. Some changes get included while others dont. To ensure your development sources are always up to date Lineo has provided a CVS server. The CVS server allows changes to be made from multiple users, while keeping track of what the changes are and who made them. If something gets broken in the process it is simple to back track through the changes.

    The uClinux repository is available at http://cvs.uclinux.org. From there you can browse the source and check out what changes have been made and why.

    If you want to download the complete source then this can be done by logging into CVS using the CVS client on your development box. uClinux provides anonymous read-only access to their repository.

    To start, you must log in. Use the following command.

    	echo anonymous > cvs d:pserver:anonymous@cvs.uclinux.org:/var/cvs login
    

    This logs you into CVS using the username anonymous and password anonymous.

    	cvs z3 d:pserver:anonymous@cvs.uclinux.org:/var/cvs co P <dir>
    

    where <dir> is one of the present directories,

    	uClibc		The uClinux Userland C Library
    	uClinux-2.0.x	2.0.38 uClinux Kernel
    	uClinux-2.4.x	2.4.0 uClinux Kernel
    	userland	uClinux Userland Binaries
    

    The z3 specifies the compression used. z3 is maximum compression. The co stands for check out, while P specifies pruning directories (i.e. remove empty directories).

    Then at a later date you can update your sources by using the following command in the relevant directory.

    	cvs z3 update d P
    

Copyright 2002-2005 Craig Peacock - 15th June 2005.