Qnet 0.03

Node: Top, Next: , Previous: (dir), Up: (dir)

This file is an ad-interim document to tell how to install a customized uClinux system for the Qnet device designed and produced by Qubica SpA.

Node: Setting up the Host System, Next: , Previous: Top, Up: Top

Setting up the Host System

In order to build a complete system for the qnet device, we'll start from the uClinux distribution and tools.

You'll therefore need to download the following file:
The cross-compiler to build uClinux code on an x86 host computer. The tar weights 28MB. It is meant to be uncompressed from the root directory, and its content goes to /usr/local.
The source for the uClinux kernel and filesystem. It weights 81MB and it can be extracted wherever you see fit. In this document I'll assume it is extracted in /opt/uclinux-src.

Once equipped with the complete source code you can follow the README file and build your first kernel and filesystem after graphically configuring the system. In this document, however, we'll rather follow all the steps from the command line, to ease repeating the task whenever needed.

In the following, we'll often refer to the following directories:

This is where we'll put all our scripts and subdirectories. We'll call this the project directory.
This is where the uClinux-dist-20020927.tar.gz uncompresses itself. We'll call this the uclinux directory.
This includes the kernel source we'll be using and modifying. We'll call this directory the kernel directory.
The directory where this package has been uncompressed. The actual pathname will depend on your setup, but here I'll assume this name in the examples of this document. We'll call this directory the qnet directory.
The directory where patches are found. We'll call this directory the patches directory.

Node: Compiling uClinux as a Whole, Next: , Previous: Setting up the Host System, Up: Top

Compiling uClinux as a Whole

In order to compile the uClinux tree avoiding the long operation of configuring what to select and what to discard, you can start from a set of configuration files. The ones I'm using are available in the qnet directory as config0.tar.gz (where the zero represent the initial situation).

Since most such files are hidden, to avoid unintentional and invisible damage to your system, the tar has been created from the project directory, so it extracts into an uClinux-dist subdirectory.

        decio% cd /opt/uclinux-src
        decio% tar xvzf ~/qnet/config0.tar.gz

The provided files reflect a typical configuration for a ColdFire 5407 processor running on the Motorola development platform (the 5407C3).

With this configuration in place, you'll be able to run "make oldconfig" to generate dependent configuration files. Then you can "make dep" and "make" in order to build your first uClinux image.

        decio% cd uClinux-dist
        decio% make oldconfig
        ... configuration takes 7 kbogoMips-second and prints 890 lines
        decio% make dep
        ... make dep takes 58 kbogoMips-second and prints 895 lines
        decio% make
        ... compilation takes 575 kbogoMips-second and prints 3486 lines

The kilo-bogoMips-second figure represents the running time of the commands on an unloaded host with plenty of RAM (figures can be much higher if the system needs to swap). The actual number of seconds depends also on the speed of your host, that can be approximated as its bogoMIPS value. Therefore, 60 kbogoMips-second are one minute if your hosts features 1000 bogoMIPS and half as much if your host is twice as fast.

At the end of the compilation step you'll most likely get an error, since the Makefile tries to copy the binary image to /tftpboot, which is usually only writable to the superuser. We'll ignore the error, as we are not yet concerned with booting through the network, which is covered in Loading the Kernel.

The output files we'll be concerned with are the following ones:

