This document describes how to use the firmware
U-Boot and the operating system
Linux in Embedded PowerPC, ARM and MIPS Systems.

There are many steps along the way, and it is nearly impossible to cover
them all in depth, but we will try to provide all necessary information to
get an embedded system running from scratch. This includes all the
tools you will probably need to configure, build and run
U-Boot and Linux.

First, we describe how to install the Cross Development Tools
Embedded Linux Development Kit
which you probably need - at least when you use a standard x86 PC
running Linux
or a Sun Solaris 2.6 system
as build environment.

Then we describe what needs to be done to connect to the serial
console port of your target: you will have to configure a terminal
emulation program like cu or
kermit.

In most cases you will want to load images into your target using
ethernet; for this purpose you need TFTP and DHCP / BOOTP servers. A
short description of their configuration is given.

A description follows of what needs to be done to configure and build
the U-Boot for a specific
board, and how to install it and get it working on that board.

The configuration, building and installing of Linux
in an embedded configuration is the next step.
We use SELF, our Simple Embedded Linux Framework,
to demonstrate how to set up both a
development system (with the root filesystem mounted over NFS) and an
embedded target configuration (running from a ramdisk image based on
busybox).

This document does not describe what needs to be
done to port U-Boot or Linux to a new hardware platform. Instead, it
is silently assumed that your board is already supported by U-Boot
and Linux.

You have the freedom to distribute copies of this document in any
format or to create a derivative work of it and distribute it
provided that you:

Distribute this document or the derivative work at no charge at all.
It is not permitted to sell this document or the
derivative work or to include it into any package or distribution
that is not freely available to everybody.

Send your derivative work (in the most suitable format such as
sgml) to the author.

License the derivative work with this same license or use GPL.
Include a copyright notice and at least a pointer to the license
used.

Give due credit to previous authors and major contributors.

It is requested that corrections and/or comments be forwarded to the
author.

If you are considering to create a derived work other than a
translation, it is requested that you discuss your plans with the
author.

Use the information in this document at your own risk. DENX disavows any
potential liability for the contents of this document. Use of the
concepts, examples, and/or other content of this document is entirely
at your own risk.
All copyrights are owned by their owners, unless specifically noted
otherwise. Use of a term in this document should not be regarded as
affecting the validity of any trademark or service mark.
Naming of particular products or brands should not be seen as
endorsements.

The Embedded Linux Development Kit (ELDK)
includes the GNU cross development tools, such as the compilers,
binutils, gdb, etc., and a number of pre-built target tools and
libraries necessary to provide some functionality on the target
system.

It is provided for free with full source code, including all patches,
extensions, programs and scripts used to build the tools.

Starting from version 4.1, the ELDK is available in two versions, which
use Glibc resp. uClibc as the main C library for the target packages.

Note: It may be necessary, and is usually recommended, to install the
latest available software updates on your host system. For example, on Fedora Core systems, you can use one of yum, apt-get or up2date to keep your systems current.

Stable versions of the ELDK are distributed in the form of an ISO
image, which can be either burned onto a CD or mounted directly,
using the loopback Linux device driver (Linux host only).

For the PowerPC target,
the ELDK distribution was split into two independent
ISO images: one targeting the 4xx family of processors (AMCC),
and another one for the 8xx, 6xx, 74xx and 85xx families (Freescale).
This makes the ISO images fit on standard CDROM media.

If you are not bound by the CDROM size limitiation
there is still a single image containing all targets.

Development versions of the ELDK are available as directory trees so
it is easy to update individual packages; instructions for download
of these trees and creation of ISO images from it is described in section 3.4.2. Downloading the ELDK.

The ELDK contains an installation utility and a number of RPM
packages, which are installed onto the hard disk of the cross
development host by the installation procedure. The RPM packages can
be logically divided into two parts:

Embedded Linux Development Tools (ELDT)

Target components

The first part contains the cross development tools that are executed
on the host system. Most notably, these are the GNU cross compiler,
binutils, and gdb. For a full list of the provided ELDT packages,
refer to section 3.8.1. List of ELDT Packages below.

The target components are pre-built tools and libraries which are
executed on the target system. The ELDK includes necessary target
components to provide a minimal working NFS-based environment for the
target system. For a list of the target packages included in the
ELDK, refer to section 3.8.2. List of Target Packages below.

The ELDK contains several independent sets of the target packages, one
for each supported target architectureCPU family. Each set has been built using
compiler code generation and optimization options specific to the
respective target CPU family.

You can either download the ready-to-burn ISO-images from one of the mirror sites
(see 3.1. ELDK Availability),
or you can download the individual files of the ELDK
from the development directory tree and either use these directly for installation
or create an ISO image that can be burned on CD-ROM.

Change to a directory with sufficient free disk space; for the
PowerPC version of the ELDK you need about 780 MB, or twice as much
(1.6 GB) if you also want to create an ISO image in this directory.

To download the ISO image from the ppc-linux-x86/iso directory of one of the
mirror sites you can use standard tools like wget or ncftpget,
for example:

Note: The size of this ISO image is more than 790 MB,
so it does not fit on CDROM media.
If you don't need support for all PowerPC processors then you can use
one of the following alternative images which can be writen to standard CDROM media:

This will create an ISO image
eldk-ppc-linux-x86.iso in your local directory
that can be burned on CD or DVD (depending on size)
or mounted using the loopback device and
used for installation as described above. Of course you can use the
local copy of the directory tree directly for the installation, too.

The initial installation is performed using the install utility
located in the root of the ELDK ISO image directory tree. The install
utility has the following syntax:

$ ./install [-d <dir>] [<cpu_family1>] [<cpu_family2>] ...

-d <dir>

Specifies the root directory of the ELDK being installed. If omitted, the ELDK goes into the current directory.

<cpu_family>

Specifies the target CPU family the user desires to install. If one or more <cpu_family> parameters are specified, only the target components specific to the respective CPU families are installed onto the host. If omitted, the target components for all supported target architectureCPU families are installed.

Note: Make sure that the "exec" option to the mount command is in effect when mounting the ELDK ISO image. Otherwise the install program cannot be executed. On some distributions, it may be necessary to modify the /etc/fstab file, adding the "exec" mount option to the cdrom entry - it may also be the case that other existing mount options, such as "user" prevent a particular configuration from mounting the ELDK CD with appropriate "exec" permission. In such cases, consult your distribution documentation or mount the CD explicitly using a command such as "sudo mount -o exec /dev/cdrom /mnt/cdrom" (sudo allows regular users to run certain privileged commands but may not be configured - run the previous command as root without "sudo" in the case that "sudo" has not been setup for use on your particular GNU/Linux system).

You can install the ELDK to any empty directory you wish, the only
requirement being that you have to have write and execute permissions
on the directory. The installation process does not require
superuser privileges.

Depending on the parameters the install utility is invoked with, it
installs one or more sets of target components. The ELDT packages are
installed in any case.

The ELDK has an RPM-based structure. This means that on the ISO
image, individual components of the ELDK are in the form of RPM
packages, and after installation, the ELDK maintains its own database
which contains information about installed packages. The RPM database
is kept local to the specific ELDK installation, which allows you to
have multiple independent ELDK installations on your host system.
(That is, you can install several instances of ELDK under different
directories and work with them independently). Also, this provides
for easy installation and management of individual ELDK packages.

For the above commands to work correctly, it is crucial that the
correct rpm binary gets invoked. In case of
multiple ELDK installations and RedHat-based host system, there may
well be several rpm tools installed on the host
system.

You must make sure, either by using an explicit path or by having set
an appropriate PATH environment variable, that
when you invoke rpm to install/remove components
of a ELDK installation, it is the ELDK's rpm
utility that gets actually invoked. The rpm
utility is located in the bin subdirectory
relative to the ELDK root installation directory.

To avoid confusion with the host OS (RedHat) rpm
utility, the ELDK creates symlinks to its rpm
binary with the names such that it could be invoked using the
${CROSS_COMPILE}rpm notation, for all supported
$CROSS_COMPILE values.

The standard (host OS) rpm utility allows various
macros and configuration parameters to specified in
user-specific ~/.rpmrc and ~/.rpmmacros files. The ELDK
rpm tool also has this capability, but the names
of the user-specific configuration files
are ~/.eldk_rpmrc and ~/.eldk_rpmmacros, respectively.

After the initial installation is complete, all you have to do to
start working with the ELDK is to set and export the
CROSS_COMPILE environment variable.
Optionally, you may wish to add the bin and usr/bin directories of
your ELDK installation to the value of your PATH
environment variable. For instance, a sample ELDK installation and
usage scenario looks as follows:

No special actions are required from the user to switch between
multiple ELDK installations on the same host system. Which ELDK
installation is used is determined entirely by the filesystem
location of the binary that is being invoked. This approach can be
illustrated using the following example.

Assume the directory
/work/denx_tools/usr/bin, where the ppc-linux-gcc
compiler binary has been installed,
is a part of the PATH environment variable. The
user types the command as follows:

$ ppc_8xx-gcc -c myfile.c

To load the correct include files, find the correct libraries, spec
files, etc., the compiler needs to know the ELDK root directory. The
compiler determines this information by analyzing the shell command it
was invoked with ( ppc_8xx-gcc
- without
specifying the explicit path in this example) and, if needed, the
value of the PATH environment variable. Thus, the
compiler knows that it has been executed from the
/work/denx_tools/usr/bin directory.

Then, it knows that the compiler is installed in the usr/bin
subdirectory of the root installation directory, so the ELDK, the
compiler is a part of, has been installed in the subdirectories of the
/work/denx_tools directory. This means
that the target include files are in
/work/denx_tools/<target_cpu_variant>/usr/include,
and so on.

The target components of the ELDK can be mounted via NFS as the root
file system for your target machine. For instance, for an
8xx-based
target, and assuming the ELDK has been installed into the
/opt/eldk directory, you can
use the following directory as the NFS-based root file system:

/opt/eldk/ppc_8xx

Before the NFS-mounted root file system can work, you must create
necessary device nodes in the
<ELDK_root>/<target_cpu_variant>/dev
directory. This process requires superuser privileges and thus
cannot be done by the installation procedure (which typically runs as non-root). To facilitate
creation of the device nodes, the ELDK provides a script named
ELDK_MAKEDEV, which is located in the root
of the ELDK distribution ISO image. The script acccepts the following
optional arguments:

-d <dir>

Specifies the root directory of the ELDK being installed. If omitted, then the current directory is assumed.

-a <cpu_family>

Specifies the target CPU family directory. If omitted, all installed target architecture directories will be populated with the device nodes.

-h

Prints usage.

NOTE: Compared to older versions of the ELDK,
options and behaviour of this command have been changed significantly.
Please read the documentation.

Some of the target utilities included in the ELDK, such as
mount and su, have the SUID bit
set. This means that when run, they will have privileges of the file
owner of these utilities. That is, normally, they will have the
privileges of the user who installed the ELDK on the host system.
However, for these utilities to work properly,
they must have superuser privileges. This means that if the ELDK was
not installed by the superuser, the file owner of the target
ELDK utilities that have the SUID bit set must be changed to
root before a target component may be mounted as
the root file system. The ELDK distribution image contains an
ELDK_FIXOWNER script, which you can use to change
file owners of all the appropriate files of the ELDK installation to
root. The script accepts the same arguments as the ELDK_MAKEDEV script above.
Please note that you must have superuser
privileges to run this script. For instance, if you have installed
the ELDK in the /opt/eldk
directory, you can use the following commands:

# cd /opt/eldk
# /mnt/cdrom/ELDK_FIXOWNER

Please note, that in the case that the installation directory, where the new ELDK
distribution is being installed, is already populated with other ELDK distributions,
the execution of the ELDK_FIXOWNER script without arguments will make the script
work with all installed ELDK target architecture
directories. This could take some time. To save the time, please use the -a argument
to specify the appropriate target architecture.
For instance:

All the target packages can be rebuilt
from the provided source RPM packages.
At first you have to install the Source RPM itself:

bash$ ${CROSS_COMPILE}rpm -iv <package_name>.src.rpm

Then you can rebuild the binary target RPM using the following command
from the ELDK environment:

bash$ ${CROSS_COMPILE}rpmbuild -ba <package_name>.spec

In order for the rebuilding process to work correctly, the following
conditions must be true:

The $CROSS_COMPILE environment variable
must be set as appropriate for the target CPU family.

The <ELDK_root>/usr/ppc-linux/bin
directory must be in PATH before the
/usr/bin directory. This is to make sure that
the command gcc results in the fact that the
ELDK cross compiler is invoked, rather than the host
gcc.

Note 1: Not all packages will be installed automatically; for example the
boa and thttpd web servers are
mutually exclusive - you will have to remove one package before you
can (manually) install the other one.

In this section, you
will find instructions on how to build the ELDK
from scratch, using the pristine package sources available on the
Internet, and patches, spec files, and build scripts provided on the
ELDK source CD-ROM.

The ELDK uses the
Fedora Core 4 Linux distribution as source code
reference. Any modifications to Fedora Core's sources the ELDK has
introduced are in the form of patches applied by the RPM tool while
building the packages. Also, the ELDK uses modified spec files for
its RPM packages. So, the sources of almost every ELDK package
consist of the following parts:

After cloning the repository, you can use standard =git= commands to check out
any specific release of the ELDK;
for example, to get the files for
ELDK release 4.1, please run the command

$ git-checkout ELDK_4_1

It must be noted that some of the packages which are included in the
ELDK are not included in Fedora Core. Examples of such packages are
appWeb, microwindows, and wu-ftpd. For these
packages tarballs are provided in the DENX git repository.
We also provide a copy of the original Fedora SRPMS
to make sure these remain available permanently.

To facilitate building of the ELDK, a build infrastructure has been
developed. The infrastructure is composed of the following components:

ELDK_BUILD script

build.sh script

cpkgs.lst file

tpkgs.lst file

SRPMS.lst file

tarballs.lst file

The ELDK_BUILD script is the main script of the
ELDK build procedure. It is the tool that you would normally use to
build the ELDK from scratch. In the simplest case, the script may be
invoked without arguments, and it will perform all necessary steps to
build the ELDK in a fully automated way. You may pass the following optional
arguments to the ELDK_BUILD script:

-d <arch>

target architecture: "ppc", "arm" or "mips", defaults to "ppc".

-n <build_name>

an identification string for the build. Defaults to the value based on the build architecture and current date, and has the following format: <arch>-YYYY-MM-DD

-p <build_dir>

(optional) the name of a directory that will be used to store all the build results; used for out-of-tree building

Warning: The ELDK build scripts rely on standard behaviour of the RPM tool.
Make sure you don't use non-standard settings in your personal ~/.rpmmacros file that
might cause conflicts.

build.sh is a supplementary script that is called
by ELDK_BUILD to accomplish certain steps of the
build. Refer to section 3.9.3. build.sh Usage below for more
details.

The cpkgs.lst and tpkgs.lst
files are read by build.sh and must contain lines
describing sub-steps of the eldt and
trg build procedure steps. Essentially, the
files contain the list of the ELDT and target packages to be included
in the ELDK. The SRPMS.lst file contains the
list of the Fedora Core source RPM packages used during the ELDK build.
The tarballs.lst file contains the list of
source tarballs of the packages that are included in the ELDK but are
not present in Fedora Core 4.

For the ELDK_BUILD script to work correctly, it
must be invoked from a certain build environment created on the host
system. The build environment can be either checked out from the DENX
CVS (see section 3.9.2. Setting Up ELDK Build Environment below for details) or copied
from the ELDK build environment CD-ROM.

To be more specific, the following diagram outlines the build
environment needed for correct operation of the
ELDK_BUILD script:

In subdirectories of the cross_rpms and target_rpms
directories, the sources and RPM spec files of,
respectively, the ELDT and target packages are
stored. The install
subdirectory contains the sources of the installation utility which
will be built and placed in the root of the ISO image.
tarballs directory contains the source
tarballs of the packages that are included in the ELDK but are not
present in Fedora Core 4.

The SRPMS directory may contain the source RPM packages of Fedora Core
4. If some (or all) of the Fedora Core SRPMs needed for the build are
missing in the directory, the ELDK_BUILD script
will download the source RPMs automatically from the Internet.

The ELDK_BUILD script examines the contents of the
ELDK_PREFIX environment variable to determine the
root directory of the ELDK build environment. If the variable is not
set when the script is invoked, it is assumed that the root directory
of the ELDK build environment is /opt/eldk. To build the ELDK in the
example directory layout given above, you must set and export the
ELDK_PREFIX variable <some_directory> prior to invoking
ELDK_BUILD.

After all the build steps are complete, the following subdirectories
are created in the ELDK build environment:

On Linux hosts, the binary and source ISO images are created
automatically by the ELDK_BUILD script and placed
in the results directory. On
Solaris hosts, creating the ISO images is a manual step. Use the
contents of the b_cdrom and
s_cdrom directories for the
contents of the ISO images.

For your convenience,
the ELDK build environment CD-ROM provides full
ELDK build environment. All you need to do is copy the contents of
the CD-ROM to an empty directory on your host system. Assuming the
ELDK build environment CD-ROM is mounted at /mnt/cdrom,
and the empty directory
where you want to create the build environment is named
/opt/eldk, use the following
commands to create the build environment:

