|
Qnet 0.03 |
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.
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:
http://www.uclinux.org/pub/uClinux/m68k-elf-tools/m68k-elf-tools-20020410.tar.gz
/usr/local.
http://uclinux.org/pub/uClinux/dist/uClinux-dist-20020927.tar.gz
/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:
/opt/uclinux-src
/opt/uclinux-src/uClinux-dist
uClinux-dist-20020927.tar.gz uncompresses
itself. We'll call this the uclinux directory.
/opt/uclinux-src/uClinux-dist/linux-2.4.x
~/qnet
~/qnet/patches
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
uClinux-dist/.config
uClinux-dist/config/.config
uClinux-dist/linux-2.4.x/.config
uClinux-dist/config.arch
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:
linux-2.4.x/linux
images/linux.bin
images/romfs.img
images/image.bin
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.
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:
drivers/char/mcfserial.c.
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/config.in
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.
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.
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:
QNET_DIR
QNET_S19DIR
s19 subdirectory of QNET_DIR.
QNET_SERIAL
QNET_IP
runtftp.
programs print to the standard output.
The programs used to load and boot the kernels, are the following ones:
toserial
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.
setuplogic
init.s19 file to the target and
runs it at its predefined address.
runtftp <imagefile> <address>
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=192.168.0.100
./setuplogic
./runtftp /usr/src/uClinux-dist/images/image.bin 00020000
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.
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=192.168.0.100
./setuplogic
./cmdline ""
./runtftp /usr/src/uClinux-dist/images/image.bin 00020000
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
...
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:
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:
bah.....
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.
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 config.in 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-
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.
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.
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.
This chapter will be filled at a later point.
This chapter will be filled at a later point.
This chapter will be filled at a later point.