This is the kernel compiled as an ELF file. We'll call this file the kernel executable.
The kernel stripped of any ELF information. This is what we'll copy to the target computer, where there is no ELF loader that can handle the kernel executable. We'll call this file the kernel image.
The binary image for a root filesystem that matches the chosen configuration. We'll call this file the filesystem image.
A binary file that includes both the kernel image and the filesystem image (actually, it's just the two files concatenated). We'll call this file the uclinux image.

Node: Compiling the Kernel, Next: , Previous: Compiling uClinux as a Whole, Up: Top

Compiling the Kernel

In order to compile a kernel that can work with the Qnet device, we'll move to the kernel directory, and concentrate on kernel issues. Unfortunately, the kernel configured for the 5407C3 won't work unchanged on the Qnet.

Node: Fundamental Changes for Qnet, Next: , Previous: Compiling the Kernel, Up: Compiling the Kernel

Fundamental Changes for Qnet

In order to build a kernel that can boot a command prompt on the Qnet device, we need to change the code we are using to account for differences between the 5407C3 development board and this device.

There are two differences that need to be fixed immediately:

the console baud rate
While the Motorola development board runs the serial port at 19200, the Qnet runs at 115200 baud. This must be fixed in drivers/char/mcfserial.c.
the location of MBAR
The MBAR register on Qnet is placed by the firmware at address 0x90000000 instead of 0x10000000. This must be fixed in include/asm/coldfire.h.

In order to account for those differences in the cleanest way (i.e., not breaking the source with respect to the Motorola development platform), we'll create a new configuration item for the kernel, CONFIG_QNET. Since the differences are pretty minor, we'll always set CONFIG_M5407C3 when CONFIG_QNET is selected.

The patch file qnet-kernel.patch0, in the patches directory, implements the two fixes above and the change in configuration:

        decio% cd linux-2.4.x
        decio% patch -p1 < ~/qnet/qnet-kernel.patch0
        patching file arch/m68knommu/
        patching file drivers/char/mcfserial.c
        patching file include/asm-m68knommu/coldfire.h
        patching file .config
        decio% make oldconfig ARCH=m68knommu
        ... configuration takes 3 kbogoMips-second and prints 366 lines

The final command, make oldconfig is required so the new .config is used to generate the new header files for C code. The ARCH assignment tells make the kernel being reconfigured is what we want instead of an i386 kernel.

Node: Actual kernel Compilation, Previous: Fundamental Changes for Qnet, Up: Compiling the Kernel

Actual kernel Compilation

In order to compile the modified kernel, we'll remain in the kernel directory as compiling the kernel alone is faster than scanning all the other directories of uClinux.

The following commands will compile the Qnet kernel from within the kernel directory, as well as re-build the uclinux image.

        decio% make ARCH=m68knommu CROSS_COMPILE=m68k-elf-
        ... compilation takes 35 kbogoMips-second and prints 317 lines
        decio% m68k-elf-objcopy -O binary linux ../images/linux.bin
        decio% cat ../images/linux.bin ../images/romfs.img > ../images/image.bin

We'll need to issue those three commands every time we change kernel source code. We'll also need to make oldconfig whenever the .config file is modified.

Node: Loading the Kernel, Next: , Previous: Compiling the Kernel, Up: Top

Loading the Kernel

In order to load and run a kernel and filesystem, you need first to program the logic device through the serial port. With that in place, you can run a tftp server and send a kernel and filesystem through the network.

The scripts provided use the following environment variables, if defined:

The source directory of the qnet package, where other programs are to be found. If not defined, the current directory is used.
The directory where to look for the various s19 files to send to the serial port. If not defined, it defaults to the s19 subdirectory of QNET_DIR.
The serial port where commands and data are sent. If not defined, programs print to the standard output.
The IP address to use for the qnet device. If not specified, it defaults to The variable is only used by runtftp. programs print to the standard output.

The programs used to load and boot the kernels, are the following ones:

This program converts the end-of-line characters so the data is correctly interpreted by the target device. It is used by all other programs. While a simpler "tr '\\n' '\\r'" would have been worked for Unix files, the toserial script can eat DOS files too. Too bad so many S19 files use DOS conventions for end-of-line.
The program sends the init.s19 file to the target and runs it at its predefined address.
runtftp <imagefile> <address>
The program sends the tftpd.s19 file to the target, tells it to use QNET_IP as IP address for the on-board Ethernet device and then sends the image file imagefile to that IP address using the tftp protocol.

Using these tools, running a kernel reduces to the following steps:

        export QNET_SERIAL=/dev/ttyS0
        export QNET_IP=
        ./runtftp /usr/src/uClinux-dist/images/image.bin 00020000

Node: Customizing the Kernel, Next: , Previous: Loading the Kernel, Up: Top

Customizing the Kernel

In order to tailor the kernel for the qnet device, there are a few changes to make. Most of them are independent and you can apply any subset of them or all of them. The only interference between the various changes is in the configuration file for the kernel, as we'll need to add IDE and Ethernet support one at a time, as the default code for either won't code with qnet. Thus, I won't include the config files but only the difference applied.

Node: The Command Line, Next: , Previous: Customizing the Kernel, Up: Customizing the Kernel

The Command Line

The default configuration has no provision for passing a command line. On the other hand, Qubica provided a program to store a command line at address 0x1e000, so up to 512 bytes of command line can be passed to the kernel.

The trivial patch for the kernel to retrieve the command line is available as cmdline.patch in the qnet directory.

In order to download a command line to the target, you can use the program cmdline in the qnet directory. It will load the s19/utils.s19 file to the target and will use it. The program, like those introduced in Loading the Kernel, uses the environment variables QNET_SERIAL, QNET_DIR and QNET_S19DIR if specified.

The complete boot sequence, including a command line is thus:

        export QNET_SERIAL=/dev/ttyS0
        export QNET_IP=
        ./cmdline ""
        ./runtftp /usr/src/uClinux-dist/images/image.bin 00020000

Node: Making Depend, Next: , Previous: The Command Line, Up: Customizing the Kernel

Making Depend

In the following sections we'll patch the kernel. This means that new files will appear and old files will include a different set of header files. Thus, you'll need to run "make dep" in the kernel tree any now and then, in order to avoid hairy mismatches between the configuration/headers and the compiled code.

Since the uClinux distribution added ipsec support to the kernel, and part of the code lives in ../freeswan, you won't be able to successfully make dep in the kernel tree unless you first remove references to such an external directory.

The patch noipsec.patch, in the patches directory, takes care of this detail, assuming you are not enabling ipsec in your kernel:

        ostro% patch -p1 < ~/qnet/patches/noipsec.patch
        patching file net/Makefile
        ostro% make dep ARCH=m68knommu

Node: The Ethernet Driver, Next: , Previous: Making Depend, Up: Customizing the Kernel

The Ethernet Driver

The network device in the qnet platform is an RTL8019, that Linux can handle using the NE2000 driver. The patch file ethernet.patch sets the driver up for proper register access when the system is configured for qnet.

Apply the patch as usual, it changes two files in drivers/net, hopefully not breaking other implementations. Then enable the CONFIG_NE2000 option in .config and recompile

        patch -p1 < ~/qnet/ethernet.patch
        perl -p -i -e 's/^.*_NE2000.*$//' .config
        yes | make oldconfig ARCH=m68knommu
        make ARCH=m68knommu CROSS_COMPILE=m68k-elf-
        m68k-elf-objcopy -O binary linux ../images/linux.bin
        cat ../images/linux.bin ../images/romfs.img > ../images/image.bin

There is no need of a special command line, unless you want to do DHCP or anything similar, as the patch already sets up for auto-configuring all three devices.

The current version of the patch has the following problems:

Node: The IDE Driver, Next: , Previous: The Ethernet Driver, Up: Customizing the Kernel

The IDE Driver

The ide device in the qnet platform is completely standard. However, a patch is needed so that the kernel can locate the controller at the proper I/O address. Moreover, you'll need to change the timer interrupt to a different interrupt vector, as the external IDE uses the same line as the one used by the timer in the default setup. The patch ide.patch, thus changes platform/5407/config.c in addition to the various IDE files.

        patch -p1 < ~/qnet/ide.patch
        perl -p -i -e 's/^..CONFIG_IDE.*$//' .config
        make oldconfig ARCH=m68knommu
        select the needed options for the IDE driver
        make ARCH=m68knommu CROSS_COMPILE=m68k-elf-
        m68k-elf-objcopy -O binary linux ../images/linux.bin
        cat ../images/linux.bin ../images/romfs.img > ../images/image.bin

To load the image to the target use the usual command lines. You'll get back messages like the following ones:


Node: Isofs Support, Next: , Previous: The IDE Driver, Up: Customizing the Kernel

Isofs Support

There's an error in the file fs/isofs/rock.c as distributed in uClinux-dist-20020927.tar.gz. If you want to use isofs support in your platform it must be fixed. This is accomplished by the patch isofs.patch in the qnet directory. The patch also fixes a missing header inclusion in fs/isofs/namei.c.

Node: Memory Size, Next: , Previous: Isofs Support, Up: Customizing the Kernel

Memory Size

As distributed, the uClinux version of the kernel doesn't autodetect the memory size in the system. The memory size is hardwired to 32MB even if the configuration file defines CONFIG_RAMAUTO (or any specific size, actually). The memory size specified at configuration time is only used for other platforms (you can grep for it in the various crt0 assembly files).

Whatever the assembly file being used, the setup_arch function assumes to find the end-of-memory address at the _ramend location. The symbol is exported by the assembly file.

The approach taken for qnet is asking at compilation time what address in megabytes to use for the top-of-memory address. This is done by changing he file for the platform and using the chosen value in crt0_ram.S. Both changes are in the patch file memsize.patch.

As usual, you must make oldconfig and make. If you want to accept the default value (512 MB), the following commands will work:

        yes "" | make oldconfig ARCH=m68knommu
        make ARCH=m68knommu CROSS_COMPILE=m68k-elf-

Node: Kernel Location, Next: , Previous: Memory Size, Up: Customizing the Kernel

Kernel Location

Changing the kernel location is similar to changing the memory size as done above. The patch file kerneladdr.patch adds a configuration option that allows to choose the kernel position in memory, in megabytes. The default value, 0, enforces the default behaviour to place the kernel a the beginning of available RAM. Please note that if you load the kernel at higher addresses, you won't be able to see any RAM that sits below the kernel, unless you explicitly dereference a pointer to those addresses.

Unlikely to what happens for memsize above, relocating the kernel requires a change to the linker script, found in arch/m68knommu/platform/5407/MOTOROLA/ram.ld. This file, however, is not parsed by the C preprocessor, so a different approach must be taken. The Makefile in the MOTOROLA directory, therefore, has been modified to explicitly preprocess the linker script using perl to edit the script on the fly.

Node: Using a Different Console, Next: , Previous: Kernel Location, Up: Customizing the Kernel

Using a Different Console

To select a different console than the default one, you can simply use the "console=" command line argument to the kernel. The default configuration for the ColdFire includes only one console driver, associated to the name ttyS (ad defined in drivers/char/mcfserial.c.

To use the second serial port, thus, "console=ttyS1" will do. You can also specify the baud rate to be used, for example "console=ttyS1,9600".

To get rid of the console altogether, you'll need to register a new console driver and enable it as a default console driver. The patch patches/noconsole.patch registers a new driver, called "none". A command line argument "console=none" will this work to disable the default console setup. With no argument, the usual serial port will be used as system console.

With a disabled console, you'll still be able to get kernel messages from /proc/kmsg. The final line you get at boot time will be:

        <4>Warning: unable to open an initial console.

confirming that there is no tty device currently acting as a console. The system, completes its boot normally, though, and you can telnet in through the network.

Node: Enabling the data caches as write-back, Previous: Using a Different Console, Up: Customizing the Kernel

Enabling the data caches as write-back

The default data cache configuration is write-through, but in our environment using write-back make the system run twice as fast. The patch patches/cache.patch enables the cache for the first 512 megs (instead of 256) and sets it as write-back. This requires a change in the flush function, that is bugged in the default implementation, but the bugs are only exposed by using the write-back setup.

Node: Creating the Filesystem, Next: , Previous: Customizing the Kernel, Up: Top

Creating the Filesystem

This chapter will be filled at a later point.

Node: Loading the Filesystem, Next: , Previous: Creating the Filesystem, Up: Top

Loading the Filesystem

This chapter will be filled at a later point.

Node: Cross-Compiling Applications, Previous: Loading the Filesystem, Up: Top

Cross-Compiling Applications

This chapter will be filled at a later point.

Table of Contents