bash$ cd /opt/eldk
bash$ cp -r /mnt/cdrom/* .

These commands will create the directory structure as described in
section 3.9.1. ELDK Build Process Overview above.
All necessary scripts and ELDK specific source files will be placed in the
build subdirectory, and the required
tarballs can be found in the
tarballs subdirectory. In the
SRPMS subdirectory, you will find all
the Fedora Core 4 SRPMS needed to build the ELDK.

Alternatively, you can obtain the ELDK build environment from the
DENX git repository.
Three modules are provided:
eldk/build.git, eldk/tarballs.git and
eldk/SRPMS.git. The first one contains the files
for the build subdirectory in
the build environment;
the second one contains source tarballs of
the packages that are included in the ELDK but are not present in
Fedora,
and the last one contains the original Fedora SRPMS.
To create the ELDK build environment from the DENX git
repository,
please use the following commands
(the example below assumes that
the root directory of the build environment is
/opt/eldk):

If you wish
to perform only a part of the ELDK build procedure, for
instance to re-build or update a certain package, it may sometimes be
convenient to invoke the build.sh script manually,
without the aid of the ELDK_BUILD script. Please
note, however, that this approach is in general discouraged.

The whole build procedure is logically divided into six steps, and
the build.sh must be told which of the build steps
to perform. The build steps are defined as follows:

rpm - build RPM

eldt - build ELDT packages

seldt - save ELDT SRPM packages to create a source ISO image later on

trg - build target packages

biso - prepare the file tree to create the binary ISO image

siso - prepare the file tree to create the source ISO image

Further, the eldt and trg
build steps are devided into sub-steps, as defined in the
cpkgs.lst and tpkgs.lst

files (see below for details). You may specify which sub-steps of the
build step are to be performed.

an identification string for the build. It is used as a name for some directories created during the build. You may use for example the current date as the build name.

-p <prefix>

is the name of the directory that contains the build environment. Refer to build overview above for description of the build environment.

-r <result>

is the name of the directory where the resulting RPMs and SRPMs created on this step will be placed.

-w <work>

is the name of the directory where the build is performed.

<stepname>

is the name of the build step that is to be performed. Refer to the list of the build procedure steps above.

<sub_step_number>

is an optional parameter which identifies sub-steps of the step which are to be performed. This is useful when you want to re-build only some specific packages. The numbers are defined in the cpkgs.lst and tpkgs.lst files discussed below. You can specify a range of numbers here. For instance, "2 5" means do steps from 2 to 5, while simply "2" means do all steps starting at 2.

By default, the invocation of build.sh assumes that the Glibc-based ELDK version is being built. For the uClibc-based
ELDK build, set the UCLIBC environment variable to 1 prior to running build.sh :

bash$ export UCLIBC=1

Please note that you must never use build.sh to
build the ELDK from scratch. For build.sh to work
correctly, the script must be invoked from the build environment
after a successful build using the ELDK_BUILD
script. A possible scenario of build.sh usage is
such that you have a build environment with results of a build
performed using the ELDK_BUILD script and want to
re-build certain ELDT and target packages, for instance, because you
have updated sources of a package or added a new package to the
build.

When building the target packages (during the
trg buildstep), build.sh
examines the contents of the
TARGET_CPU_FAMILY_LIST environment variable, which
may contain a list indicating which target CPU variants the packages
must be built for.
Possible CPU variants are 4xx, 4xxFP, 6xx, 74xx, 8xx and 85xx.
For example, the command below rebuilds
the target RPM listed in the tpckgs.lst file
under the number of 47 (see section 3.9.4. Format of the cpkgs.lst and tpkgs.lst Files for
description of the tpckgs.lst and
cpkgs.lst files), for the 8xx and 85xxCPUs:

Note: If you are going to invoke build.sh to re-build a
package that has already been built in the build environment by the
ELDK_BUILD script, then you must first manually
uninstall the package from ELDK installation created by the build
procedure under the work
directory of the build environment.

Note: It is recommended that you use the build.sh script
only at the final stage of adding/updating a package to the ELDK. For
debugging purposes, it is much more convenient and efficient to build
both ELDT and target packages using a working ELDK installation, as
described in the sections 3.7.2. Rebuilding Target Packages
and 3.7.3. Rebuilding ELDT Packages above.

The ELDK source CD-ROM contains the cpkgs.lst
and tpkgs.lst files used to build this version
of the ELDK distribution. Use them as reference if you want to
include any additional packages into the ELDK, or remove unneeded
packages.

To add a package to the ELDK you must add a line to either the
cpkgs.lst file, if you are adding a ELDT
package, or to the tpkgs.lst file, if it is a
target package. Keep in mind that the relative positions of packages
in the cpkgs.lst and
tpkgs.lst files (the sub-step numbers) are very
important. The build procedure builds the packages sequentially as
defined in the *.lst files and installs the
packages in the "work" environment as they are built. This
implies that if a package depends on other packages, those packages
must be specified earlier (with smaller sub-step numbers) in the
*.lst files.

Note: For cpkgs.lst, the package_version may be replaced
by the special keyword "RHAUX". Such packages are used as auxiliary when building
ELDK 4.0 on non-Fedora hosts. These packages will be built and used during the
build process, but will not be put into the ELDK 4.0 distribution ISO images.

If you use
a Solaris 2.x host environment, you need additional
freeware packages (mostly GNU tools) to install and especially to
build the ELDK packages. The following table lists all required
packages that must be installed on the Solaris host system
before attempting to build and/or install the
ELDK. All these files except those marked with (**) (and the RPM and
zlib-1.1.2 packages, which are available at
ftp://rpmfind.net/linux/solaris
are available for free download at
ftp://ftp.sunfreeware.com/pub/freeware/sparc/2.6/

Some tools are needed to install and configure U-Boot and Linux on
the target system. Also, especially during development, you will want
to be able to interact with the target system. This section describes
how to configure your host system for this purpose.

To use U-Boot and Linux as a development system and to make full use
of all their capabilities you will need access to a serial console
port on your target system. Later, U-Boot and Linux can be
configured to allow for automatic execution without any user
interaction.

There are several ways to access the serial console port on your target system,
such as using a terminal server, but the most common way is to attach it to a
serial port on your host. Additionally, you will need a terminal
emulation program on your host system, such as cu or kermit.

The cu command is part of the
UUCP package and can be used to act as a dial-in
terminal. It can also do simple file transfers, which can be used in
U-Boot for image download.

On RedHat systems you can check if the UUCP
package is installed as follows:

$ rpm -q uucp

If necessary, install the UUCP package from your distribution media.

To configure cu for use with U-Boot and Linux
please make sure that the following entries are present in the
UUCP configuration files; depending on your target
configuration the serial port and/or the console baudrate may be
different from the values used in this example:
(/dev/ttyS0, 115200 bps, 8N1):

/etc/uucp/sys:

#
# /dev/ttyS0 at 115200 bps:
#
system S0@115200
port serial0_115200
time any

The name kermit stands for a whole family of
communications software for serial and network connections. The fact
that it is available for most computers and operating systems makes
it especially well suited for our purposes.

kermit executes the commands in its
initialization file, .kermrc, in your home
directory before it executes any other commands, so this can be
easily used to customize its behaviour using appropriate
initialization commands. The following settings are recommended for
use with U-Boot and Linux:

~/.kermrc:

set line /dev/ttyS0
set speed 115200
set carrier-watch off
set handshake none
set flow-control none
robust
set file type bin
set file name lit
set rec pack 1000
set send pack 1000
set window 5

This example assumes that you use the first serial port of your host
system (/dev/ttyS0) at a baudrate of
115200 to connect to the target's serial console port.

You can then connect to the serial line:

$ kermit -c
Connecting to /dev/ttyS0, speed 115200.
The escape character is Ctrl-\ (ASCII 28, FS)
Type the escape character followed by C to get back,
or followed by ? to see other options.
----------------------------------------------------

Due to licensing conditions you will often find two kermit packages
in your GNU/Linux distribution. In this case you will want to install the
ckermit package. The gkermit package is only a command line
tool implementing the kermit transfer protocol.

If you cannot find kermit on the distribution
media for your Linux host system, you can download it from
the kermit project home page: http://www.columbia.edu/kermit/

minicom is another popular serial communication
program. Unfortunately, many users have reported problems using it
with U-Boot and Linux, especially when trying to use it for serial
image download. It's use is therefore discouraged.

The terminal emulation program must have write access to the serial
port and to any locking files that are used to prevent concurrent
access from other applications. Depending on the used Linux
distribution you may have to make sure that:

the serial device belongs to the same group as the
cu command, and that the permissions of
cu have the setgid bit set

the kermit belongs to the same group as
cu and has the setgid bit set

the /var/lock directory
belongs to the same group as the cu command, and
that the write permissions for the group are set

BOOTP resp. DHCP can be used to
automatically pass configuration information to the
target. The only thing the target must "know" about itself is its own
Ethernet hardware (MAC) address. The following command can be used to check if
DHCP support is available on your host system:

With this configuration, the DHCP server will reply to a request from
the target with the ethernet address
00:30:BF:01:02:D0 with the following information:

The target is located in the subnet 10.0.0.0
which uses the netmask 255.0.0.0.

The target has the hostname tqm
and the IP address 10.0.0.99.

The host with the IP address 10.0.0.2 will
provide the boot image for the target and provide NFS server
function in cases when the target mounts it's root filesystem over
NFS.
The host listed with the next-server
option can be different from the host that is running the DHCP
server.

The host provides the file /tftpboot/TQM8xxL/uImage
as boot image for the target.

The target can mount the directory
/opt/eldk/ppc_8xx on the NFS
server as root filesystem.

For a development environment it is very convenient when the host and
the target can share the same files over the network. The easiest way for
such a setup is when the host provides NFS server functionality and
exports a directory that can be mounted from the target as the root
filesystem.

Assuming NFS server functionality is already provided by your host, the
only configuration that needs to be added is an entry for your target
root directory to your /etc/exports file, for
instance like this:

/opt/eldk/ppc_8xx 10.0.0.0/255.0.0.0(rw,no_root_squash,sync)

This line exports the
/opt/eldk/ppc_8xx directory
with read and write permissions to all hosts on the 10.0.0.0
subnet.

After modifying the /etc/exports file you must
make sure the NFS system is notified about the change, for instance
by issuing the command:

Das U-Boot (or just "U-Boot" for short) is Open Source Firmware
for Embedded PowerPC, ARM, MIPS, x86 and other processors.
The U-Boot project is hosted by DENX, where you can also find the
project home page: http://www.denx.de/wiki/UBoot

The current version of the U-Boot source code can be retrieved from
the DENX "git" repository.

Those poor people sitting behind a restrictive firewall may use http tunneling to access the repositories.
Here is an example for cvsgrab, available from http://cvsgrab.sourceforge.net/, to access the U-Boot repository:

If you used CVS to get a copy of the U-Boot sources, then you can skip
this next step since you already have an unpacked directory tree. If you
downloaded a compressed tarball from the DENX FTP server, you can
unpack it as follows:

After changing to the directory with the U-Boot source code you should
make sure that there are no build results from any previous
configurations left:

$ make distclean

The following (model) command configures U-Boot for the TQM8xxL board:

$ make tqm8xxl_config

The TQM8xxL boards are available in many configurations (different
CPUs, clock frequencies, with or without LCD display, with or without
Fast Ethernet interface). Depending on the board configuration chose
one of the following make targets:

TQM823L_config

TQM823L_66MHz_config

TQM823L_80MHz_config

TQM823L_LCD_config

TQM823L_LCD_66MHz_config

TQM823L_LCD_80MHz_config

TQM850L_config

TQM850L_66MHz_config

TQM850L_80MHz_config

TQM855L_config

TQM855L_66MHz_config

TQM855L_80MHz_config

TQM860L_config

TQM860L_66MHz_config

TQM860L_80MHz_config

TQM862L_config

TQM862L_66MHz_config

TQM862L_80MHz_config

TQM855M_config

TQM855M_66MHz_config

TQM855M_80MHz_config

TQM860M_config

TQM860M_66MHz_config

TQM860M_80MHz_config

TQM862M_config

TQM862M_66MHz_config

TQM862M_80MHz_config

TQM862M_100MHz_config

And finally we can compile the tools and U-Boot itself:

$ make all

By default the build is performed locally and the objects are saved in
the source directory. One of the two methods can be used to change
this behaviour and build U-Boot to some external directory:

1. Add O= to the make command line invocations:

make O=/tmp/build distclean
make O=/tmp/build tqm8xxl_config
make O=/tmp/build all

Note that if the 'O=output/dir' option is used then it must be used
for all invocations of make.

2. Set environment variable BUILD_DIR to point to the desired
location:

export BUILD_DIR=/tmp/build
make distclean
make tqm8xxl_config
make all

Note that the command line "O=" setting overrides the BUILD_DIR
environment variable.

The following section assumes that flash memory is used as the storage
device for the firmware on your board. If this is not the case, the
following instructions will not work - you will probably have to
replace the storage device (probably ROM or EPROM) on such systems to
install or update U-Boot.

All TQM8xxL boards use a serial number for identification purposes.
Also, all boards have at least one ethernet (MAC) address assigned.
You may lose your warranty on the board if this data gets lost.
Before installing U-Boot or otherwise changing the software
configuration of a board (like erasing some flash memory) you should
make sure that you have all necessary information about such data.

A fast and simple way to write new data to flash memory is via the use of
a debugger or flash programmer with a BDM or JTAG
interface. In cases where there is no running firmware at all
(for instance on new hardware), this is usually the only way to
install any software at all.

If you have Linux running on your TQM8xxL system and your Linux configuration
includes a flash device driver, then you can use this to install a U-Boot
image to the appropriate address in flash memory:

Connect to the SMC1 port of the tqm8xxl board using the
cu program. See the hints for configuring
cu above. Make sure you can communicate with the
MON8xx firmware: reset the board and hit ENTER a
couple of times until you see the MON8xx prompt
(MON:>). Then proceed as follows:

U-Boot uses a special image format when loading the Linux kernel or
ramdisk or other images. This image contains (among other things)
information about the time of creation, operating system, compression
type, image type, image name and CRC32 checksums.

The tool mkimage is used to create such images or
to display the information they contain.
When using the ELDK, the mkimage command is
already included with the other ELDK tools.

If you don't use the ELDK then you should install
mkimage in some directory that is in your command
search PATH, for instance:

To initialize the U-Boot firmware running on your TQM8xxL board, you
have to connect a terminal to the board's serial console port.

The default configuration of the console port on the TQM8xxL board
uses a baudrate of 115200/8N1 (115200 bps, 8
Bit per character, no parity, 1 stop bit, no
handshake).

If you are running Linux on your host system we recommend either
kermit or cu as terminal
emulation programs. Do not use
minicom, since this has caused problems for many
users, especially for software download over the serial port.

In the default configuration, U-Boot operates in an interactive mode
which provides a simple command line-oriented user interface using a
serial console on port "COM.1 (X.18)".

In the simplest case, this means that U-Boot shows a prompt (default:
=>) when it is ready to receive user input. You
then type a command, and press enter. U-Boot will try to run the
required action(s), and then prompt for another command.

To see a list of the available U-Boot commands, you can type
help (or simply ?). This will
print a list of all commands that are available in your current
configuration. [Please note that U-Boot provides a
lot of configuration options; not all options are
available for all processors and boards, and some options might be
simply not selected for your configuration.]

Note: If you bought your TQM8xxL board with U-Boot already installed,
you can skip this section since the manufacturer probably has already
performed these steps.

Connect the port labeled "COM.1 (X.18)" on your TQM8xxL board to the
designated serial port of your host, start the terminal program, and
connect the power supply of your TQM8xxL board. You should see
messages like this:

You can interrupt the "Count-Down" by pressing any key. If you don't
you will probably see some (harmless) error messages because the
system has not been initialized yet.

In some cases you may see a message

*** Warning - bad CRC, using default environment

This is harmless and will go away as soon as you have initialized and
saved the environment variables.

At first you have to enter the serial number and the ethernet address
of your board. Pay special attention here since these parameters are
write protected and cannot be changed once saved (usually this is
done by the manufacturer of the board). To enter the data you have to
use the U-Boot command setenv, followed by the
variable name and the data, all separated by white space (blank
and/or TAB characters). Use the variable name
serial# for the board ID and/or serial number, and
ethaddr for the ethernet address, for instance:

Please double check that the printed values are correct! You will not be
able to correct any errors later! If there is something wrong,
reset the board and restart from the beginning; otherwise you can
store the parameters permanently using the saveenv
command:

The following section describes the most important commands available
in U-Boot. Please note that U-Boot is highly configurable, so not
all of these commands may be available in the configuration of
U-Boot installed on your hardware, or additional commands may exist.
You can use the help command to print a list of
all available commands for your configuration.

For most commands, you do not need to type in the full command name;
instead it is sufficient to type a few characters. For instance,
help can be abbreviated as h.

The behaviour of some commands depends of the configuration of
U-Boot and on the definition of some variables in your U-Boot
environment.

All U-Boot commands expect numbers to be entered in hexadecimal
input format.

Be careful not to use edit keys besides 'Backspace', as hidden
characters in things like environment variables can be very
difficult to find.

The bdinfo command (short: bdi)
prints the information that U-Boot passes about the
board such as memory addresses and sizes, clock frequencies, MAC address,
etc. This information is mainly needed to be passed to the Linux
kernel.

The output contains the device name, flags, and the current usage.
For example, the output

serial 80000003 SIO stdin stdout stderr

means that the serial device is a system device
(flag 'S') which provides input (flag
'I') and output (flag 'O')
functionality and is currently assigned to the 3 standard I/O streams
stdin, stdout and
stderr.

iminfo (short: imi) is used to
print the header information for images like Linux kernels or
ramdisks. It prints (among other information) the image name, type
and size and verifies that the CRC32 checksums stored within the
image are OK.

=> help help
help [command ...]
- show help information (for 'command')
'help' prints online help for the monitor commands.
Without arguments, it prints a short usage message for all commands.
To get detailed help information for specific commands you can type
'help' with one or more command names as arguments.
=>

The help command (short: h or ?) prints online help. Without any
arguments, it prints a list of all U-Boot commands that are available
in your configuration of U-Boot. You can get detailed information for
a specific command by typing its name as argument to the help
command:

You can use the base command (short: ba) to print or set a "base
address" that is used as address offset for all memory commands; the
default value of the base address is 0, so all addresses you enter are
used unmodified. However, when you repeatedly have to access a
certain memory region (like the internal memory of some embedded
PowerPC processors) it can be very convenient to set the base address
to the start of this area and then use only the offsets:

With the cmp command you can test of the contents
of two memory areas is identical or not. The command will either test
the whole area as specified by the 3rd (length) argument, or stop at
the first difference.

Like most memory commands the cmp can access the
memory in different sizes: as 32 bit (long word), 16 bit (word) or 8
bit (byte) data. If invoked just as cmp the
default size (32 bit or long words) is used; the same can be selected
explicitely by typing cmp.l instead. If you want
to access memory as 16 bit or word data, you can use the variant
cmp.w instead; and to access memory as 8 bit or
byte data please use cmp.b.

Please note that the count argument specifies
the number of data items to process, i. e. the number of long words or
words or bytes to compare.

=> cmp.l 100000 40000000 400
word at 0x00100004 (0x50ff4342) != word at 0x40000004 (0x50504342)
Total of 1 word were the same
=> cmp.w 100000 40000000 800
halfword at 0x00100004 (0x50ff) != halfword at 0x40000004 (0x5050)
Total of 2 halfwords were the same
=> cmp.b 100000 40000000 1000
byte at 0x00100005 (0xff) != byte at 0x40000005 (0x50)
Total of 5 bytes were the same
=>

The last displayed memory address and the value of the count argument
are remembered, so when you enter md again
without arguments it will automatically
continue at the next address, and use the same count again.

The mm is a method to interactively modify memory
contents. It will display the address and current contents and then
prompt for user input. If you enter a legal hexadecimal number, this
new value will be written to the address. Then the next address will
be prompted. If you don't enter any value and just press ENTER, then
the contents of this address will remain unchanged. The command stops
as soon as you enter any data that is not a hex number (like
.):

This tests writes to memory, thus modifying the memory
contents. It will fail when applied to ROM or flash memory.

This command may crash the system when the tested memory range
includes areas that are needed for the operation of the U-Boot
firnware (like exception vector code, or U-Boot's internal program
code, stack or heap memory areas).

The mw is a way to initialize (fill) memory with
some value. When called without a count
argument, the value will be written only to the specified address.
When used with a count, then a whole memory
areas will be initialized with this value:

The nm command (non-incrementing memory
modify) can be used to interactively write different data
several times to the same address. This can be useful for instance to
access and modify device registers:

The command flinfo (short: fli)
can be used to get information about the available flash memory. The
number of flash banks is printed with information about the size and
organization into flash "sectors" or erase units.
For all sectors the start addresses are printed; write-protected sectors
are marked as read-only (RO).
Some configurations of U-Boot also mark empty sectors with an (E).

Note that both the start and end addresses for this command
must point exactly at the start resp. end addresses of flash sectors.
Otherwise the command will not be executed.

Another way to select certain areas of the flash memory for the erase
command uses the notation of flash banks and sectors:

Technically speaking, a bank is an area of
memory implemented by one or more memory chips that are connected to
the same chip select signal of the CPU, and a
flash sector or erase unit
is the smallest area that can be erased in one operation.

For practical purposes it is sufficient to remember that with flash
memory a bank is something that eventually may be erased as a whole
in a single operation. This may be more efficient (faster) than
erasing the same area sector by sector.

[It depends on the actual type of flash chips used on the board if
such a fast bank erase algorithm exists, and on the implementation of
the flash device driver if is actually used.]

In U-Boot, flash banks are numbered starting with
1, while flash sectors start with
0.

To erase the same flash area as specified using start and end
addresses in the example above you could also type:

=> era 1:6-8
Erase Flash Sectors 6-8 in Bank # 1
.. done
=>

To erase a whole bank of flash memory you can use a command like this one:

Note: Included topic DULGData.tqm8xxlUBootEraseBank does not exist yet

Note that a warning message is printed because some
write protected sectors exist in this flash bank
which were not erased.

The protect command is another complex one. It is used to set
certain parts of the flash memory to read-only mode or to make them
writable again. Flash memory that is "protected" (= read-only)
cannot be written (with the cp command) or erased (with the
erase command). Protected areas are marked as (RO) (for "read-only") in
the output of the flinfo command:

The actual level of protection depends on the flash chips used on
your hardware, and on the implementation of the flash device driver
for this board. In most cases U-Boot provides just a simple
software-protection, i. e. it prevents you from erasing or overwriting
important stuff by accident (like the U-Boot code itself or U-Boot's
environment variables), but it cannot prevent you from circumventing
these restrictions - a nasty user who is loading and running his own
flash driver code cannot and will not be stopped by this
mechanism. Also, in most cases this protection is only effective while
running U-Boot, i. e. any operating system will not know about
"protected" flash areas and will happily erase these if requested to
do so.

=> help autoscr
autoscr [addr] - run script starting at addr. A valid autoscr header must be present
=>

With the autoscr command you can run "shell" scripts
under U-Boot: You create a U-Boot script image by simply writing
the commands you want to run into a text file; then you will have to
use the mkimage tool to convert this text file
into a U-Boot image (using the image type
script).

This image can be loaded like any other image file, and with
autoscr you can run the commands in such an image.
For instance, the following text file:

The bootm command is used to start operating system
images. From the image header it gets information about the type of
the operating system, the file compression method used (if any), the
load and entry point addresses, etc. The command will then load the
image to the required memory address, uncompressing it on the fly if
necessary. Depending on the OS it will pass the required boot
arguments and start the OS at it's entry point.

The first argument to bootm is the memory address
(in RAM, ROM or flash memory) where the image is stored, followed by
optional arguments that depend on the OS.

For Linux, exactly one optional argument can be
passed. If it is present, it is interpreted as the start address of a
initrd ramdisk image (in RAM, ROM or flash
memory). In this case the bootm command consists
of three steps: first the Linux kernel image is uncompressed and
copied into RAM, then the ramdisk image is loaded to RAM, and finally
controll is passed to the Linux kernel, passing information about the
location and size of the ramdisk image.

To boot a Linux kernel image without a initrd
ramdisk image, the following command can be used:

=> bootm ${kernel_addr}

If a ramdisk image shall be used, you can type:

=> bootm ${kernel_addr} ${ramdisk_addr}

Both examples of course imply that the variables used are set to correct
addresses for a kernel and a initrd ramdisk image.

When booting images that have been loaded to RAM (for instance
using TFTP download) you have to be careful that the locations where
the (compressed) images were stored do not overlap with the memory
needed to load the uncompressed kernel. For instance, if you load a
ramdisk image at a location in low memory, it may be overwritten when
the Linux kernel gets loaded. This will cause undefined system
crashes.

U-Boot has support for so-called standalone applications.
These are programs that do not require the
complex environment of an operating system to run. Instead they can
be loaded and executed by U-Boot directly, utilizing U-Boot's
service functions like console I/O or malloc()
and free().

This can be used to dynamically load and run special extensions to
U-Boot like special hardware test routines or bootstrap code to load
an OS image from some filesystem.

The go command is used to start such standalone
applications. The optional arguments are passed to the application
without modification. For more informatoin see 5.12. U-Boot Standalone Applications.

With kermit you can download binary data via the serial line. Here we
show how to download uImage, the Linux kernel
image. Please make sure, that you have set up
kermit as described in section
4.3. Configuring the "kermit" command
and then type:

The printenv command prints one, several or all variables
of the U-Boot environment. When arguments are given, these are
interpreted as the names of environment variables which will be
printed with their values:

Without arguments, printenv prints all a list with
all variables in the environment and their values, plus some
statistics about the current usage and the total size of the memory
available for the environment.

All changes you make to the U-Boot environment are made in RAM only.
They are lost as soon as you reboot the system. If you want to make
your changes permanent you have to use the saveenv
command to write a copy of the environment settings to persistent
storage, from where they are automatically loaded during startup:

To modify the U-Boot environment you have to use the
setenv command. When called with exactly one
argument, it will delete any variable of that name from U-Boot's
environment, if such a variable exists. Any storage occupied for such
a variable will be automatically reclaimed:

When called with more arguments, the first one will again be the name
of the variable, and all following arguments will (concatenated by
single space characters) form the value that gets stored for this
variable. New variables will be automatically created, existing ones
overwritten.

=> printenv bar
## Error: "bar" not defined
=> setenv bar This is a new example.
=> printenv bar
bar=This is a new example.
=>

Remember standard shell quoting rules when the value of a variable
shall contain characters that have a special meaning to the command
line parser (like the $ character that is used
for variable substitution or the semicolon which separates commands).
Use the backslash (\) character to escape such
special characters, or enclose the whole phrase in apstrophes (').
Use "${name}" for variable expansion
(see 14.2.11. How the Command Line Parsing Works for details).

There is no restriction on the characters that can be used in a
variable name except the restrictions imposed by the command line
parser (like using backslash for quoting, space and tab characters to
separate arguments, or semicolon and newline to separate commands).
Even strange input like "=-/|()+=" is a perfectly
legal variable name in U-Boot.

A common mistake is to write

setenv name=value

instead of

setenv name value

There will be no error message, which lets you believe everything went
OK, but it didn't: instead of setting the variable name to the value
value you tried to delete a variable with the name name=value
- this is probably not what you intended! Always remember that name
and value have to be separated by space and/or tab characters!

=> help run
run var [...]
- run the commands in the environment variable(s) 'var'
=>

You can use U-Boot environment variables to store commands and even
sequences of commands. To execute such a command, you use the
run command:

=> setenv test echo This is a test\;printenv ipaddr\;echo Done.
=> printenv test
test=echo This is a test;printenv ipaddr;echo Done.
=> run test
This is a test
ipaddr=10.0.0.99
Done.
=>

You can call run with several variables as
arguments, in which case these commands will be executed in sequence:

=> setenv test2 echo This is another Test\;printenv serial#\;echo Done.
=> printenv test test2
test=echo This is a test;printenv ipaddr;echo Done.
test2=echo This is another Test;printenv serial#;echo Done.
=> run test test2
This is a test
ipaddr=10.0.0.99
Done.
This is another Test
serial#=TQM860LDDBA3-P50.203 10226122 4
Done.
=>

If a U-Boot variable contains several commands (separated by
semicolon), and one of these commands fails when you "run" this
variable, the remaining commands will be executed anyway.

If you execute several variables with one call to
run, any failing command will cause "run" to
terminate, i. e. the remaining variables are not
executed.

The U-Boot environment is a block of memory that is kept on
persistent storage and copied to RAM when U-Boot starts. It is used
to store environment variables which can be used to configure the
system. The environment is protected by a CRC32 checksum.

This section lists the most important environment variables, some of
which have a special meaning to U-Boot. You can use these variables
to configure the behaviour of U-Boot to your liking.

autoload: if set to "no" (or any string beginning with 'n'), the
rarpb, bootp or dhcp commands will perform only a
configuration lookup from the BOOTP / DHCP server, but not try to
load any image using TFTP.

autostart: if set to "yes", an image loaded using the rarpb,
bootp, dhcp, tftp, disk, or docb commands will be
automatically started (by internally calling the bootm command).

baudrate: a decimal number that selects the console baudrate (in
bps). Only a predefined list of baudrate settings is available.
When you change the baudrate (using the "setenv baudrate ..."
command), U-Boot will switch the baudrate of the console terminal
and wait for a newline which must be entered with the new speed
setting. This is to make sure you can actually type at the new
speed. If this fails, you have to reset the board (which will
operate at the old speed since you were not able to saveenv the
new settings.)
If no "baudrate" variable is defined, the default baudrate of
115200 is used.

bootargs: The contents of this variable are passed to the Linux
kernel as boot arguments (aka "command line").

bootcmd: This variable defines a command string that is
automatically executed when the initial countdown is not
interrupted.
This command is only executed when the variable
bootdelay is also defined!

bootdelay: After reset, U-Boot will wait this number of seconds
before it executes the contents of the
bootcmd variable. During this time a countdown is printed,
which can be interrupted by pressing any key.
Set this variable to 0 boot without delay. Be careful:
depending on the contents of your bootcmd variable, this can
prevent you from entering interactive commands again forever!
Set this variable to -1 to disable autoboot.

cpuclk: (Only with MPC859 / MPC866 / MPC885 processors) On some processors,
the CPU clock frequency can be adjusted by the user (for example to
optimize performance versus power dissipation). On such systems the
cpuclk variable can be set to the desired CPU clock value, in MHz. If the
cpuclk variable exists and its value is within the
compile-time defined limits (CFG_866_CPUCLK_MIN and CFG_866_CPUCLK_MAX
= minimum resp. maximum allowed CPU clock), then the specified value is used.
Otherwise, the default CPU clock value is set.

ethaddr: Ethernet MAC address for first/only ethernet interface
(= eth0 in Linux).
This variable can be set only once (usually during manufacturing
of the board). U-Boot refuses to delete or overwrite this
variable once it has been set.

initrd_high: used to restrict positioning of initrd ramdisk images:
If this variable is not set, initrd images will be copied to the
highest possible address in RAM; this is usually what you want
since it allows for maximum initrd size. If for some reason you
want to make sure that the initrd image is loaded below the
CFG_BOOTMAPSZ limit, you can set this environment variable to a
value of "no" or "off" or "0". Alternatively, you can set it to a
maximum upper address to use (U-Boot will still check that it
does not overwrite the U-Boot stack and data).
For instance, when you have a system with 16 MB RAM, and want to
reserve 4 MB from use by Linux, you can do this by adding
"mem=12M" to the value of the "bootargs" variable. However, now
you must make sure that the initrd image is placed in the first
12 MB as well - this can be done with

=> setenv initrd_high 00c00000

Setting initrd_high to the highest possible address in your system (0xFFFFFFFF)
prevents U-Boot from copying the image to RAM at all.
This allows for faster boot times, but requires a Linux kernel
with zero-copy ramdisk support.

ipaddr: IP address; needed for tftp command

loadaddr: Default load address for commands like tftp or
loads.

loads_echo: If set to 1, all characters received during a
serial download (using the loads command) are echoed back. This
might be needed by some terminal emulations (like cu), but
may as well just take time on others.

mtdparts: This variable (usually defined using the
mtdparts command) allows to share a common MTD
partition scheme between U-Boot and the Linux kernel.

pram: If the "Protected RAM" feature is enabled in your board's
configuration, this variable can be defined to enable the
reservation of such "protected RAM", i. e. RAM which is not
overwritten by U-Boot. Define this variable to hold the number of
kB you want to reserve for pRAM. Note that the board info
structure will still show the full amount of RAM. If pRAM is
reserved, a new environment variable "mem" will automatically be
defined to hold the amount of remaining RAM in a form that can be
passed as boot argument to Linux, for instance like that:

=> setenv bootargs ${bootargs} mem=\${mem}
=> saveenv

This way you can tell Linux not to use this memory, either, which
results in a memory region that will not be affected by reboots.

serial#: contains hardware identification information such as
type string and/or serial number.
This variable can be set only once (usually during manufacturing
of the board). U-Boot refuses to delete or overwrite this
variable once it hass been set.

silent: If the configuration option CONFIG_SILENT_CONSOLE has been enabled
for your board, setting this variable to any value will suppress all console
messages. Please see doc/README.silent for details.

verify: If set to n or no disables the checksum calculation
over the complete image in the bootm command to trade speed for
safety in the boot process. Note that the header
checksum is still verified.

The following environment variables may be used and automatically
updated by the network boot commands (bootp, dhcp, or tftp),
depending the information provided by your boot server:

bootfile: see above

dnsip: IP address of your Domain Name Server

gatewayip: IP address of the Gateway (Router) to use

hostname: Target hostname

ipaddr: see above

netmask: Subnet Mask

rootpath: Pathname of the root filesystem on the NFS server

serverip: see above

filesize: Size (as hex number in bytes) of the file downloaded
using the last bootp, dhcp, or tftp command.

U-Boot allows to store commands or command sequences in a plain text file.
Using the mkimage tool you can then convert this file into a script image
which can be executed using U-Boot's autoscr command.

For example, assume that you will have to run the following sequence of commands
on many boards, so you store them in a text file, say "setenv-commands":

examples/hello_world.c contains a small "Hello World" Demo
application; it is automatically compiled when you build U-Boot. It's
configured to run at address 0x00040004, so you can play with it like
that:

This example, which demonstrates how to register a CPM interrupt
handler with the U-Boot code, can be found in
examples/timer.c. Here, a CPM timer is set up to generate an
interrupt every second. The interrupt service routine is trivial, just
printing a '.' character, but this is just a demo program. The
application can be controlled by the following keys:

U-Boot operates on "image" files which can be basically anything,
preceeded by a special header; see the definitions in
include/image.h for details; basically, the header defines the
following image properties:

CGL shall provide support for detecting a repeating reboot cycle due to recurring failures and will go to an offline state if this occurs.

This feature is available in U-Boot if you enable the CONFIG_BOOTCOUNT_LIMIT
configuration option. The implementation uses the following environment variables:

bootcount:

This variable will be automatically created if it does not exist,
and it will be updated at each reset of the processor.
After a power-on reset, it will be initialized with 1, and each reboot
will increment the value by 1.

bootlimit:

If this variable exists, its contents are taken as the maximum
number of reboot cycles allowed.

altbootcmd:

If, after a reboot, the new value of bootcount
exceeds the value of bootlimit, then instead of the standard boot action
(executing the contents of bootcmd) an alternate boot action will be
performed, and the contents of altbootcmd will be executed.

If the variable bootlimit is not defined in the environment,
the Boot Count Limit feature is disabled.
If it is enabled, but altbootcmd is not defined, then U-Boot will drop
into interactive mode and remain there.

It is the responsibility of some application code (typically a Linux application)
to reset the variable bootcount, thus allowing for more boot cycles.

At the moment, the Boot Count Limit feature is available only for MPC8xx and MPC82xx PowerPC processors.

By adding the CFG_CMD_BMP option to your
CONFIG_COMMANDS command selections
you can enable support for bitmap images in U-Boot.
This will add bmp to the list of commands in your configuration of U-Boot:

To keep the code in U-Boot simple and as fast as possible, the bitmap images must match the color depth of your framebuffer device. For example, if your display is configured for a color depth of 8 bpp (bit per pixel) then the bmp command will complain if you try to load images with a different color depth:

(As you can see above, the sub-commands "info" and "display" can be
abbreviated as "i" resp. "d" .)

Images that are bigger than your framebuffer device will be clipped on the top
and right hand side.

Images that are smaller than the display will be loaded into the top left corner.

Since loading an image will define a new color map,
the remainder of the display will appear with incorrect colors.
It is therefore recommended that all images match exactly the size of the current
display device.
We accepted these restrictions since speed was top priority,
and all attempts to implement scaling or optimizing the color maps
would slow down the display too much. It is much easier to perform the
necessary transformations on the development host, where a plethora of tools
is available.

Even if you manage to boot U-Boot and Linux into a graphical user application
within 5 or 6 seconds of power-on (which is not difficult), many
customers expect to see "something" immediately. U-Boot supports the concept of
a splash screen for such purposes.

To enable splash screen support, you have to add a
"#define CONFIG_SPLASH_SCREEN" to your board configuration file. This will also implicitly enable U-Boot Bitmap Support.

After power-on, U-Boot will test if the environment variable "splashimage"
is defined, and if it contains the address of a valid bitmap image. If this is the case, the normal startup messages will be suppressed and the defined splash screen will be displayed instead. Also, all output (devices stdout and stderr ) will be suppressed (redirected to the "nulldev" device).

The TQM8xxL board is fully supported by DENX Software Engineering.
This means that you will always be able to build a working default
configuration with just minimal interaction.

Please be aware that you will need the "powerpc" cross development
tools for the following steps. Make sure that the directory which
contains the binaries of your
ELDK are in your PATH.

To be sure that no intermediate results of previous builds are left
in your Linux kernel source tree you can clean it up as follows:

bash$ make mrproper

The following command selects a standard configuration for the TQM8xxL
board that has been extensively tested. It is recommended to use this
as a starting point for other, customized configurations:

bash$ make tqm8xxl_config

The TQM8xxL boards are available in many configurations (different
CPUs, with or without LCD display, with or without Fast Ethernet
interface). Depending on the board configuration chose one of the
following make targets:

TQM823L_config

TQM823L_LCD_config

TQM850L_config

TQM860L_config

Please use the TQM860L configuration for TQM855L boards.

Note: When you type "make XXX_config" this means that a default configuration file for the board named XXX gets selected. The name of this default configuration file is arch/""/configs/XXX_defconfig . By listing the contents of the arch/""/configs/ directory you can easily find out which other default configurations are available.

If you don't want to change the default configuration you can now
continue to use it to build a kernel image:

bash$ make oldconfig
bash$ make dep
bash$ make uImage

Otherwise you can modify the kernel configuration as follows:

bash$ make config

or

bash$ make menuconfig

Note: Because of problems (especially with some older Linux kernel
versions) the use of "make xconfig" is
not recommended.

The make target uImage uses
the tool mkimage (from the U-Boot package) to
create a Linux kernel image in
arch/ppc/boot/images/uImage

which is immediately
usable for download and booting with U-Boot.

In case you configured modules you will also need to compile the modules:

If your host computer is not the same architecture as the target
system, and if you got your kernel tree from kernel.org or other
"official" sources,
then you may have to supply an architecture override and a cross
compiler definition. The most reliable way to do this is to specify
them on the make command line as part of the make command. If
this is the case, use for example:

In principle, if you have a Linux kernel image
somewhere in system memory (RAM, ROM, flash...), then all you need to boot the system is the bootm command.
Assume a Linux kernel image has been stored at address 0x40080000 - then you can boot this image with the following command:

In nearly all cases, you will want to pass additional information to
the Linux kernel; for instance, information about the root device or
network configuration.

In U-Boot, this is supported using the bootargs
environment variable. Its contents are automatically passed to the
Linux kernel as boot arguments (or "command line" arguments). This allows the
use of the same Linux kernel image in a wide range of configurations. For
instance, by just changing the contents of the
bootargs variable you can use the very same Linux
kernel image to boot with an initrd ramdisk image,
with a root filesystem over NFS, with a CompactFlash disk or from a
flash filesystem.

As one example, to boot the Linux kernel image at address 0x200000 using
the initrd ramdisk image at address 0x400000 as
root filesystem,
you can use the following commands:

=> setenv bootargs root=/dev/ram rw
=> bootm 200000 400000

To boot the same kernel image with a root filesystem over NFS, the
following command sequence can be used. This example assumes that your
NFS server has the IP address "10.0.0.2" and exports the directory
"/opt/eldk/ppc_8xx" as root filesystem for the target. The target has been
assigned the IP address "10.0.0.99" and the hostname "tqm". A netmask
of "255.0.0.0" is used:

Passing command line arguments to the Linux kernel allows for very
flexible and efficient configuration which is especially important in
Embedded Systems. It is somewhat strange that these features are
nearly undocumented everywhere else. One reason for that is
certainly the very limited capabilities of other boot loaders.

It is especially U-Boot's capability to easily define, store, and
use environment variables that makes it such a powerful tool in this
area. In the examples above we have already seen how we can use for
instance the root and ip boot
arguments to pass information about the root filesystem or network
configuration. The ip argument is not only useful
in configurations with root filesystem over NFS; if the Linux kernel
has the CONFIG_IP_PNP configuration enabled (IP
kernel level autoconfiguration), this can be used to enable automatic
configuration of IP addresses of devices and of the routing table
during kernel boot, based on either information supplied on the
kernel command line or by BOOTP or RARP protocols.

The advantage of this mechanism is that you don't have to spend
precious system memory (RAM and flash) for network configuration
tools like ifconfig or route -
especially in Embedded Systems where you seldom have to change the
network configuration while the system is running.

We can use U-Boot environment variables to store all necessary
configuration parameters:

Then you can use these variables to build the boot arguments to be
passed to the Linux kernel:

=> setenv nfsargs 'root=/dev/nfs rw nfsroot=${serverip}:${rootpath}'

Note how apostrophes are used to delay the substitution of the
referenced environment variables. This way, the current values of
these variables get inserted
when assigning values to the "bootargs" variable itself later,
i. e. when it gets assembled from the given parts
before passing it to the kernel.
This allows us to simply
redefine any of the variables (say, the value of "ipaddr" if it has to be
changed), and the changes will automatically propagate to the Linux
kernel.

Note: You cannot use this method directly to define for example the
"bootargs" environment variable, as the implicit usage of this variable by
the "bootm" command will not trigger variable expansion - this happens
only when using the "setenv" command.

In the next step, this can be used for a flexible method to define
the "bootargs" environment variable by using a
function-like approach to build the boot arguments step by step:

In this setup we define two variables, ram_root
and nfs_root, to boot with root filesystem from a
ramdisk image or over NFS, respecively. The variables can be executed
using U-Boot's run command. These variables make use of the run
command itself:

First, either run ramargs or run nfsargs is used to
initialize the bootargs environment variable as needed to boot
with ramdisk image or with root over NFS.

Then, in both cases, run addip is used to append the ip
parameter to use the Linux kernel IP autoconfiguration mechanism
for configuration of the network settings.

Finally, the bootm command is used with two resp. one address argument(s) to boot the Linux kernel image with resp. without a
ramdisk image. (We assume here that the variables kernel_addr
and ramdisk_addr have already been set.)

This method can be easily extended to add more customization options
when needed.

If you have used U-Boot's network commands before (and/or read the
documentation), you will probably have recognized that the names of
the U-Boot environment variables we used in the examples above are
exactly the same as those used with the U-Boot commands to boot over a
network using DHCP or BOOTP. That means that, instead of manually setting
network configuration parameters like IP address, etc., these variables
will be set automatically to the values retrieved with the network
boot protocols. This will be explained in detail in the examples
below.

After Power-On or reset the system will initialize and then wait for
a key-press on the console port. The duration of this countdown is
determined by the contents of the bootdelay
environment variable (default: 5 seconds).

If no key is pressed, the command (or the list of commands) stored in
the environment variable bootcmd is executed. If
you press a key, you get a prompt at the console port which allows
for interactive command input.

In the example above the following commands are executed sequentially:

These commands take the following effect (pay attention for the
modification of environment variables by these commands):

bootp: This command uses the BOOTP protocol to ask a boot
server for information about our system and to load a boot image
(which will usually be a Linux kernel image). Since no aguments
are passed to this command, it will use a default address to load
the kernel image (0x100000 or the last address used by other
operations).

The Target sends a BOOTP request on the network, and (assuming
there is a BOOTP server available) receives a reply that contains the
IP address (ipaddr=10.0.0.99) and other network information for
the target (hostname=tqm, serverip=10.0.0.2,
gatewayip=10.0.0.2, netmask=255.0.0.0).

Also, the name of the boot image (bootfile=/tftpboot/TQM8xxL/uImage
)
and the root directory on a NFS server
(rootpath=/opt/eldk/ppc_8xx) was transmitted.

U-Boot then automatically downloaded the bootimage from the server using
TFTP.

You can use the command iminfo (Image Info, or short imi) to
verify the contents of the loaded image:

This command defines the environment variable bootargs. (If an old
definition exists, it is deleted first). The contents of this variable
is passed as command line to the LInux kernel when it is booted (hence
the name). Note how U-Boot uses variable substitution to dynamically
modify the boot arguments depending on the information we got from the
BOOTP server.

This command line passes the following information to the Linux kernel:

root=/dev/nfs rw: the root filesystem will be mounted
using NFS, and it will be writable.

nfsroot=10.0.0.2:/opt/eldk/ppc_8xx: the NFS server has the
IP address 10.0.0.2, and exports the directory
/opt/eldk/ppc_8xx for our system to use as root
filesystem.

ip=10.0.0.99:10.0.0.2:10.0.0.2:255.0.0.0:tqm::off: the
target has the IP address 10.0.0.99; the NFS server is
10.0.0.2; there is a gateway at IP address 10.0.0.2; the
netmask is 255.0.0.0 and our hostname is tqm. The first
ethernet interface (eth0) willbe used, and the Linux kernel
will immediately use this network configuration and not try to
re-negotiate it (IP autoconfiguration is off).

See Documentation/nfsroot.txt in you Linux kernel
source directory for more information about these parameters and other
options.

bootm: This command boots an operating system image that
resides somewhere in the system memory (RAM or flash - the m
in the name is for memory).
In this case we do not pass any
memory address for the image, so the load address 0x100000 from
the previous TFTP transfer is used:

The previous section described how to load the Linux kernel image
over ethernet using TFTP. This is especially well suited for your
development and test environment, when the kernel image is still
undergoing frequent changes, for instance because you are modifying
kernel code or configuration.

Later in your development cycle you will work on application code or
device drivers, which can be loaded dynamically as modules. If the
Linux kernel remains the same then you can save the time needed for
the TFTP download and put the kernel image into the flash memory of
your TQM8xxL board.

The U-Boot command flinfo can be used to display
information about the available on-board flash on your system:

From this output you can see the total amount of flash memory, and
how it is divided in blocks (Erase Units or
Sectors). The RO markers
show blocks of flash memory that are write protected (by software) -
this is the area where U-Boot is stored. The remaining flash memory
is available for other use.

For instance, we can store the Linux kernel image in flash starting
at the start address of the next free flash sector. Before we can do
this we must make sure that the flash memory in that region is empty
- a Linux kernel image is typically around 600...700 kB, so to be on
the safe side we dedicate the whole area from 0x40080000 to
0x4027FFFF for the kernel image. Keep in mind that with
flash memory only whole erase units can be cleared.

After having deleted the target flash area, you can download
the Linux image and write it to flash. Below is a transcript of
the complete operation with a final iminfo command to check
the newly placed Linux kernel image in the flash memory.

Note: Included topic DULGData.tqm8xxlInstallKernelTftp does not exist yet

Note how the filesize variable (which gets set by
the TFTP transfer) is used to automatically adjust for the actual
image size.

Now we can boot directly from flash. All we need to do is passing the
in-flash address of the image (40080000) with the bootm
command; we also make the definition of the
bootargs variable permanent now:

To test booting from flash you can now reset the board (either by
power-cycling it, or using the U-Boot command
reset), or you can manually call the
boot command which will run the commands in the
bootcmd variable:

When your application development is completed, you usually will want
to run your Embedded System standalone, i. e.
independent from external resources like NFS filesystems. Instead of
mounting the root filesystem from a remote server you can use a
compressed ramdisk image, which is stored in flash memory and loaded
into RAM when the system boots.

Note: Included topic DULGData.tqm8xxlUBootInstallRamdisk does not exist yet

To tell the Linux kernel to use the ramdisk image as root filesystem
you have to modify the command line arguments passed to the kernel,
and to pass two arguments to the bootm command,
the first is the memory address of the Linux kernel image, the second
that of the ramdisk image:

All currently available flash filesystems are based on the Memory
Technology Devices MTD layer, so you must enable (at least) the
following configuration options to get flash filesystem support in
your system:

As you can see it worked the first time. When we tried to write
the (new date) again, we got an error.
The reason is that the date has changed (probably at least the
seconds) and flash memory cannot be simply overwritten - it has to be
erased first.

You can use the eraseall Linux commands to erase a whole MTD
partition:

At the moment it seems that the Journalling Flash File System JFFS
is the best choice for filesystems in flash memory of embedded
devices. You must enable the following configuration options to get
JFFS support in your system:

CONFIG_JFFS_FS=y
CONFIG_JFFS_FS_VERBOSE=0

If the flash device is erased, we can simply mount it, and the
creation of the JFFS filesystem is performed automagically.

Note: For simple accesses like direct read or write operations or
erasing you use the character device interface (/dev/mtd*) of
the MTD layer, while for filesystem operations like mounting we must
use the block device interface (/dev/mtdblock*).

Probably even more interesting for embedded systems is the second
version of JFFS, JFFS2, since it not only fixes a few design issues
with JFFS, but also adds transparent compression, so that you can save
a lot of precious flash memory.

The mkfs.jffs2 tool is used to create a JFFS2 filesystem image; it
populates the image with files from a given directory. For instance,
to create a JFFS2 image for a flash partition of 3 MB total size and
to populate it with the files from the /tmp/flashtools directory you
would use:

Note: Especially when you are running time-critical applications
on your system you should carefully study if the behaviour of the
flash filesystem might have any negative impact on your application.
After all, a flash device is not a normal harddisk. This is especially
important when your flash filesystem gets full; JFFS2 acts a bit weird
then:

You will note that an increasing amount of CPU time is spent by
the filesystem's garbage collection kernel thread.

Access times to the files on the flash filesystem may increase
drastically.

This is especially critical when you are using the flash filesystem to
store log files: when your application detects some abnormal condition
and produces lots of log messages (which usually are especially
important in this situation) the filesystem may fill up and cause
extreme long delays - if your system crashes, the most important
messages may never be logged at all.

In some cases it is sufficent to have read-only access to some files,
and if the files are big enough it becomes desirable to use some
method of compression. The Compressed ROM Filesystem CramFs might
be a solution here.

Please note that CramFs has - beside the fact that it is a
read-only filesystem - some severe limitations (like missing support
for timestamps, hard links, and 16/32 bit uid/gids), but there are
many situations in Embedded Systems where it's still useful.

To create a CramFs filesystem a special tool
mkcramfs is used to create a file which contains
the CramFs image. Note that the CramFs filesystem can be written and
read only by kernels with PAGE_CACHE_SIZE == 4096, and some versions
of the mkcramfs program may have other
restrictions like that the filesystem must be written and read with
architectures of the same endianness. Especially the endianness
requirement makes it impossible to build the CramFs image on x86 PC
host when you want to use it on a PowerPC target. The endianness
problem has been fixed in the version of mkcramfs
that comes with the ELDK.

In some cases you can use a target system running with root
filesystem mounted over NFS to create the CramFs image on the native
system and store it to flash for further use.

Note: The normal version of the mkcramfs program
tries to initialize some entries in the filesystem's superblock with
random numbers by reading /dev/random; this may
hang permanently on your target because there is not enough input
(like mouse movement) to the entropy pool. You may want to use a
modified version of mkcramfs which does not depend
on /dev/random.

To create a CramFs image, you put all files you want in the
filesystem into one directory, and then use the
mkcramfs= program as follows:

The tmpfs filesystem, formerly known as shmfs, is a filesystem
keeping all files in virtual memory.

Everything in tmpfs is temporary in the sense that no files will be
created on any device. If you unmount a tmpfs instance,
everything stored therein is lost.

tmpfs puts everything into the kernel internal caches and grows and
shrinks to accommodate the files it contains and is able to swap
unneeded pages out to swap space. It has maximum size limits which can
be adjusted on the fly via 'mount -o remount ...'

If you compare it to ramfs (which was the template to create tmpfs)
you gain swapping and limit checking. Another similar thing is the RAM
disk (/dev/ram*), which simulates a fixed size hard disk in physical
RAM, where you have to create an ordinary filesystem on top. Ramdisks
cannot swap and you do not have the possibility to resize them.

size: The limit of allocated bytes for this tmpfs instance. The
default is half of your physical RAM without swap. If you
oversize your tmpfs instances the machine will deadlock
since the OOM handler will not be able to free that memory.

nr_blocks: The same as size, but in blocks of PAGECACHE_SIZE.

nr_inodes: The maximum number of inodes for this instance. The default
is half of the number of your physical RAM pages.

These parameters accept a suffix k, m or g for kilo, mega and giga and
can be changed on remount.

To specify the initial root directory you can use the following mount
options:

mode: The permissions as an octal number

uid: The user id

gid: The group id

These options do not have any effect on remount. You can change these
parameters with chmod(1), chown(1) and chgrp(1) on a mounted
filesystem.

So the following mount command will give you a tmpfs instance on
/mytmpfs which can allocate 12MB of RAM/SWAP and it is only accessible
by root.

In order to use a tmpfs filesystem, the CONFIG_TMPFS option has to be
enabled for your kernel configuration. It can be found in the
Filesystems configuration group. You can simply check if a running
kernel supports tmpfs by searching the contents of /proc/fileysystems:

In embedded systems tmpfs is very well suited to provide read and write
space (e.g. /tmp and /var) for a read-only root file system such
as CramFs described in section
9.1.4. Compressed ROM Filesystem.
One way to achieve this is to use symbolic links. The following code
could be part of the startup file /etc/rc.sh of the read-only ramdisk:

The commented out sections will of course fail on a read-only root filesystem,
so you have to create the /tmpfs mount-point and the symbolic links in your root
filesystem beforehand in order to successfully use this setup.

If your board is equipped with a PC-Card adapter (also known as
PCMCIA adapter) you can use this for miscellaneous types of mass
storage devices like Flash Disks, CompactFlash, and IDE Harddisks.

Please note that there are other options to operate such devices on
Embedded PowerPC Systems (for instace you can use the PCMCIA
controller builtin to the MPC8xx CPUs to build a direct IDE
interface, or you can use some external controller to provide such an
interface). The following description does not cover such
configurations. Only the solution which uses a standard PC Card Slot
is described here.

The standard way to use PC Cards in a Linux system is to install the
"PCMCIA Card Services" package. This is a quite complex set of kernel
modules and tools that take care of things like automatic detection
and handling of "card insert" or "remove" events, identification of
the inserted cards, loading the necessary device drivers, etc. This is
a very powerful package, but for embedded applications it has several
serious disadvantages:

Memory footprint - the package consists of a lot of tools and
modules that take a lot of space both in the root filesystem and
in system RAM when running

Chicken and Egg Problem - the package loads the needed device
drivers as kernel modules, so it needs a root filesystem on
another device; that means that you cannot easily put the root
filesystem on a PC Card.

For "disk" type PC Cards (FlashDisks, CompactFlash, Hard Disk Adapters
- basicly anything that looks like an ordinary IDE drive) an
alternative solution is available: direct support within the Linux
kernel. This has the big advantage of minimal memory footprint, but of
course it comes with a couple of disadvantages, too:

It works only with "disk" type PC Cards - no support for modems,
network cards, etc; for these you still need the PCMCIA Card
Services package.

There is no support for "hot plug", i. e. you cannot insert or
remove the card while Linux is running. (Well, of course you
can do this, but either you willnot be able to access any card
inserted, or when you remove a card you will most likely crash
the system. Don't do it - you have been warned!)

The code relies on initialization of the PCMCIA controller by the
firmware (of course U-Boot will do exactly what's required).

On the other hand these are no real restrictions for use in an
Embedded System.

To enable the "direct IDE support" you have to select the following
Linux kernel configuration options:

You can now access your PC Card "disk" like any normal IDE drive. If
you start with a new drive, you have to start by creating a new
partition table. For PowerPC systems, there are two commonly used
options:

At first we create two small partitions that will be used to store a
Linux boot image; a compressed Linux kernel is typically around 400
... 500 kB, so chosing a partition size of 2 MB is more than generous.
2 MB coresponds to 4096 disk blocks of 512 bytes each, so we enter:

The MS-DOS partition table is especially common on PC type computers,
which these days means nearly everywhere. You will prefer this format
if you want to exchange your "disk" media with any PC type host
system.

The fdisk command is used to create MS-DOS type
partition tables; to create the same partitioning scheme as above you
would use the following commands:

# fdisk /dev/hda
Device contains neither a valid DOS partition table, nor Sun, SGI or OSF disklabel
Building a new DOS disklabel. Changes will remain in memory only,
until you decide to write them. After that, of course, the previous
content won't be recoverable.
The number of cylinders for this disk is set to 1575.
There is nothing wrong with that, but this is larger than 1024,
and could in certain setups cause problems with:
1) software that runs at boot time (e.g., old versions of LILO)
2) booting and partitioning software from other OSs
(e.g., DOS FDISK, OS/2 FDISK)
Command (m for help): m
Command action
a toggle a bootable flag
b edit bsd disklabel
c toggle the dos compatibility flag
d delete a partition
l list known partition types
m print this menu
n add a new partition
o create a new empty DOS partition table
p print the partition table
q quit without saving changes
s create a new empty Sun disklabel
t change a partition's system id
u change display/entry units
v verify the partition table
w write table to disk and exit
x extra functionality (experts only)

U-Boot provides only basic functionality to access PC Card based
"disks": you can print the partition table and read and write blocks
(addressed by absolute block number), but there is no support to
create new partitions or to read files from any type of filesystem.

[Such features could be easily added as U-Boot extensions aka
"standalone programs", but so far it has not been implemented yet.]

As usual, you can get some information about the available IDE
commands using the help command in U-Boot:

That means you will have to partition the "disk" on your host system;
U-Boot can be configured for DOS and MacOS type partition tables.
Since U-Boot cannot read files from a filesystem you should create
one (or more) small partitions (maybe 1 MB or so) if you want to boot
from the "disk".

For example on a 128 MB CompactFlash card we could create the
following partiton table under Linux:

Here we have two small boot partitions (/dev/hda1 and /dev/hda2, 2
MB each), one big partition to hold a filesystem (/dev/hda3, 99 MB),
and a swap partition (/dev/hda4, 22 MB). We also initialized
/dev/hda4 as swap space.

This requires a little more explanation: as you can see from the
output of the help ide command, the
write subcommand takes 3 arguments: a memory
address from where the data are read, an (absolute) block number on
the disk where the writing starts, and a number of disk blocks.

Since U-Boot expects all input in hex notation we have to perform
some calculation: partition 1 starts at block (or sector) number 32,
which is 0x20; partition 2 starts at block number 4352 = 0x1100.

We used a block count of 0x800 = 2048 in both cases - this means we
wrote 2048 block of 512 bytes each, or a 1024 kB - much more than the
actual size of the LInux kernel image - but the partition is big
enough and we are on the safe side, so we didn't bother to calculate
the exact block count.

To boot from a disk you can use the diskboot command:

=> help diskboot
diskboot loadAddr dev:part

The diskboot command (or short disk) expects a load address in
RAM, and a combination of device and partition numbers, separated by a
colon. It then reads the image from disk and stores it in memory. We
can now boot it using the bootm command [to automatically boot the
image define the U-Boot environment autostart with the value =yes=].

We can use the same method that we used to store a Linux kernel image
to a disk partition to load a filesystem image into another partiton
- as long as the image fits into physical RAM - but usually it's
easier to initialize the filesystem either on the host system
(swapping the PC Card between host and target is easy enough), or you
can use the configuration with root filesystem over NFS to populate
the filesystem on the target.

You only have to set the bootargs variable to boot
Linux with root filesystem on disk, for instance:

If you forgot to reserve (sufficient) space in a separate partition
on your disk, you can still use an ordinary file for swap space. You
only have to create a file of appropriate size, and initialize it as
follows:

To complement the U-Boot Splash Screen feature the
new configuration option "CONFIG_8xx_PRE_INIT_FB" was added to the
Linux kernel. This allows the Linux kernel to skip certain parts of the framebuffer initialization and to reuse the framebuffer contents that was set up by the U-Boot firmware. This allows to have an image displayed nearly immediately after power-on, so the delay needed to boot the Linux kernel is masked to the user.

The current implementation has some limitations:

We did not succeed in reusing the previously allocated framebuffer
contents directly. Instead, Linux will allocate a new framebuffer,
copy the contents, and then switch the display. This adds a minimal
delay to the boot time, but is otherwise invisible to the user.

Linux manages its own colormap, and we considered it too much effort
to keep the same settings as used by U-Boot. Instead we use the "trick"
that U-Boot will fill the color map table backwards (top down). This works
pretty well for images which use no more than 200...255 colors.
If the images uses more colors, a bad color mapping may result.
We strongly recommend to convert all images that will be loaded
as Linux splash screens to use no more than 225 colors. The "ppmquant"
tool can be used for this purpose
(see Bitmap Support in U-Boot for details).

Usually there will be a Linux device driver that is used to adjust the
brightness and contrast of the display. When this driver starts, a visible
change of brightness will happen if the default settings as used by U-Boot
differ.
We recommend to store settings of brightness and contrast in U-Boot
environment variables that can be shared between U-Boot and Linux. This
way it is possible (assuming adequate driver support) to adjust the
display settings correctly already in U-Boot and thus to avoid any flicker
of the display when Linux takes over control.

It is not an easy task to design the root file system
for an embedded system.
There are three major problems to be solved:

what to put in it

which file system type to use

where to store and how to boot it

For now we will assume that the contents of the root file system
is aready known;
for example, it is given to us as a directory tree
or a tarball which contains all the required files.

We will also assume that our system is a typical resource-limited embedded
system so we will especially look for solutions where the root file system can be stored on on-board flash memory or other flash memory based devices like CompactFlash or SD cards, MMC or USB memory sticks.

So our focus here is on the second item:
the options we have for
chosing a file system type and the consequences this has.

In all cases we will base our experiments on the same content of the
root filesystem; we use the images of the SELF (Simple Embedded Linux Framework) that come with the ELDK. In a first step we will transform the
SELF images into a tarball to meet the requirements mentioned above:

In a ELDK installation, the SELF images can be found in the
/opt/eldk/<architecture>/images/ directory.
There is already a compressed ramdisk image in this directory,
which we will use (ramdisk_image.gz):

Ram disks are used very often to hold the root file system of embedded systems. They have several advantages:

well-known

well-supported by the Linux kernel

simple to build

simple to use - you can even combine the ramdisk
with the Linux kernel into a single image file

RAM based, thus pretty fast

writable file system

original state of file system after each reboot = easy
recovery from accidental or malicious data corruption etc.

On the other hand, there are several disadvantages, too:

big memory footprint:
you always have to load the complete filesystem into RAM,
even if only small parts of are actually used

slow boot time: you have to load (and uncompress) the whole
image before the first application process can start

only the whole image can be replaced (not individual files)

additional storage needed for writable persistent data

Actually there are only very few situations where a ramdisk image is the
optimal solution. But because they are so easy to build and use we will discuss them here anyway.

In almost all cases you will use an ext2 file system in your ramdisk
image. The following steps are needed to create it:

Create a directory tree with the content of the target root filesystem.
We do this by unpacking our master tarball:

$ mkdir rootfs
$ cd rootfs
$ tar zxf /tmp/rootfs.tar.gz

We use the genext2fs tool to create the ramdisk image
as this allows to use a simple
text file to describe which devices shall be created in the
generated file system image.
That means that no root permissions are required at all.
We use the following device table
rootfs_devices.tab:

JFFS2 (Journalling Flash File System version 2)
was specifically designed for use on flash memory devices
in embedded systems.
It is a log-structured file system which means that it is robust
against loss of power, crashes or other unorderly shutdowns of the system
("robust" means that data that is just being written when the
system goes down may be lost,
but the file system itself does not get corrupted
and the system can be rebootet without need for any kind
of file system check).

Some of the advantages of using JFFS2 as root file system in embedded systems
are:

file system uses compression, thus making efficient use of flash memory

log-structured file system, thus robust against unorderly shutdown

writable flash file system

Disadvantages are:

long mount times (especially older versions)

slow when reading: files to be read get uncompressed on the fly
which eats CPU cycles and takes time

slow when writing: files to be written get compressed,
which eats CPU cycles and takes time, but it may even take much
longer until data gets actually stored in flash if the file system
becomes full and blocks must be erased first or - even worse - if
garbage collection becomes necessary

The garbage collector thread may run at any time,
consuming CPU cycles and blocking accesses to the file system.

Despite the aforementioned disadvantages,
systems using a JFFS2 based root file system are easy to build,
make efficient use of the available resources
and can run pretty reliably.

To create a JFFS2 based root file system please proceed as follows:

Create a directory tree with the content of the target root filesystem.
We do this by unpacking our master tarball:

$ mkdir rootfs
$ cd rootfs
$ tar zxf /tmp/rootfs.tar.gz

We can now create a JFFS2 file system image using the
mkfs.jffs2 tool:

file system uses compression,
thus making efficient use of flash memory

Allows for quick boot times as only used files get
loaded and uncompressed

Disadvantages are:

only the whole image can be replaced (not individual files)

additional storage needed for writable persistent data

mkcramfs tool does not support device table,
so we need root permissions to create the required device files

To create a cramfs based root file system please proceed as follows:

Create a directory tree with the content of the target root filesystem.
We do this by unpacking our master tarball:

$ mkdir rootfs
$ cd rootfs
$ tar -zxf /tmp/rootfs.tar.gz

Create the required device files. We do this here by unpacking
a special tarball which holds only the device file entries.
Note: this requires root permissions!

# cd rootfs
# tar -zxf /tmp/devices.tar.gz

Many tools require some storage place in a filesystem,
so we must provide at least one (small) writable filesystem.
For all data which may be lost when the system goes down,
a "tmpfs" filesystem is the optimal choice.
To create such a writable tmpfs filesystem we add the
following lines to the /etc/rc.sh script:

Some tools require write permissions on some device nodes
(for example, to change ownership and permissions),
or dynamically (re-) create such files
(for example, /dev/log which is usually a Unix Domain socket).
The files are placed in a writable filesystem;
in the root filesystem symbolic links are used
to point to their new locations:

dev/ptyp0

→

/tmpfs/dev/ptyp0

dev/ttyp0

→

/tmpfs/dev/ttyp0

dev/ptyp1

→

/tmpfs/dev/ptyp1

dev/ttyp1

→

/tmpfs/dev/ttyp1

dev/ptyp2

→

/tmpfs/dev/ptyp2

dev/ttyp2

→

/tmpfs/dev/ttyp2

dev/ptyp3

→

/tmpfs/dev/ptyp3

dev/ttyp3

→

/tmpfs/dev/ttyp3

dev/ptyp4

→

/tmpfs/dev/ptyp4

dev/ttyp4

→

/tmpfs/dev/ttyp4

dev/ptyp5

→

/tmpfs/dev/ptyp5

dev/ttyp5

→

/tmpfs/dev/ttyp5

dev/ptyp6

→

/tmpfs/dev/ptyp6

dev/ttyp6

→

/tmpfs/dev/ttyp6

dev/ptyp7

→

/tmpfs/dev/ptyp7

dev/ttyp7

→

/tmpfs/dev/ttyp7

dev/ptyp8

→

/tmpfs/dev/ptyp8

dev/ttyp8

→

/tmpfs/dev/ttyp8

dev/ptyp9

→

/tmpfs/dev/ptyp9

dev/ttyp9

→

/tmpfs/dev/ttyp9

dev/ptypa

→

/tmpfs/dev/ptypa

dev/ttypa

→

/tmpfs/dev/ttypa

dev/ptypb

→

/tmpfs/dev/ptypb

dev/ttypb

→

/tmpfs/dev/ttypb

dev/ptypc

→

/tmpfs/dev/ptypc

dev/ttypc

→

/tmpfs/dev/ttypc

dev/ptypd

→

/tmpfs/dev/ptypd

dev/ttypd

→

/tmpfs/dev/ttypd

dev/ptype

→

/tmpfs/dev/ptype

dev/ttype

→

/tmpfs/dev/ttype

dev/ptypf

→

/tmpfs/dev/ptypf

dev/ttypf

→

/tmpfs/dev/ttypf

tmp

→

/tmpfs/tmp

var

→

/tmpfs/var

dev/log

→

/var/log/log

In case you use dhclient also:

etc/dhclient.conf

→

/tmpfs/var/lib/dhclient.conf

etc/resolv.conf

→

/tmpfs/var/lib/resolv.conf

To place the corresponding directories and device files
in the tmpfs file system,
the following code is added to the /etc/rc.sh script:

When storing the root file system in on-board flash memory
it seems only natural to look for special falsh filesystems
like JFFS2, or for other file system types that are designed
for such environments like cramfs.
It seems to be a bad idea to use a standard ext2 file system
because it contains neither any type of wear levelling which
is needed for writable file systems in flash memory,
nor is it robust against unorderly shutdowns.

The situation changes if we use an ext2 file system which we mount
read-only. Such a configuration can be very useful in some situations.

Advantages:

very fast

low RAM memory footprint

Disadvantages:

high flash memory footprint because no compression

To create an ext2 image
that can be used as a read-only root file system
the following steps are necessary:

Create a directory tree with the content of the target root filesystem.
We do this by unpacking our master tarball:

$ mkdir rootfs
$ cd rootfs
$ tar -zxf /tmp/rootfs.tar.gz

Like with the cramfs root file system, we use
"tmpfs" for cases where a writable file system is
needed and add the
following lines to the /etc/rc.sh script:

We can again use the same setup as before for the JFFS2 filesystem,
just changing the bootargument to "rootfstype=ext2"
(or simply omit it completely as this is the default anyway),
and we must change the "rw" argument into "ro" to mount
our root file system really read-only:

Using an ext2 file system on a flash memory card
(like CompactFlash, SD, MMC or a USB memory stick)
is standard technology.
To avoid unnecessary flash wear it is a good idea to mount
the root file system read-only,
or at least using the "noatime" mount option.

For our test we can use the "ext2.img" file from the previous
step without changes:

In this test we use a standard CompactFlash card
which comes with a single partition on it. We use U-Boot to copy
the ext2 file system image into this partition:

Note that the "ide write" command takes parameters as hex numbers,
and the write count is in terms of disk blocks of 512 bytes each.
So we have to use 0x20 for the starts sector of the first partition,
and 3788800 / 512 = 7400 = 0x1CE8 for the block count.

We now prepare the Linux boot arguments
to take this partition as read-only root device:

This is a more complicated example that shows that - depending
on project requirements - many other alternatives for chosing a root
file system for your embedded system exist.

The szenario is as follows: on your embedded device you use a
cheap and popular storage medium like CompactFlash, MMC or SD cards
or USB memory sticks
to store both the Linux kernel and your root file system.
You want to distribute software updates over the internet:
your customers can download the file from your web site,
or you sent the images by email.
Your customers may use any flash card or memory stick they happen to find,
so you have no information about brand or size of the storage device.

Unfortunately most of your customers use Windows systems.
And they don't want to be bothered with long instructions
how to create special partitions on the storage device
or how to write binary images or things like that.
A simple "copy file" operation is nearly exhausting their capabilities.

What to do?
Well, if copying a file is all your customers can do we should
not ask for more. Storage devices like CompactFlash cards etc.
typically come with a single partition on it, which holds a FAT or
VFAT file system. This cannot be used as a Linux root file system directly,
so we have to use some trickery.

Here is one possible solution:
Your software distribution consistes of two files:
The first file is the Linux kernel with a minimal ramdisk image attached
(using the multi-file image format for U-Boot);
U-Boot can load and boot such files from a FAT or VFAT file system.
The second file is your root file system.
For convenience and speed we use again an image of an ext2
file system.
When Linux boots, it will initially use the attached ramdisk
as root file system.
The programs in this ramdisk will mount the FAT or VFAT file system -
read-only.
Then we can use a loop device (see losetup(8))
to associate the root file system image with a block device
which can be used as a mount point.
And finally we use pivot_root(8) to change the root file system
to our image on the CF card.

This sounds not so complicated,
and actually it is quite simple once
you understand what needs to be done.
Here is a more detailed description:

The root file system image is easy:
as mantioned before, we will use an ext2 file system image,
and to avoid wearing the flash storage device we will use it
in read-only mode - we did a read-only ext2 root file system image
before, and here we can just re-use the existing image file.

The initial ramdisk image that performs the pivot_root step
must be created from scratch,
but we already know how to create ramdisk images,
so we just have to figure out what to put in it.

The most important tool here is nash,
a script interpreter that was specifically designed for
such purposes (see nash(8)).
We don't need any additional tools,
and if we use static linking,
that the nash binary plus a small script to control it
is all we need for our initial ramdisk.

To be precise, we need a couple of (empty) directories
(bin, dev, etc, lib, loopfs, mnt, proc, and sysroot),
the bin/nash binary,
the linuxrc script
and a symbolic link sbin pointing to bin:

The first line says that it's a script file for the /bin/nash
interpreter.
Note: even if this file looks like a shell script
it is NOT interpreted by a shell,
but by the nash interpreter.
For a complete list of available nash commands and their syntax
please refer to the manual page, nash(8).

The first action is to mount the /proc pseudo file system
which is needed to find out some required information.

Then we create block device entries for all partitions
listed in /proc/partitions (mkdevices command).

In the next step a block device for our new root file system
is created (mkrootdev command).

Then we mount the CF card.
We assume that there is only a single partition on it (/dev/hda1)
which is of type VFAT
(which also will work with FAT file systems).
These assumptions work fine with basicly all memory devices
used under Windows.

We further assume that the file name of the
root file system image on the
CF card is "rootfs.img" - this file now gets mounted
using a loop device (losetup and mount commands).

Our file system image,
is now mounted on the /sysroot directory.
In the last step we use pivot_root to make
this the new root file system.

As a final cleanup we unmount the /proc file system which
is not needed any more.

There is one tiny flaw in this method:
since we mount the CF card on a directory in the ramdisk
to be able to access to root file system image.
This means that we cannot unmount the CF card,
which in turn prevents us from freeing the space for the
inital ramdisk.
The consequence is that you permanently lose
approx. 450 kB of RAM for the ramdisk.
[We could of course re-use this ramdisk space for temporary data,
but such optimization is beyond the scope of this document.]

And how does this work on our target?

First we copy the two images to the CF card; we do this
on the target under Linux:

As you can see, the ramdisk solution is the worst of all
in terms of RAM memory footprint;
also it takes a pretty long time to boot.
However, it is one of the few solutions that allow an in-situ
update while the system is running.

JFFS2 is easy to use as it's a writable file system
but it takes a long time to boot.

A read-only ext2 file system shines when boot time and RAM memory
footprint are important; you pay for this with an increased flash memory
footprint.

External flash memory devices like CompactFlash cards or USB memory
sticks can be cheap and efficient solutions especially when
lots of data need to be stored or when easy update procedures are required.
-

Introduction

Overlay File Systems provide an interesting approach to several frequent
problems in Embedded Systems.
For example,
mini_fo is a virtual kernel file system
that can make read-only file systems writable.
This is done by redirecting modifying operations
to a writeable location called "storage directory",
and leaving the original data in the "base directory" untouched.
When reading, the file system merges the modifed
and original data so that only the newest versions will appear.
This occurs transparently to the user,
who can access the data like on any other read-write file system.

What it is good for?

In embedded systems the main use of mini_fo
is to overlay the root file system.
This means it is mounted on top of the regular root file system,
thereby allowing applications or users
to transparently make modifications to it
but redirecting these to a different location.

Some examples of why this is usefull are explained in the following sections.

Making a read-only root filesystem writeable

Root file systems stored in flash are often read only,
such as cramfs
or read only ext2.
While this offers major advantages in terms of speed and flash memory footprint,
it nevertheless is often desireable to be able to modify the root file system,
for example to

apply (small) software updates
without having to burn a whole new root file system image to flash

make modifications during developement
when frequent changes to the root file system occur.

This can be achieved by mounting mini_fo
on top of the root file system
and using a (probably small) writeable partition
as the storage file system.
This could be either a JFFS2 flash file system,
or during development even an external hard disk.
This has the following advantages:

read-only file systems
(fast, small memory footprint)
can be used like persistent writable file systems
(in contrast to a ramdisk)

slow flash journalling file systems
with large flash memory footprint can be avoided.

Non persistant changes

Ramdisks are often used
when the root file system needs to be modified non-persistantly.
This works well,
but downsides are the large RAM memory footprint
and the time costly operation of copying the ramdisk into RAM
during startup.
These can be avoided by overlaying the root file system
as in the previous example
but with the difference that the tmpfs file system
is used as storage.
Thus only modified files are stored in RAM,
and can even be swapped out if neccessary.
This saves boot time and RAM!

Resetable changes

Mini_fo can be easily used to implement a
"reset to factory defaults" function
by overlaying the default root file system.
When configuration changes are made,
these are automatically directed to the storage file system
and take precedence over the original files.
Now, to restore the system to factory defaults,
all that needs to be done is delete
the contents of the storage directory.
This will remove all changes made to the root file system
and return it to the original state.

Note: Deleting the contents of the storage directory
should only be done when the overlay file system is unmounted.

Examples

Generally,
there are two different ways of overlaying the root file system,
which both make sense in different scenarios.

Starting a single application in a chrooted overlayed environment

This is easy.
Let's assume "/" is the read-only root file system
and /dev/mtdblock5 contains a small JFFS2 flash partition
that shall be used to store modifications
made by application "/usr/bin/autoPilot":

The mini_fo file system is mounted with "/" as base directory,
"/tmp/sto/" as storage directory to the mount point "/mnt/mini_fo".
After that, chroot(1) is used to start the application
with the new file system root "/mnt/mini_fo".
All modifications made by the application
will be stored to the JFFS2 file system in /tmp/sto.

Starting the whole system system in chrooted overlayed environment

This is more interesting,
and a bit trickier,
as mounting needs to be done during system startup
after the root file system has been mounted,
but before init is started.
The best way to do this is to have a script
that mounts the mini_fo file system on top of root
and then starts init in the chrooted overlayed environment.
For example assume the following script "overlay_init", stored in /sbin/:

Now its easy to choose between a mini_fo overlayed
and the regular non overlayed system
just by setting the "init" kernel parameter
in the boot loader to "init=/sbin/overlay_init".

Tips

pivot_root(1) can be used with chroot
if there is need to access the original non overlayed root file system
from the chrooted overlayed environment.

Performance overhead

The mini_fo file system is inserted as an additional layer
between the VFS and the native file system,
and thus creates some overhead
that varies strongly
depending of the operation performed.

modifying a regular file for the first time
This results in a copy
of the original file
beeing created in the storage directory,
that is then modified.
Overhead depends on the size of the modified file.

Reading from files,
creating new files,
modifying already modified files
These operations are passed directly
through to the lower native layer,
and only impose an overhead of 1-2%.

Further information

This section discusses how the mini_fo overlay file system
can be used in embedded systems.
More general information is available at the
mini_fo project page:
http://www.denx.de/wiki/Know/MiniFOHome.

The pramfs file system supports persistent memory devices such as
SRAM. Instead of having a block emulation layer over such a
memory area and using a normal file system on top of that, pramfs
seeks to induce minimal overhead in this situation. Most
important in this respect is that the normal block layer caching of
the Linux kernel is circumvented in pramfs.

Having rebooted (using mem=224M on the kernel command line again of course)
we mount the file system but this time without the init parameter
because it is preinitialized. We then check the contents again:

The purpose of this document is not to provide an
introduction into programming and debugging in general. We assume
that you know how to use the GNU debugger gdb and
probably it's graphical frontends like ddd. We
also assume that you have access to adequate tools for your work, i.
e. a BDI2000 BDM/JTAG debugger. The following discussion assumes that
the host name of your BDI2000 is bdi.

Please note that there are several limitations in earlier versions of
GDB. The version of GDB as distributed with the ELDK contains several
bug fixes and extensions. If you find that your GDB behaves
differently, have a look at the GDB sources and patches that come
with the ELDK source.

When U-Boot starts it is running from ROM space. Running from flash would
make it nearly impossible to read from flash while executing code from flash
not to speak of updating the U-Boot image in flash itself. To be able to do
just that, U-Boot relocates itself to RAM. We therefore
have two phases with different program addresses. The following sections
show how to debug U-Boot in both phases.

For debugging U-Boot after relocation we need to know the address to which
U-Boot relocates itself to. When no exotic features like PRAM are used, this
address usually is <MAXMEM> - CFG_MONITOR_LEN. In our example with 16MB
RAM and CFG_MONITOR_LEN = 192KB this yields the address 0x1000000 - 0x30000 =
0xFD0000. With this knowledge, we can instruct gdb to forget the old symbol table
and reload the symbols with our calculated offset:

board_init_r is the first C routine running in the newly relocated C friendly RAM
environment.

The simple example above relocates the symbols of only one section, .text.
Other sections of the executable image (like .data, .bss, etc.) are not relocated
and this prevents gdb from accessing static and global variables by name.
See more sophisticated examples in section
10.3. GDB Startup File and Utility Scripts.

First start GDB in the root directory of your Linux kernel, using the
vmlinux kernel image as file to debug:

bash$ cd <linux-root>
bash$ ${CROSS_COMPILE}gdb vmlinux
GNU gdb 5.1.1
Copyright 2002 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "--host=i386-redhat-linux --target=ppc-linux".
(gdb)

The option -m prints out the addresses of the
various code and data segments (
.text,
.data,
.sdata,
.bss,
.sbss
) after relocation. GDB needs these
addresses to know where all the symbols are located. We now
interrupt GDB to load the symbol table of the module as follows:

To prevent GDB from jumping around in the code when trying to
single step, i. e. when it seems as if the code is not executing
line by line, you can recompile your code with the following
additional compiler options:

-fno-schedule-insns -fno-schedule-insns2

On some systems (like the MPC8xx or MPC8260) you can only define
one hardware breakpoint. Therefore you must delete an existing
breakpoint before you can define a new one:

gdbserver allows you to connect your program with
a remote GDB using the "target remote" command. On the target
machine, you need to have a copy of the program you want to debug.
gdbserver does not need your program's symbol
table, so you can strip the program if necessary to save space.
GDB on the host system does all the symbol
handling. Here is an example:

If the target program you want to debug is linked against shared
libraries, you must tell GDB where the proper target libraries are
located. This is done using the set solib-absolute-prefix GDB
command. If this command is omitted, then, apparently, GDB loads the
host versions of the libraries and gets crazy because of that.

The Linux Kernel
- describing most aspects of the Linux Kernel. Probably, the
first reference for beginners. Lots of illustrations explaining
data structures use and relationships. In short: a must have.

[Thanks to Rafal Jaworowski for these detailed instructions.]
This is a short tutorial how to host ELDK on FreeBSD 5.x and 6.x.
The procedure described below was tested on 5.2.1, 5.3 and 6-current releases;
we assume the reader is equipped with the ELDK 3.x CDROM or ISO image for installation,
and is familiar with FreeBSD basic administration tasks like ports/packages installation.

Prerequisites:

Install linux_base

The first step is to install the Linux compatibility layer from ports
/usr/ports/emulators/linux_base/ or packages
ftp://ftp.freebsd.org/pub/FreeBSD/ports/i386/packages/emulators/

Please make sure to install version 7.1_5 (linux_base-7.1_5.tbz) or later;
in particular, version 6.1.5 which can also be found in the ports tree
does not work properly!

The compatibility layer is activated by

# kldload linux

Install bash

Since ELDK and Linux build scripts are organised around bash while FreeBSD does
not have it in base, this shell needs to be installed either from ports
/usr/ports/shells/bash2/ or packages collection
ftp://ftp.freebsd.org/pub/FreeBSD/ports/i386/packages/shells/

The installation puts the bash binary in /usr/local/bin. It is a good
idea to create a symlink in /bin so that hash bang from scripts (#!/bin/bash)
works without modifications:

Copy the install files from the CDROM or ISO image to a writable location.
Brand the ELDK installer as Linux ELF file:

# cd <elkd_install_dir>
# brandelf -t Linux ./install

Note:
The following workaround might be a good alternative for the tedious
copying of the installation CDROM to a writable location and manual branding:
you can set a fallback branding in FreeBSD - when the loader
cannot recognise the ELF brand it will switch to the last resort defined.

There are three issues with the Makefile in the Linux kernel source tree:

GNU make has to be used.

The 'expr' utility in FreeBSD base behaves differently from the version
than is used in Linux
so we need to modify the Makefile to explicitly use the Linux version
(which is part of the Linux compatibility package).
This is best achieved with defining
"EXPR = /compat/linux/usr/bin/expr" somewhere at =Makefile='s beginning and
replacing all references to 'expr' with the variable ${EXPR).

Some build steps (like when running 'scripts/mkdep' can generate very long
arguments lists (especially is the Linux kernel tree is in a directory with
long absolute filenames). A solution is to use xargs to split such long
commands into several with shorter argument lists.

The Linux kernel can then be built following the standard instructions, for example:

I tried to install ELDK version 2.x on a SuSE 8.2 / SuSE 9 / RedHat-9 Linux host
but failed - it terminated without installing any packages. Why?

Answer:

Newer Linux distributions use libraries that are incompatible
to those used by the ELDK's installation tools.
This problem was fixed in later releases of the ELDK (version 3.0 and later).
It is therefore recommended to use a more recent version of the ELDK.
If you really want to install an old version,
the following back-port is available:

After configuring and compiling a Linux kernel in the
kernel source tree that comes with the ELDK, I cannot compile
user space programs any more - I get error messages because
many #include file like <errno.h> etc. are missing.
This is with ELDK 4.0 or 4.1.

Answer:

This problem is caused by the way how the ELDK is packaged.
At the moment, the ELDK kernel headers are not packed into a
separate "kernel-headers" RPM to avoid duplication, because
the kernel source tree is always installed.
Instead, the ELDK "kernel-headers" package is just a set of
symlinks. This worked fine in the past, but fails with the
new support for ARCH=powerpc systems.
The next version of the ELDK will contain a real kernel-headers RPM,
which will fix this problem.
As a workaround on current systems, you can install
the real kernel include files into the
"include/asm", "include/linux" and "include/mtd" directories.
To do this, the following commands can be used:

I don't want to erase my flash memory
because I'm not sure if my new U-Boot image will work.
Is it possible to configure U-Boot such that I can load it into RAM instead of flash,
and start it from my old boot loader?

Answer:

No.

Question:

But I've been told it is possible??

Answer:

Well, yes. Of course this is possible. This is software, so everything is possible.
But it is difficult, unsupported, and fraught with peril.
You are on your own if you choose to do it.
And it will not help you to solve your problem.

Question:

Why?

Answer:

U-Boot expects to see a virgin CPU, i. e. the CPU state must match what you see
if the processor starts executing the first instructions when it comes out of reset.
If you want to start U-Boot from another boot loader, you must disable a lot of code, i. e. all
initialization parts that already have been performed by this other boot loader, like
setting up the memory controller, initializing the SDRAM, initializing the serial port,
setting up a stack frame etc.
Also you must disable the relocation to RAM and adjust the link addresses etc.

This requires a lot of experience with U-Boot, and the fact that you had to
ask if this can be done means that you are not in a position to do this.

The code you have to disable contains the most critical parts in U-Boot, i. e. these
are the areas where 99% or more of all errors are located when you port U-Boot to a new
hardware. In the result, your RAM image may work, but in the end you will need a
full image to program the flash memory with it, and then you will have to enable
all this highly critical and completely untested code.

You see? You cannot use a RAM version of U-Boot to avoid testing a flash version,
so you can save all this effort and just burn your image to flash.

Question:

So how can I test an U-Boot image and recover my system if it doesn't work?

Answer:

Attach a BDI2000 to your board, burn the image to flash, and debug it in
it's natural environment, i. e. U-Boot being the boot loader of the system and
taking control over the CPU right as it comes out of reset.
If something goes wrong, erase the flash and program a new image. This is
a routine job using a BDI2000.

ELDK 3.0 uses GCC-3.2.2; your U-Boot sources are too old for this compiler.
GCC-3.x requires a few adaptions which were added in later versions of U-Boot.
Use for example the source tree (1.0.2) which is included with the ELDK,
or download the latest version from CVS.

I have ported U-Boot to a custom board. It starts OK, but crashes or
hangs after relocating itself to RAM. Why?

Answer:

Your SDRAM initialization is bad, and the system crashes when it
tries to fetch instructions from RAM. Note that simple read and write
accesses may still work, it's the burst mode that is failing. This only
shows up when caches are enabled because cache is the primary (or only) user
of burst operations in U-Boot. In Linux, burst accesses may also result from
DMA. For example, it is typical that a system may crash under heavy network load
if the Ethernet controller uses DMA to memory.

It is NOT sufficient to program the memory controller of your CPU;
each SDRAM chip also requires a specific initialization sequence which you
must adhere to to the letter - check with the chip manufacturer's
manual.

It has been observed that some operating systems like pSOS+ or VxWorks
do not stress the memory subsystem
as much as Linux or other UNIX systems like LynxOS do,
so just because your board appears to work running another OS
does not mean it is 100% OK.

Standard memory tests are not effective in identifying this type of problem because
they do not cause stressful cache burst read/write operations.

I have ported U-Boot to a custom board. It seems to boot OK, but it prints:

*** Warning - bad CRC, using default environment

Why?

Answer:

Most probably everything is OK. The message is printed because the flash sector or ERPROM containing the environment variables has never been initialized yet. The message will go away as soon as you save the envrionment variables using the saveenv command.

I want to debug U-Boot after relocation to RAM, but it doesn't work
since all the symbols are at wrong addresses now.

Answer:

To debug parts of U-Boot that are running from ROM/flash, i. e.
before relocation, just use a command like
"powerpc-linux-gdb uboot" as usual.

For parts of U-Boot that run from RAM, i. e.
after relocation, use "powerpc-linux-gdb"without
arguments, and use the add-symbol-file command in
GDB to load the symbol table at the relocation address in RAM. The
only problem is that you need to know that address, which depends on
RAM size, length reserved for U-Boot, size of "protected RAM" area,
etc. If in doubt, enable DEBUG mode when building U-Boot so it
prints the address to the console.

Note: when you want to switch modes during one debug session (i. e. without
restarting GDB) you can "delete" the current symbol information by using
the symbol-file command without arguments, and then either using
"symbol-file u-boot" for code before relocation, or
"add-symbol-file u-boot _offset_" for code after relocation.

I am using U-Boot with a Linux kernel version
Y (Y < 2.4.5-pre5), but the last message I see is

Uncompressing Kernel Image ... OK

Then the system hangs.

Answer:

Most probably you pass bad parameters to the Linux kernel.
There are several possible reasons:

Bad definition of the bd_info structure
You must make sure that your machine specific header file
(for instance include/asm-ppc/tqm8xx.h)
includes the same definition of the Board Information
structure as we define in
include/ppcboot.h, and make sure that
your definition of IMAP_ADDR uses the same
value as your U-Boot configuration in
CFG_IMMR.

Bad clock information
Before kernel version 2.4.5-pre5 (BitKeeper Patch 1.1.1.6,
22MAY2001) the kernel expected the clock information in MHz,
but recent kernels expect it in Hz instead. U-Boot passes
the clock information in Hz by default.
To switch to the old behaviour, you can set the
environment variable "clocks_in_mhz" in U-Boot:

=> setenv clocks_in_mhz 1
=> saveenv

For recent kernel the "clocks_in_mhz" variable must not be set.
If it is present in your environment, you can delete it as follows:

=> setenv clocks_in_mhz
=> saveenv

A common error is to try "setenv clocks_in_mhz 0" or to some other value - this
will not work,
as the value of the variable is not important at all.
It is the existence of the variable that will be checked.

Inconsistent memory map
Some boards may need corrct mappings for some special hardware devices like
BCSR (Board Control and Status Registers) etc.
Verify that the mappings expected by Linux match those created by U-Boot.

Remember that flash memory cannot be erased in arbitrary areas, but
only in so called "erase regions" or "sectors". If you have U-Boot
running you can use the flinfo (Flash information,
short fli) command to print information about the
flash memory on your board, for instance:

Ethernet does not work on my board. I have configured a MAC address
of 01:02:03:04:05:06, and I can see that an ARP
packet is sent by U-Boot, and that an ARP reply is sent by the
server, but U-Boot never receives any packets. What's wrong?

Answer:

You have chosen a MAC address which, according to the ANSI/IEEE
802-1990 standard, has the multicast bit set. Under normal conditions
a network interface discards such packets, and this is what
U-Boot is doing. This is not a bug, but correct behaviour.

For bring-up testing in the lab you can also use so-called
locally administered ethernet addresses. These are addresses that
have the 2nd LSB in the most significant byte of MAC address set.
The gen_eth_addr tool that comes with U-Boot (see "tools/gen_eth_addr" )
can be used to generate random addresses from this pool.

You have to buy a block of 4096 MAC addresses (IAB = Individual Address Block)
or a block of 16M MAC addresses (OUI = Organizationally Unique Identifier,
also referred to as 'company id') from IEEE Registration Authority.
The current cost of an IAB is $550.00, the cost of an OUI is $1,650.00.
See http://standards.ieee.org/regauth/oui/index.shtml

You can set the "locally administered" bit to make your own MAC address (no guarantee of uniqueness, but pretty good odds if you don't do something dumb). Ref: Wikipedia

Universally administered and locally administered addresses are distinguished by setting the second least significant bit of the most significant byte of the address. If the bit is 0, the address is universally administered. If it is 1, the address is locally administered. The bit is 0 in all OUIs. For example, 02-00-00-00-00-01. The most significant byte is 02h. The binary is 00000010 and the second least significant bit is 1. Therefore, it is a locally administered address.

If the target is connected directly to the host PC (i. e. without a switch inbetween)
the problem goes away or is at least less incisive.

What's wrong?

Answer 1:: Most probably you have a full duplex/half duplex problem.
Verify that U-Boot is setting the ethernet interface on your board
to the proper duplex mode (full/half).
I'm guessing your board is half duplex but your switch is
full (typical of a switch ;-).

The switch sends traffic to your board while your board is
transmitting... that is a collision (late collision at that) to your
board but is OK to the switch. This doesn't happen nearly as much with
a direct link to your PC since then
you have a dedicated link without much asynchronous traffic.

The software (U-Boot/Linux) needs to
poll the PHY chip for duplex mode and then (re)configure the MAC chip
(separate or built into the CPU) to match.
If the poll isn't happening
or has a bug, you have problems like described above.

If this doesn't work, fix your TFTP server configuration and
make sure it is running.
(2) If your TFTP server is working, run ethereal (or
equivalent ethernet sniffing) to see what ethernet packets are
being sent by your development board. It usually works best to
run ethereal on your TFTP server (if you run it on a different
machine and you use an ethernet switch, the third machine
likely won't see the tftp packets).

variable substitution using "... ${_variablename_} ..." syntax
NOTE:
Older versions of U-Boot used "$(...)" for variable substitution.
Support for this syntax is still present in current versions,
but will be removed soon.
Please use "${...}" instead, which has the additional benefit
that your environment definitions are compatible with the Hush shell, too.

special characters ('$', ';') can be escaped by prefixing with '\', for example:

setenv bootcmd bootm \${address}

You can also escape text by enclosing in single apostrophes, for example:

similar to Bourne shell, with control structures like
if...then...else...fi, for...do...done, while...do...done,
until...do...done, ...

supports environment ("global") variables (through setenv /
saveenv commands) and local shell variables (through standard
shell syntax name=value ); only environment variables can be
used with the run command, especially as the variable to run
(i. e. the first argument).

In the current implementation, the local variables space and
global environment variables space are separated. Local
variables are those you define by simply typing like
name=value. To access a local variable later on, you have to
write '$name' or '${name}'; to execute the contents of a
variable directly you can type '$name' at the command prompt.
Note that local variables can only be used for simple commands,
not for compound commands etc.

Global environment variables are those you can set and print
using setenv and printenv. To run a command stored in such a
variable, you need to use the run command, and you must not
use the '$' sign to access them.

To store commands and special characters in a variable, use
single quotation marks surrounding the whole text of the
variable, instead of the backslashes before semicolons and
special symbols.

Be careful when using the hash ('#') character - like with a
"real" Bourne shell it is the comment character, so you have to
escape it when you use it in the value of a variable.

Instead of "echo Image OK" there could be a command (sequence) to
boot or otherwise deal with the correct image; instead of the
"echo Image corrupted!!"
there could be a command (sequence) to (load and)
boot an alternative image, etc.

This will check if the image at (flash?) address "addr1" is ok and
boot it; if the image is not ok, the alternative image at address
"addr2" will be checked and booted if it is found to be OK. If both
images are missing or corrupted, a new image will be loaded over TFTP
and booted.

If a command line (or an environment variable executed by a run
command) contains several commands separated by semicolons, and
one of these commands fails, the remaining commands will still be executed.

If you execute several variables with one call to run (i. e.
calling run with a list of variables as arguments), any failing
command will cause run to terminate, i. e. the remaining
variables are not executed.

To find out what happened, you can try to decode the stack backtrace
(the list of addresses printed after the "Call backtrace:" line.
The backtrace tool can be used
for this purpose. However, there is a little problem: the addresses printed
for the stack backtrace are after relocation of the U-Boot code to RAM;
to use the backtrace tool you need to know U-Boot's address offset
(the difference between the start address of U-Boot in flash and
its relocation address in RAM).

The easiest way to find out the relocation address is to enable debugging for
the U-Boot source file lib_*/board.c - U-Boot will then print some debug
messages

...
Now running in RAM - U-Boot at: 00f75000
...

Now you have to calculate the address offset between your link address
(The value of the TEXT_BASE definition in your board/?/config.mk file).
In our case this value is 0x40000000, so the address offset is
0x40000000 - 0x00f75000 = 0x3f08b000

Now we use the backtrace script with the System.map file in the U-Boot source tree and this address offset:

Check your linker script board/your_board/u-boot.lds
which controls how the object files are linked together
to build the U-Boot image.

It looks as if your board uses an "embedded" environment, i. e. the flash
sector containing the environment variables is surrounded by code.
The u-boot.lds tries to collect as many as possible code in the first
part, making the gap between this first part and the environment
sector as small as possible. Everything that does not fit is then
placed in the second part, after the environment sector.

Some your modifications caused the code that was put in this
first part to grow, so that the linker finds that it would have to
overwrite space that is already used.

Try commenting out one (or more) line(s) before the line containing
the "common/environment.o" statement. [ "lib_generic/zlib.o" is usually
a good candidate for testing as it's big ]. Once you get U-Boot linked, you can
check in the u-boot.map file how big the gap is, and which object
files could be used to fill it up again.

Can I use U-Boot to load and uncompress a compressed
image from flash into RAM? And can I choose whether I want to
automatically run it at that time, or wait until later?

Answer:

Yes to both questions. First, you should generate your
image as type "standalone" (using "mkimage ... -T standalone ...").
When you use the bootm command for such an image, U-Boot will
automatically uncompress the code while it is storing it at that
image's load address in RAM (given by the -a option to the mkimage
command).

As to the second question, by default, unless you say differently,
U-Boot will automatically start the image by jumping to its entry
point (given by the -e option to mkimage) after loading it.
If you want to prevent automatic execution, just set the environment variable
"autostart" to "no" ("setenv autostart no") before running bootm.

I tried adding some new code to the hellow_world.c
demo program. This works well as soon as I only add code to the
existing hello_world() function, but as soon as I add some
functions of my own, things go all haywire: the code of the
hello_world() function does not get executed correctly, and my
new function gets calles with unexpected arguments.
What's wrong?

Answer:

You probably failed to notice that any code you add to
the example program may shift the entry point address.
You should check this using the nm program:

If you use -O0 (no optimization) does it fix the problem?
If it does, it most likely is an optimization/volatile issue.
The hard part figuring out where.
Device handling and board-specific code is the place to start.

On a PowerPC, the instructions beginning with 0xFF are floating point
instructions. When your memory subsystem fails, the PowerPC is reading
bad values (0xFF) and thus executing illegal floating point instructions.

Your kernel image is quite big - nearly 1 MB compressed;
when it gets uncompressed it will need 2.5 ... 3 MB, starting at address 0x0000.
But your compressed image was stored at 1 MB (0x100000), so the uncompressed
code will overwrite the (remaining) compressed image. The solution is thus simple:
just use a higher address to download the compressed image into RAM.
For example, try:

You may find yourself in a situation where the Linux kernel crashes or hangs without
any output on the console. The first attempt to get more information in such a situation
is a Post Mortem dump of the log buffer - often the Linux kernel has already collected
useful information in its console I/O buffer which just does not get printed because the
kernel does not run until successful initialization of the console port.

Proceed as follows:

Find out the virtual address of the log buffer;
For 2.4 Linux kernels search for "log_buf":
2.4 Linux:

bash$ grep log_buf System.map
c0182f54 b log_buf

Here the virtual address of the buffer is 0xC0182F54
For 2.6 kernels "__log_buf" must be used:

bash$ grep __log_buf System.map
c02124c4 b __log_buf

Here the virtual address of the buffer is 0xC02124C4

Convert to physical address: on PowerPC systems, the kernel is usually configured for
a virtual address of kernel base (CONFIG_KERNEL_START) of 0xC0000000.
Just subtract this value from the address you found. In our case we get:

For the PowerPC architecture, the Linux kernel uses the following registers:

R1:

stack pointer

R2:

pointer to task_struct for the current task

R3-R4:

parameter passing and return values

R5-R10:

parameter passing

R13:

small data area pointer

R30:

GOT pointer

R31:

frame pointer

A function can use r0 and r3 - r12 without saving and restoring them.
r13 - r31 have to be preserved
so they must be saved and restored when you want to use them.
Also, cr2 - cr4 must be preserved,
while cr0, cr1, cr5 - cr7, lr, ctr and xer
can be used without saving & restoring them.
[ Posted Tue, 15 Jul 2003 by Paul Mackerras to linuxppc-embedded@lists.linuxppc.org ].

Why doesn't the kernel use the command-line options I set in the "bootargs"
environment variable in U-Boot when I boot my target system?

Answer:

This problem is typical for ARM systems only.
The following discussion is ARM-centric:

First, check to ensure that you have configured your U-Boot build so that
CONFIG_CMDLINE_TAG is enabled. (Other tags like CONFIG_SETUP_MEMORY_TAGS
or CONFIG_INITRD_TAG may be needed, too.)
This ensures that u-boot will boot the kernel with a command-line tag
that incorporates the kernel options you set in the
"bootargs" environment variable.

If you have the CONFIG_CMDLINE_TAG option configured, the
problem is almost certainly with your kernel build. You have to instruct the
kernel to pick up the boot tags at a certain address. This is done in the
machine descriptor macros, which are found in the processor start-up C code
for your architecture. For the Intel DBPXA250 "Lubbock" development board,
the machine descriptor macros are located at the bottom of the file
arch/arm/mach-pxa/lubbock.c, and they look like this:

The machine descriptor macros for your machine will be located in a similar
file in your kernel source tree. Having located your machine descriptor
macros, the next step is to find out where U-Boot puts the kernel boot tags
in memory for your architecture. On the Lubbock, this address turns out to
be the start of physical RAM plus 0x100, or 0xa0000100. Add the "BOOT_PARAMS"
macro with this address to your machine descriptor macros; the result
should look something like this:

If there is already a BOOT_PARAMS macro in your machine descriptor macros,
modify it so that it has the correct address. Then, rebuild your kernel and
re-install it on your target. Now the kernel should be able to pick up
the kernel options you have set in the "bootargs" environment variable.

I want to configure my system with root filesystem over NFS, but I cannot find any such configuration option.

Answer:

What you are looking for is the CONFIG_ROOT_NFS configuration option, which depends on CONFIG_IP_PNP.To enable root filesystem over NFS you must enable the "IP: kernel level autoconfiguration" option in the "Networking options" menu first.

You probably run your system with the root file system mounted
over NFS. Change into the root directory of your target file system,
and remove the file "etc/ld.so.cache". That should fix this problem:

# cd /opt/eldk/ppc_6xx/
# rm -f etc/ld.so.cache

Explanation:

Normally, the file "etc/ld.so.cache" contains a compiled list
of system libraries. This file is used by the dynamic linker/loader ld.so
to cache library information. If it does not exist, rebuilt automatically.
For some reason, a corrupted or partial file was written to your root
file system.
This corrupt file then confused the dynamic linker so that it crashed
when trying to start the init process.

The Linux kernel boots, but then hangs after printing: "Warning: unable to open an initial console".

Answer:

Most probably you have one or missing entries in the /dev directory in your root filesystem. If you are using the ELDK's root filesystem over NFS, you probably forgot to run the ELDK_MAKEDEV and ELDK_FIXOWNER scripts as described in 3.6. Mounting Target Components via NFS.

The default configuration of the SELF was not designed
to mount additional
filesystems with file locking over NFS,
so no portmap deamon is running, which is causing your problems.
There are two solutions for the problem:

Add the portmap deamon (/sbin/portmap) to the target filesystem
and start it as part of the init scripts.

Tell the "mount" program and the kernel that you don't
need file locking by passing the "nolock" option
to the mount call, i. e. use

# mount -o nolock -t nfs 192.168.1.1:/target/home /home

Explanation:

If you call the mount command like above (i. e. without the
"nolock" option) an RPC call to the "portmap" deamon will be attempted
which is required to start a lockd kernel thread which is necessary if
you want to use file locking on the NFS filesystem. This call will fail
only after a very long timeout.

Ethernet does not work on my board. But everything is fine
when I use the ethernet interface in
U-Boot (for example by performing a TFTP download).
This is a bug in U-Boot, right?

Answer:

No. It's a bug in the Linux ethernet driver.

In some cases the Linux driver fails to set the MAC address.
That's a buggy driver then - Linux ethernet drivers are supposed to
read the MAC address at startup.
On ->open, they are supposed to reprogram the MAC address back into the
chip (but not the EEPROM, if any) whether or not the address has been changed.

In general, a Linux driver shall
not make any assumptions about any initialization being done (or not
done) by a boot loader; instead, that driver is responsible
for performing all of the necessary initialization itself.

And U-Boot shall not touch any hardware it does not access itself.
If you don't use the ethernet interface in U-Boot, it won't be
initialized by U-Boot.

A pretty extensive discussion of this issue can be found in
the thread ATAG for MAC address on the ARM Linux mailing list.
archive 1archive 2

I expect to see some Linux kernel messages on the console, but there aren't any.

Answer:

This is absolutely normal when using the ELDK with root filesystem
over NFS. The ELDK startup routines will start the syslog daemon,
which will collect all kernel messages and write them into a logfile
( /var/log/messages ).

If you want to see the messages
at the console, either run "tail -f /var/log/messages &" on the
console window, or stop the syslog daemon by issuing a
"/etc/rc.d/init.d/syslog stop" command. Another alternative is to increase
the console_loglevel of the kernel (any message with log level less than
console_loglevel will be printed to the console). With the following command
the console_loglevel could be set at runtime: "echo 8 > /proc/sys/kernel/printk".
Now all messages are displayed on the console.

When using the framebuffer driver the console output goes to the LCD
display, but I cannot input anything. What's wrong?

Answer:

You can define "console devices" using the console= boot argument.
Add something like this to your bootargs setting:

... console=tty0 console=ttyS0,${baudrate} ...

This will ensure that the boot messages are displayed on both the
framebuffer (/dev/tty0) and the serial
console (/dev/ttyS0); the last device named in a
console= option will be the one that takes input,
too, so with the settings above you can use the serial console to
enter commands etc.
For a more detailed description see http://www.tldp.org/HOWTO/Remote-Serial-Console-HOWTO/configure-kernel.html

We are only seeing 263.78 bogomips on a MPC5200 running
at 396 MHz.
Doesn't this seem way to low ?? With a 603e core I'd expect
1 bogomip per MHz or better.

Answer:

No, the values you see is correct.
Please keep in mind that there is a good reason for the name BogoMIPS.

On PowerPC, the bogomips calculation is measuring the speed of a dbnz instruction.
On some processors like the MPC8xx it takes 2 clocks per dbnz instruction,
and you get 1 BogoMIP/MHz.
The MPC5200 takes 3 clocks per dbnz in this loop, so you get .67 BogoMIP/MHz.

I have a PowerPC board with 1 GiB of RAM (or more).
It works fine with root file system over NFS, but it will crash when I try to
use a ramdisk.

Answer:

Check where your ramdisk image gets loaded to.
In the standard configuration, the Linux kernel can access only 768 MiB of RAM,
so your ramdisk image must be loaded below this limit. Check your boot messages.
You are hit by this problem when U-Boot reports something like this:

Loading Ramdisk to 3fdab000, end 3ff2ff9d ... OK

and then Linux shows a message like this:

mem_pieces_remove: [3fdab000,3ff2ff9d) not in any region

To fix, just tell U-Boot to load the ramdisk image below the 768 MB limit:

I built a ramdisk image which is bigger than 4 MB. I run into
problems when I try to boot Linux with this image, while other
(smaller) ramdisk images work fine.

Answer:

The Linux kernel has a default maximum ramdisk size of 4096 kB. To
boot with a bigger ramdisk image, you must raise this value. There
are two methods:

Dynamical adjustment using boot arguments:
You can pass a boot argument
ramdisk_size=<size-in-kB>
to the Linux kernel to overwrite the configured maximum.
Note that this argument needs to be before any root argument. A
flexible way to to this is using U-Boot environment
variables. For instance, to boot with a ramdisk image of 6 MB
(6144 kB), you can define:

If you later find out that you need an even bigger ramdisk
image, or that a smaller one is sufficient, all that needs
changing is the value of the "rd_size"
environment variable.

Increasing the Linux kernel default value:
When configuring your Linux kernel, adjust the value of the
CONFIG_BLK_DEV_RAM_SIZE parameter so that
it contains a number equal or larger than your ramdisk (in
kB). (In the 2.4 kernel series, you'll find this setting under the
"Block devices" menu choice while, in the 2.6 series, it will be under
"Device drivers" -> "Block devices".)

I used to build a zImage.initrd file which
combined the Linux kernel with a ramdisk image. Can I do something
similar with U-Boot?

Answer:

Yes, you can create "Multi-File Images" which contain several images,
typically an OS (Linux) kernel image and one or more data images like
RAMDisks. This construct is useful for instance when you want to boot
over the network using BOOTP etc., where the boot server provides
just a single image file, but you want to get for instance an OS
kernel and a RAMDisk image.
The typical way to build such an image is:

Which kernel configuration options are relevant to support PCMCIA
cards under Linux?

Answer:

The following kernel configuration options are required to support
miscellaneous PCMCIA card types with Linux and the PCMCIA CS package:

PCMCIA IDE cards (CF and true-IDE)
To support the IDE CardService client, the kernel has to be
configured with general ATA IDE support. The MPC8xx IDE support
(CONFIG_BLK_DEV_MPC8XX_IDE flag) must be turned
off.

PCMCIA modem cards
The kernel has to be configured with standard serial port support
(CONFIG_SERIAL flag). After the kernel bootup the
following preparation is needed:

bash# mknod /dev/ttySp0 c 240 64

This creates a new special device for the modem card; please note
that /dev/ttyS0 ... S4 and TTY_MAJOR 4 are
already used by the standard 8xx UART driver).
/dev/ttySp0 becomes available for use as soon as
the CardServices detect and initialize the PCMCIA modem card.

For "disk" type PC Cards (FlashDisks, CompactFlash, Hard Disk Adapters - basically anything that looks like an ordinary IDE drive), an alternative solution is available: direct support within the Linux kernel. This has the big advantage of minimal memory footprint, but of course it comes with a couple of disadvantages, too:

It works only with "disk" type PC Cards - no support for modems, network cards, etc; for these you still need the PCMCIA Card Services package.

There is no support for "hot plug", i. e. you cannot insert or remove the card while Linux is running. (Well, of course you can do this, but either you will not be able to access any card inserted, or when you remove a card you will most likely crash the system. Don't do it - you have been warned!)

The code relies on initialization of the PCMCIA controller by the firmware (of course U-Boot will do exactly what's required).

On the other hand these are no real restrictions for use in an Embedded System.

To enable the "direct IDE support" you have to select the following Linux kernel configuration options:

You can now access your PC Card "disk" like any normal IDE drive. If you start with a new drive, you have to start by creating a new partition table. For PowerPC systems, there are two commonly used options:

At first we create two small partitions that will be used to store a Linux boot image; a compressed Linux kernel is typically around 400 ... 500 kB, so chosing a partition size of 2 MB is more than generous. 2 MB coresponds to 4096 disk blocks of 512 bytes each, so we enter:

The MS-DOS partition table is especially common on PC type computers, which these days means nearly everywhere. You will prefer this format if you want to exchange your "disk" media with any PC type host system.

The fdisk command is used to create MS-DOS type partition tables; to create the same partitioning scheme as above you would use the following commands:

Instead of defining a static partition map as described in section
Memory Technology Devices you can define the partitions
for your flash memory at boot time using command line arguments.
To do that you have to enable the CONFIG_MTD_CMDLINE_PARTS kernel configuration option.
With this option enabled, the kernel will recognize a command line argument mtdparts
and decode it as follows:

If a system has a real-time clock (RTC) this is often used only to initialize the system time when the system boots. From then, the system time is running independently. The RTC will probably only be used again at shutdown to save the current system time. Such a configuration is used in many workstation configurations. It is useful if time is not really critical, or if the system time is synchronized against some external reference clock like when using the Network Time Protocol (NTP) to access time servers on the network.

But some systems provide a high-accuracy real-time clock (RTC) while the system clocks are not as accurate, and sometimes permanent access to the net is not possible or wanted. In such systems it makes more sense to use the RTC as reference clock (Stratum 1 NTP server - cf. http://www.ntp.org/). To enable this mode of operation you must edit the NTP daemon's configuration file /etc/ntp.conf in your target's root file system. Replace the lines

server 127.127.1.0 # local clock
fudge 127.127.1.0 stratum 10

by

server 127.127.43.0 # standard Linux RTC

Then make sure to start the NTP daemon on your target by adding it to the corresponding init scripts and restart it if it is already running.

The "address" of the RTC (127.127.43.0 in the example above) is not an IP address, but actually used as an index into an internal array of supported reference clocks in the NTP daemon code.
You may need to check with your ntpd implementation if the example above does not work as expected.

The physical and virtual address of the flash memory used for XIP
must be defined statically with the macros CONFIG_XIP_PHYS_ADDR and
CONFIG_XIP_VIRT_ADDR. The virtual address usually points to the end
of the kernel virtual address of the system memory. The physical and
virtual address must be aligned relative to an 8 MB boundary:

They allow cramfs optional direct access to a cramfs image in memory (ram, rom, flash). It eliminates the unnecessary step of passing data through an intermediate buffer, as compared to accessing the same image through a memory block device like mtdblock.

They allow optional cramfs linear root support. This eliminates the requirement of having to provide a block device to use a linear cramfs image as the root filesystem.

They provide optional XIP. It extends mkcramfs to store files marked "+t" uncompressed and page-aligned. Linux can then mmap those files and execute them in-place without copying them entirely to ram first.

Note: the current implementation can only be used together with
a XIP kernel, which provides the appropriate XIP memory (FLASH)
mapping.

This defines a cramfs filesystem located at the physical address
0x40400000 in FLASH memory.

After building the kernel image "pImage" as usual, you will want
to build a filesystem using the mkcramfs executable (it's located
in /scripts/cramfs). If you do not already have a
reasonable sized disk directory tree you will need to make one.
The ramdisk directory of SELF (the Simple Embedded Linux Framework
from DENX at ftp.denx.de) is a good starting point. Before you
build your cramfs image you must mark the binary files to be
executed in place later on with the "t" permission:

$ mkcramfs -r ramdisk cramfs.img

and copy it to the defined place in FLASH memory.

You can then boot the XIP kernel with the cramfs root filesystem
using the boot argument:

I am using a SCC port of a MPC8xx / MPC82xx as UART;
for the Linux UART driver I have configured support for hardware handshake.
Then I used a null-modem cable to connect the port to the serial port of my PC.
But this does not work. What am I doing wrong?

Answer:

There is absolutely no way to connect a MPC8xx / MPC82xx SCC port
to any DTE and use RS-232 standard hardware flow control.

Explanation:

The serial interface of the SCC ports in MPC8xx / MPC82xx
processors is designed as a DTE circuitry
and the RS-232 standard hardware flow control can not be used in the DTE to DTE
connection with the null-modem cable (with crossed RTS/CTS signals).

The RS-232 standard specifies a DTE to DCE connection and
its hardware handshaking is designed for this specific task.
The hardware flow control signals in the PC (and similar equipment)
are implemented as software readable/writable bits in a control
register and therefore may be arbitrary treated. Unlike that,
in the 8xx/82xx the handshake protocol is handled by the CPM microcode.
The meaning of the signals is fixed for the RS-232 standard with
no way for user to change it.

In widely spread DTE-to-DTE connections over the so called 'null-modem'
cable with the hardware flow control lines the meaning of
the handshake signals is changed with respect to the RS-232 standard.
Therefore this approach may not be used with the 8xx/82xx.

Question:

I succeeded in activating hardware handshake on the transmit side
of the SCC using the CTS signal. However I have problems in the receive
direction.

Answer:

This is caused by the semantics of the RTS signal as implemented on
the SCC controllers: the CPM will assert this signal when it wants to
send out data. This means you cannot use RTS to enable the transmitter
on the other side, because it will be enabled only when the SCC is
sending data itself.

Conclusions:

If you want to use 8xx/82xx based equipment in combination
with RS-232 hardware control protocol, you must have a DCE device (modem,
plotter, printer, etc) on the other end.

Hardware flow control on a SCC works only in transmit direction; when
receiving data the driver has to be fast enough to prevent data overrun
conditions (normally this is no problem though).

I would like to access U-Boot's environment variables from my Linux application.
Is this possible?

Answer:

Yes, you can. The environment variables must be stored in flash memory,
and your Linux kernel must support flash access through the MTD layer.
In the U-Boot source tree you can find the environment tools in the directory
tools/env, which can be built with command:

make env

For building against older versions of the MTD headers (meaning before v2.6.8-rc1) it
is required to pass the argument "MTD_VERSION=old" to make:

make MTD_VERSION=old env

The resulting binary is called fw_printenv, but actually includes support for setting
environment variables too. To achieve this, the binary behaves according to the
name it is invoked as, so you will have to create a link called fw_setenv to fw_printenv.

These tools work exactly like the U-Boot commands printenv resp. setenv
You can either build these tools with a fixed configuration selected at compile time,
or you can configure the tools using the /etc/fw_env.config configuration file
in your target root filesystem. Here is an example configuration file:

I try to run the appWeb server, but it hangs,
because read accesses to /dev/random hang forever. What's wrong?

Answer:

Your configuration of the Linux kernel does not contain drivers
that feed enough entropy for /dev/random. Often mouse or keyboard drivers
are used for this purpose, so on an embedded system without such devices
/dev/random may not provide enough random numbers for your application.

Workaround:

As a quick workaround you can use /dev/urandom instead; i. e.
try the following commands on your system:

# cd /dev
# rm -f random
# ln -s urandom random

Solution:

The correct solution for the problem is of course to feed
sufficient entropy into /dev/random. To do so you can modify
one or more appropriate device drivers on your system;
for example if you know that there is sufficient traffic on
network or on a serial port than adding SA_SAMPLE_RANDOM to
the 3rd argument when calling the request_irq() function in your
ethernet and/or serial driver(s) will cause the
inter-interrupt times to be used to build up entropy for
/dev/random.

In case that the available memory is not sufficient, i.e. for compiling
the X.org server, and no hard-drive can be attached to the system it is
possible to swap over NFS, although it is not quite straightforward.

Usually one would create a blank file, mkswap it and simply do a swapon swapfile.
Doing this on a filesystem mounted over NFS, i.e. the ELDK root filesystem, fails however.

With one level of indirection we can trick the kernel into doing it anyway. First we
create a filesystem image (ext2 will do) on the NFS filesystem and mount it with the aid of the
loopback device. Then we create a blank swapfile inside of this filesystem and turn
on swapping:

Because the ELDK right now has no device nodes for the loopback driver we create them
along the way. It goes without saying that the loop driver has to be included in
the kernel configuration. You can check this by looking for a driver for major number
7 (block devices) in /proc/devices.

It is not always necessary to rebuild a SELF based ramdisk image if you want to modify or to extend it. Especially during development it is often eaiser to unpack it, modify it, and re-pack it again. To do so, you have to understand the internal structure of the uRamdisk (resp. pRamdisk) images files as used with the U-Boot
(old: PPCBoot) boot loader:

The uRamdisk image contains two parts:

a 64 byte U-Boot header

a (usually gzip compressed) ramdisk image

To modify the contents you have to extract, uncompress and mount the ramdisk image. This can be done as follows:

Remember that Linux by default supports only ramdisks up to a size of 4 MB.
For bigger ramdisks,
you have to either modify your LInux kernel configuration
(parameter CONFIG_BLK_DEV_RAM_SIZE in the "Block devices" menue),
or pass a "ramdisk_size=" boot argument to the Linux kernel.

I am trying to single step into a Linux exception handler.
This does not seem to work. Setting a breakpoint does not work either.

Answer:

The problem is bit complex on a MPC8xx target.
Debug mode entry is like an exception and therefore
only safe at locations in the code where an exception
does not lead to an unrecoverable state.
Another exception can only be accepted if SRR0 and
SRR1 are saved. The MSR[RI] should indicate if
currently an exception is safe. MSR[RI] is cleared
automatically at exception entry.

The MPC8xx hardware breakpoints do only trigger if
MSR[RI] is set in order to prevent non-recoverable state.

The problem is that the Linux exception handler does not
take all this into account. First priority has speed,
therefore neither SRR0 nor SRR1 are saved immediately.
Only after EXCEPTION_PROLOG this registers are saved.
Also Linux does not handle the MSR[RI] bit.

Hint: Use STEPMODE HWBP when debugging Linux.
This allows the TLB Miss Exception handler to update
the TLB while you are single stepping.

Conclusion:

You cannot debug Linux exception entry and exit code.
Because of speed, DataStoreTLBMiss does not even make use
of EXCEPTION_PROLOG, and SRR0/SRR1 are never saved.
Therefore you cannot debug DataStoreTLBMiss unless you
change it's code (save SRR0/SRR1, set MSR[RI].

Your single step problem most likely comes from
the fact that GDB accesses some non-existent memory
(at least some versions do/did in the past).
This exception is stored in some way
within the 405 and when you step "rfi" it triggers.
This is because some instructions like "rfi" are always
stepped using a hardware breakpoint and not with
the JTAG single step feature.

Probably you can step over the "rfi" instruction when using the
BDI2000's telnet command interface instead of GDB.

Similar problems have also been reported when stepping through
"mtmsr" or "mfmsr" during initial boot code.
The problem comes also from the fact that GDB accesses
non-existent memory (maybe it tries to read a non-existent stack frame).

To debug the Linux kernel, I recommend that you run to a point
where the MMU is on before you connect with GDB.

To debug boot code where the MMU is off I recommend to use
the MMAP feature of the BDI to prevent illegal memory
accesses from GDB.

I am trying to set a breakpoint using the BDI2000 telnet interface. However, the code does not stop at the breakpoint.

Answer:

Make sure that the CPU has been stopped before setting the breakpoint. You can verify this by issuing the "info" command before setting the breakpoint. If the target state is "running" you must use the "halt" command to stop the CPU before you can successfully set the breakpoint.

USB does not work on my Lite5200 board.
Also, the green LED behind the USB connector remains always off.
Why?

Answer:

This is a hardware problem.
The green LED must be on as soon as you power on the Lite5200 board.
As a workaround you can short-circuit resistor R164
(bottom side of the board, close to the USB connector).
Please note that you will probably lose all warranty and/or may ruin the board.
You have been warned.

You need ELDK version 2.0.2 or later; this includes (1) the Linux
kernel source with the required extensions, the PCMCIA Card Service
package with extensions for MPC8xx systems, and the wireless tools
package to control the PCMCIA devices.

To bring up the WLAN card for network operations, the following
actions should be performed (the example output shows card
configuration for a WLAN network controlled by the Access Point
("managed" mode):

Starting CardServices on the target:

bash# /etc/rc.d/init.d/pcmcia start

Assign the IP address of the WLAN network segment to the WLAN interface:

bash# ifconfig eth1 192.168.2.3

Assign the Network (or Domain) Name to the WLAN interface:

bash# iwconfig eth1 essid "DENX"

At this point the Acess Point station MAC address should appear on
the iwconfig output:

I am using a TQM8xxL module on a STK8xxL Starter Kit board.
Everything is fine, but Ethernet does not work - neither in U-Boot
nor in Linux.

Answer:

The TQM855L/M, TQM860L/M and TQM862L/M modules use SCC1
for the Ethernet interface.
Make sure that jumpers are set on connectors labeled X.12, X.13 and
X.14 on the STK8xxL board on the positions 1-3 and 2-4; also make
sure to remove the jumpers from positions 7-8, 9-10 and 11-12 on
X.30.

For the TQM823L and TQM850L modules SCC2 is used for Ethernet. Here
jumpers must be set on connectors X.12, X.13 and X.14 on the
positions 3-5 and 4-6; X.30 is used for USB configuration on these
boards - if you don't use USB it's safe to remove the jumpers from
positions 7-8, 9-10 and 11-12 on X.30.

The convention for register usage and C linkage commonly used on
desktop PowerPC machines. Similar, but not identical to the EABI.

Includes binding specific ppc registers to certain fixed purposes, even though there may be no technical reason to enforce such binding, simplifying the process of linking together two separate sets of object code. e.g the ABI states that r1 shall be the stack pointer.

A bank of memory (flash or RAM) consists of all those memory chips on
your system that are controlled by the same chip select signal.

For example, a system might consist of one flash chip with a 8 bit bus
interface, which is attached to the CS0 chip select signal, 2 flash
chips with a 16 bit bus interface, which are attached to the CS1 chip
select signal, and 2 SDRAM chips with a 16 bit bus interface, which
are attached to the CS2 chip select signal.

An on-chip debug interface supported by a special hardware port on
some processors. It allows to take full control over the CPU with
minimal external hardware, in many cases eliminationg the need for
expensive tools like In-Circuit-Emulators.

A network protocol which can be used to inquire a server about
information for the intended system configuration (like IP address,
host name, netmask, name server, routing, name of a boot image,
address of NFS server, etc.

Cramfs is designed to be a simple, small, and compressed file
system for ROM based embedded systems. CramFs is read-only, limited
to 256MB file systems (with 16MB files), and doesn't support 16/32
bits uid/gid, hard links and timestamps.

A network protocol which can be used to inquire a server about
information for the intended system configuration (like IP address,
host name, netmask, name server, routing, name of a boot image,
address of NFS server, etc.). Sucessor of BOOTP

The licenses under which the Linux kernel and much of the utility and
library code necessary to build a complete system may be copied, distributed
and modified. Each portion of the software is copyright by its respected copyright
holder, and you must comply with the terms of the license in order to legally copy
(and hence use) it. One significant requirement is that you freely redistribute
any modifications you make; if you can't cope with this, embedded Linux isn't for you.

JFFS (developed by Axis Communicartion AB, Sweden) is a log-based
filesystem on top of the MTD
layer; it promises to keep your filesystem and data in a consistent
state even in cases of sudden power-down or system crashes. That's
why it is especially useful for embedded devices where a regular
shutdown procedure cannot always be guaranteed.

A standard (see "IEEE Standard 1149.1") that defines how to control the
pins of JTAG compliant devices.

Here:
An on-chip debug interface supported by a special hardware port on
some processors. It allows to take full control over the CPU with
minimal external hardware, in many cases eliminationg the need for
expensive tools like In-Circuit-Emulators.

The MTD functions in Linux support memory devices like flash or
Disk-On-Chip in a device-independend way so that the higher
software layers (like filesystem code) need no knowledge about the
actual hardware properties.

PC

Card

PC Cards are self-contained extension cards especially for laptops
and other types of portable computers. In just about the size of a
credit card they provide functions like LAN cards (including
wireless LAN), modems, ISDN cards, or hard disk drives - often
"solid-state" disks based on flash chips.

The physical layer transceiver which implements the
IEEE Ethernet standard interface between the ethernet wires
(twisted pair, 50 ohm coax, etc.) and the ethernet controller
(MAC). PHYs are often external transceivers but may be integrated
in the MAC chip or in the CPU.

The PHY is controlled more or less transparently to software via the MII.

A simple default configuration for Embedded Linux systems that is suitable
as starting point for building your own systems. It is based on
BusyBox
to provide an init process, shell, and many
common tools (from cat and ls
to vi), plus some other tools to provide network
connectivity, allowing to access the system over the internet using
telnet and FTP services.

The computer system which will be used later in you application
environment, for instance an Embedded System. In many cases it has
a different architecture and much more limited resoucres than a
typical Host system, so it is often not possible to develop the software
directly (native) on this system.

Generically, this refers to any device capable of implementing a variety
of asynchronous serial protocols, such as RS-232, HDLC and SDLC. In this
context, it refers to the operating mode of the SCCs which provides this
functionality.