Though the bootloader runs for a very short time during the system’s startup and is mainly responsible for loading the kernel, it is a very important system component. Setting up a bootloader is, to some extent, a task common to all Linux systems. It is a special task, nevertheless, for embedded Linux systems, because the bootloaders used in such systems are either completely different from those used in common systems or, even when they are the same, are configured and operated in very different ways.
Chapter 7 discussed the manipulation of embedded storage devices, and Chapter 8 explained how to set up a root filesystem for use in an embedded target. We are now ready to set up the bootloader along with the other components created earlier so we may obtain a bootable and functional embedded system. Because hardware architectures differ greatly among each other and because boards based on the same architecture differ greatly among themselves, the selection, set up, and configuration of a bootloader depend largely on the hardware you are using.
There is a slew of bootloaders available for Linux, thousands upon thousands of embedded boards, and many possible boot configurations for a same board. It is, therefore, inconceivable to cover all the possible combinations within a single chapter. Nor is it possible to give an in-depth discussion of the use of each of the bootloaders covered. Many existing bootloaders for Linux either already have an entire book describing their use or need one to be written for them.
Also, the number and quality of bootloaders vary greatly between architectures. Some architectures, such as the PPC and the x86, have well known, established bootloaders providing support for a range of hardware. Other architectures have few or no standard bootloaders and mainly rely on the use of bootloaders provided by the hardware manufacturer. If you are using a bootloader provided by the manufacturer, make sure you have all the binaries and documentation. If possible, obtain the source code too so you can reprogram your target freely.
This chapter will concentrate on the bootloader/boot setup combinations most commonly used in embedded systems to load Linux. Although GRUB can be installed and used on hard disks, for example, its most common use in embedded Linux systems is to load Linux from DOC devices. Hence, the GRUB section will cover only GRUB’s use to load Linux from DOC devices.
First, we start by looking at the plethora of embedded bootloaders available for use with Linux. We then discuss how to set up and configure a server to provide BOOTP/DHCP and NFS services for targets that use these services to obtain a kernel image and mount their root filesystem, respectively. This is followed by in-depth discussions of the use of LILO with disk devices, the use of GRUB with DOC devices, and the use of U-Boot.
At the end of this chapter, you will either have installed all the components we created earlier, configured your target with the appropriate bootloader, and be ready to boot your system, or you will know where to get the rest of the information you need to achieve this.
As I said above, many bootloaders can be used with Linux on various hardware. In this section, I will introduce the most popular and most versatile open source bootloaders for each architecture. Some architectures, such as the MIPS and the m68k, have no standard bootloaders at all. If your target is based on an MIPS or m68k processor, refer to the documentation provided by the manufacturer for instructions on how to set up and boot your hardware.
Also, some publications make a distinction between “bootloader” and “monitor.” In those cases, the bootloader is just the component that boots a device and launches the main software, whereas a monitor provides, in addition to booting capabilities, a command-line interface that can be used for debugging, reading/writing memory, flash reprogramming, configuring, etc. In this chapter, I will refer to both types of software as “bootloaders,” while explicitly mentioning a bootloader’s monitor capabilities when available.
In comparing bootloaders, keep in mind that the availability and extent of monitor capabilities are important during development. Once development is over, however, these capabilities may become a liability, because the priority is to ensure that the user cannot inadvertently enter the monitor mode. Some bootloaders, such as U-Boot for example, can be reconfigured to allow or disallow access to monitor features. Your production hardware may also be built to prevent physical access to the serial port.
Table 9-1 presents the open source bootloaders that can be used with Linux and the architectures they support. For each bootloader, the table also indicates whether the bootloader provides monitor capabilities, and provides a short description of the bootloader. Use this table as a starting point for identifying which bootloader is best for your embedded system.
Architectures | ||||||||
Bootloader |
Monitor |
Description |
x86 |
ARM |
PowerPC |
MIPS |
SuperH |
m68k |
LILO |
No |
The main disk bootloader for Linux |
X | |||||
GRUB |
No |
GNU’s successor to LILO |
X | |||||
ROLO |
No |
Loads Linux from ROM without a BIOS |
X | |||||
Loadlin |
No |
Loads Linux from DOS |
X | |||||
Etherboot |
No |
ROMable loader for booting systems through Ethernet cards |
X | |||||
LinuxBIOS |
No |
Linux-based BIOSreplacement |
X | |||||
Compaq’s bootldr |
Yes |
Versatile loader mainly intended for Compaq iPAQ |
X | |||||
blob |
No |
Loader from the LART hardware project |
X | |||||
PMON |
Yes |
Loader used in Agenda VR3 |
X | |||||
sh-boot |
No |
Main loader of the LinuxSH project |
X | |||||
U-Boot |
Yes |
Universal loader based on PPCBoot and ARMBoot |
X |
X |
X | |||
RedBoot |
Yes |
eCos-based loader |
X |
X |
X |
X |
X |
X |
In addition to the above table, there are a few observations to be made regarding the various bootloaders available for each architecture:
There are two main bootloaders used for the x86: LILO and GRUB. LILO is the mainstream bootloader for most x86 workstation and server distributions. On Red Hat’s distribution, however, GRUB has replaced LILO. There are other, less known bootloaders, such as Rolo and EtherBoot, which you may be interested in using under certain circumstances.
As you can see, few x86 bootloaders currently provide monitor capabilities. The most glaring limitation of x86 bootloaders is that most require an x86-based host for your development. The Makefiles of LILO and GRUB, for example, are not built to allow cross-compilation. Moreover, it is difficult to install either LILO or GRUB from a non-x86 host on storage media designated for an x86 target. Hence, even if you carry out all your development on a non-x86 host, you may need to use an x86 host to compile and install the x86 bootloader you select.
Though U-Boot aims at becoming the standard ARM bootloader, there is no standard bootloader for ARM-based systems at the time of this writing. There are, nevertheless, a couple of ARM bootloaders as shown in Table 9-1, each supporting a different set of hardware. There are also many other bootloaders that can be used to boot Linux on an ARM system. Some of these bootloaders are outdated or haven’t been updated for a long time, others are particular to one type of board or are not available under an open source license.
The main bootloader found in most PPC systems is U-Boot (formerly known as PPCBoot.)
There is no standard bootloader for MIPS-based embedded Linux systems. Though PMON may be useful as an initial codebase, you will most probably need to port it to your target before using it. At the time of this writing, efforts are underway to add MIPS support to U-Boot.
Though sh-boot is the main bootloader for SH-based embedded Linux systems, you may find other bootloaders, such as RedBoot, better adapted to your system.
Though RedBoot supports some m68k-based systems, there is no standard bootloader for m68k-based embedded Linux systems.
Now that I’ve introduced the various bootloaders and outlined the bootloader support for each architecture, let’s take a closer look at each bootloader.
The LInux LOader (LILO) was introduced by Werner Almesberger very early in Linux’s history. Now, LILO is maintained by John Coffman and the latest releases are available from http://brun.dyndns.org/pub/linux/lilo/. LILO is a very well documented bootloader. The LILO package, for instance, includes a user manual and an internals manual. The LILO mini-HOWTO available from the LDP completes this documentation by answering some of the most common questions about LILO’s use. In addition, Running Linux contains a "Using LILO" section in Chapter 5.
The GRand Unified Bootloader (GRUB) is the main bootloader for the GNU project. GRUB was originally written by Erich Boleyn in the course of finding an appropriate bootloader for what would later be known as GNU Mach. Eric’s work was later picked up by Gordon Matzigkeit and Okuji Yoshinori, who currently continue to maintain and develop GRUB. The GRUB project’s web site is located at http://www.gnu.org/software/grub/. There, you will find the GRUB manual, which discusses the package’s use extensively. One aspect of GRUB’s capabilities you may find helpful during development is its ability to boot over the network using TFTP, and BOOTP or DHCP. Though GRUB’s code can be retrieved using CVS, the latest stable releases are tar-gzipped and made available for download through the project’s web site.
The ROmable LOader (ROLO) was written and is being maintained by Robert Kaiser from Sysgo Gmbh. as part of Sysgo’s ELinos distribution. ROLO can boot Linux directly from ROM without requiring any BIOS. ROLO is available from ftp://ftp.elinos.com/pub/elinos/rolo/. Though the package contains little documentation, Vipin Malik has written a thorough article on the use of ROLO in an embedded system at http://www.embeddedlinuxworks.com/articles/rolo_guide.html.
loadlin is a DOS utility to load Linux maintained by Hans Lermen at http://elserv.ffm.fgan.de/~lermen/. Though you should avoid building your system in a way that requires DOS to be loaded first, there are cases where such a utility can be very handy. One case where it can be useful, for example, is if you want to use M-Systems’s DOS tools to boot from a DOC device. In that case, you can write an autoexec.bat file that uses the loadlin utility to load Linux. As we will see below, however, you can boot Linux directly from a DOC device using GRUB.
Many NICs are shipped with a socket for inserting ROM chips. When present and properly signed, these ROM chips are recognized as BIOS extensions and executed during startup. EtherBoot uses this capability to support the booting of diskless systems through the network. EtherBoot has been used in many environments, including X-terminals, routers, and clusters. It is available with complete documentation from http://etherboot.sourceforge.net/. The web site provides links to manufacturers who sell EPROMs preloaded with EtherBoot.
LinuxBIOS is a complete BIOS replacement that boots Linux from ROM at startup. LinuxBIOS was developed as part of clustering research conducted at the Los Alamos National Laboratory and has gathered support from many hardware manufacturers. The LinuxBIOS package and documentation are available at http://www.linuxbios.org/.
Though initially developed for the Compaq iPAQ only, Compaq’s bootldr currently supports Intel’s Assabet and HP’s Jornada 720. Though it is limited in the range of hardware it supports, bootldr provides a very rich command set and is capable of loading kernels directly from JFFS2 MTD partitions. Bootldr is part of the software collection maintained by http://www.handhelds.org/ and is available for download from ftp://ftp.handhelds.org/bootldr/.
blob was introduced as the bootloader for the LART hardware project.[1] Since its introduction, blob has been ported to many other ARM-based systems, including Intel’s Assabet and Brutus, Shannon, and Nesa boards. Unlike ARMBoot and Compaq’s bootldr, blob does not provide monitor capabilities, though it can be used to reprogram the flash and can load kernels directly from JFFS2 MTD partitions. blob is available from the LART web site along with documentation at http://www.lart.tudelft.nl/lartware/blob/.
The Prom Monitor (PMON) was written by Phil Bunce to support LSI LOGIC’s MIPS boards. It is distributed under a very simplistic license, which stipulates that PMON comes with no warranty and that you are free to redistribute it without any restriction. Though Phil’s PMON has not been updated since 1999, it is still available at http://www.carmel.com/pmon/. Others have nevertheless used PMON for more recent projects. It was ported to the now discontinued Agenda VR3 Linux PDA by Bradely LaRonde. That version is available from the AGOS SourceForge workspace at http://agos.sourceforge.net/ and information on its use is available from the Agenda Wiki site at http://agendawiki.com/. It remains that there is no central authority or roadmap for PMON, and few boards are actually supported. As I said earlier, you may find the PMON codebase a good starting point, but you will most probably need to port it to your system to use it.
sh-boot is developed as part of the Linux SH project on SourceForge. Unfortunately, sh-boot has not been updated for a while, so you may need to evaluate its usability for your system. Also, sh-boot is a simple bootloader and does not provide any monitor capabilities. The bootloader is available using CVS through the Linux SH project site at http://linuxsh.sourceforge.net/.
Though there are quite a few other bootloaders, “Das U-Boot,” the universal bootloader, is arguably the richest, most flexible, and most actively developed open source bootloader available. It is currently maintained by Wolfgang Denk of DENX Software Engineering, and is contributed to by a wide range of developers. U-Boot is based on the PPCBoot and ARMBoot projects. PPCBoot was itself based on 8xxrom sources, and ARMBoot was an ARM port of PPCBoot done by Sysgo Gmbh. At the time of this writing, U-Boot supports around 100 different PPC-based boards, more than a dozen ARM-based boards, and a handful of x86-based boards. U-Boot’s success in scaling to a wide range of hardware has prompted developers to continue porting it to even more new boards and architectures.
Among other things, U-Boot is capable of booting a kernel through TFTP, from an IDE or SCSI disk, and from a DOC. Also, it includes read-only support for JFFS2. Besides having an extensive command set and quite a few capabilities, it is also fairly well documented. The README included with the package provides an in-depth discussion of the use of U-Boot. The doc directory in the package’s source includes any extra instructions required for certain boards. In addition to the instructions found in the package, Wolfgang wrote the DENX PPCBoot and Linux Guide, available at http://www.denx.de/re/DPLG.html, which provides many practical examples of the use of PPCBoot with Linux on a TQM8xxL board. Though the discussion assumes that you are using PPCBoot and DENX’s Embedded Linux Development Kit (ELDK) distribution,[2] the sections relating to the use of PPCBoot apply with little or no changes to U-Boot, and are helpful regardless of whether you use any distribution.
The U-Boot project workspace is located at http://sourceforge.net/projects/u-boot. The U-Boot package is available from that site. If you intend to use U-Boot often, you will find it useful to subscribe to the very active U-Boot users mailing list at that site. Though there is no on-site documentation for U-Boot at the time of this writing, you can still rely on the documentation and background provided by the two projects on which U-Boot is based, PPCBoot and ARMBoot. PPCBoot’s web site is located at http://ppcboot.sourceforge.net/, and ARMBoot’s project web site is located at http://armboot.sourceforge.net/. We will explore U-Boot’s use later in this chapter.
RedBoot is supposed to be a next generation bootloader from Red Hat, replacing CygMon and GDB stubs with a firmware supporting a very wide range of hardware. Although Red Hat has stopped active development of eCos, the OS on which RedBoot is based, eCos has now been relicensed under the GPL and continues to be maintained by some of the Red Hat core eCos developers. eCos’ future, and RedBoot’s as well, is therefore in the hands of those developers.
Despite its dependency on eCos,[3] RedBoot remains a very powerful bootloader. It is, for instance, the only open source bootloader that currently supports all the architectures presented in depth in Chapter 3 and a wide range of boards based on these architectures. Also, the RedBoot package is fairly well documented, including a RedBoot User’s Guide that provides actual examples of its use on more than a dozen different systems. RedBoot’s web site is located at http://sources.redhat.com/redboot/ and its sources are available with the rest of the eCos sources using CVS. Lately, eCosCentric Ltd., the company formed by the core eCos developers from Red Hat, has been providing CVS snapshots at http://www.ecoscentric.com/snapshots/.
As we saw in Chapter 2, setting up a target for network boot is ideal during the early stages of development, because you can gradually modify the kernel and the root filesystem without having to update the target’s storage devices every time you make a modification. Though not all bootloaders can use this setup to boot, I recommend that you use such a setup whenever possible.
As I said earlier, the simplest way to boot your target from the network is to use BOOTP/DHCP, TFTP, and NFS. BOOTP/DHCP is the standard way to provide a network host with basic boot information, including the location of other servers such as TFTP and NFS. TFTP is the simplest network protocol for downloading remote files. In the case of an embedded Linux system, it is used by the target to obtain a kernel image from the TFTP server. Finally, NFS is the standard and simplest protocol for sharing entire directory trees between a client and a server. In the case of an embedded Linux system, it is used by the target to mount its root filesystem from the NFS server. NFS cannot be used for any earlier activity, because it requires a booted Linux kernel to operate. Together, these three protocols provide a very efficient host/target development setup.
To enable network booting of the target, you must set up the development host’s network services so that the target can access the components it needs. In particular, you need to set up a host to respond to BOOTP/DHCP requests, provide a kernel using a TFTP server, and enable NFS mounts. The subsections below discuss each issue separately.
Unlike other network services, DHCP is not dependent on the internet super-server. Instead, the DHCP daemon is a service of its own, and you need to start it manually. First, you need to make sure that the DHCP server is installed on your system. Though you can download it from http://www.isc.org/, the DHCP server is part of most mainstream distributions.
If you are using an RPM-based distribution, use the following command to check for the presence of the DHCP daemon:
$ rpm -q dhcp
dhcp-2.0-5
In this case, DHCP 2.0-5 is already installed. If it is not already
installed on your system, use the appropriate tools for your
distribution to install the DHCP server. Note that most distributions
include two DHCP packages, a client and a server. The package
containing the client is usually called
dhcpc-
VERSION
. There
is an additional “c” after
“dhcp” to identify the client
package.
To operate properly, the kernel on which
the DHCP server runs has to be configured with the
CONFIG_PACKET
and CONFIG_FILTER
options. The kernels shipped by default in most distributions almost
always have these enabled. If you are in the habit of building your
own kernels for your workstation, as I often do, watch out for those
options when configuring the kernel. If the kernel
wasn’t built properly, the DHCP daemon will output
the following message when it tries to start:
socket: Protocol not available - make sure CONFIG_PACKET and CONFIG_FILTER are defined in your kernel configuration! exiting.
With the package installed and the kernel properly configured, create or edit the /etc/dhcpd.conf file and add an entry for your target. For example, here is the /etc/dhcpd.conf file for my control module:
subnet 192.168.172.0 netmask 255.255.255.0 { option routers 192.168.172.50; option subnet-mask 255.255.255.0; host ctrl-mod { hardware ethernet 00:D0:93:00:05:E3; fixed-address 192.168.172.10; option host-name "ctrl-mod"; next-server 192.168.172.50; filename "/home/karim/vmlinux-2.4.18.img"; option root-path "/home/karim/ctrl-rootfs"; } }
Essentially, this entry states that the host and target are on the
192.168.172.0 network, that the TFTP server is located at
192.168.172.50, and that the address allocated to the target when it
issues its DHCP or BOOTP request is 192.168.172.10. The
hardware ethernet
field uniquely identifies the
target through its MAC address, which is 00:D0:93:00:05:E3 for my
control module. The fixed-address
field tells the
DHCP server which IP address should be allocated to the designated
MAC address. The option host-name
field gives the
hostname to the target so that it can use it internally. The
next-sever
tells the target where the TFTP server
is located. The filename
field is the
filename[4] of the image that has to be loaded by the target.
According to RFC 2131, which specifies DHCP, the filename is limited
to 128 bytes. Finally, the option root-path
field
provides the path to the target’s root filesystem on
the NFS server. If your target does not need to load its root
filesystem from an NFS server, you can omit this last field. Because
the host is the only network link to the target in this case,
option routers
points to the
host’s address. If the target was linked to an
entire network with a real router, option routers
should point to that network’s default router.
The example configuration provided above should be easy to adapt to your own target. If you need more information regarding the configuration of the DHCP server, have a look at the manpage for dhcpd.conf and the sample configuration file installed by your distribution, if one is present.
Note that if you are using a version of the DHCP daemon later than 3.0b2pl11, such as the one shipped with Red Hat 8.0, you will need to add the following line to your dhcpd.conf file:
ddns-update-style ad-hoc;
With the DHCP server configured for the target, you are almost ready to start the DHCP server. Before you do so, however, you need to make sure the /var/state/dhcp/dhcpd.leases file exists. If it doesn’t, create it using the touch command. If the file isn’t created, the DHCP daemon will refuse to start.
Finally, start the DHCP server. On distributions based on Red Hat, enter:
# /etc/init.d/dhcpd start
The first step in setting up the TFTP daemon is to make sure the TFTP package is installed. Though the latest version of the TFTP daemon is available for download as part of the NetKit package at ftp://ftp.uk.linux.org/pub/linux/Networking/netkit/, TFTP was most likely already installed on your system as part of your distribution or is available to be installed from your distribution’s CDs.
If you are using an RPM-based distribution, use the following command to check for the presence of the TFTP daemon:
$ rpm -q tftp
tftp-0.16-5
In this case, TFTP 0.16-5 is already installed. If it is not available on your system, install the TFTP package using the appropriate tool for your distribution. Alternatively, if your system doesn’t rely on a package manager or if some components have been installed without a package manager, you can also check for the presence of the actual TFTP daemon binary using the whereis command.
Once the package is installed, enable the TFTP service by modifying the appropriate internet super-server configuration file. In brief, the internet super-server listens on designated ports on behalf of the various network services. When a request for certain service is received, the super-server spawns the appropriate daemon and hands it the request. Hence, only the minimal number of daemons run at all times. TFTP is one of the daemons normally handled by the super-server.
To enable the TFTP service in a system
based on the inetd super-server, edit
/etc/inetd.conf, uncomment the line for the TFTP
service by removing the # character at the beginning, and send a
SIGHUP
signal to the inetd
process so that it rereads its configuration file. To enable the TFTP
service in a system based on the xinetd
super-server, edit /etc/xinetd.d/tftp and
comment the line containing disable = yes
by
adding a # character at the beginning. As with
inetd, you must send a SIGHUP
to xinetd.
Finally, you must provide the TFTP server with a list of directories
containing files that should be made available to TFTP clients. In a
system based on the inetd super-server, append
the list of directories to the TFTP line in
/etc/inetd.conf. In a system based on the
xinetd super-server, edit the
/etc/xinetd.d/tftp file and append the list of
directories to the server_args =
line. The default
directory for TFTP is /tftpboot. You may choose
to modify this to match your setup. Whichever directory you choose,
make sure its access permissions include read and execute for the
“other” permission.
For example, here is a TFTP line in /etc/inetd.conf for a host using the inetd super-server:
tftp dgram udp wait root /usr/sbin/tcpd in.tftpd /home/karim/
In this case, images are placed in the /home/karim directory, which has the following permissions:
$ ls -ld /home/karim
drwxr-xr-x 4 karim karim 4096 Aug 29 16:13 karim
Here is a modified /etc/xinetd.d/tftp file from a Red Hat-based installation providing the same functionality for a host using the xinetd super-server:
service tftp { socket_type = dgram protocol = udp wait = yes user = root server = /usr/sbin/in.tftpd server_args = /home/karim # disable = yes per_source = 11 cps = 100 2 }
Regardless of the super-server in use on a host, the TFTP service is usually disabled by default. Hence, even if you use the default /tftpboot, you will need to modify the super-server’s configuration files to enable TFTP.
As I explained in Chapter 2, while a bootloader and kernel must be stored locally or retrieved to local storage through one of the methods shown earlier, the target’s kernel can mount its root filesystem from a remote NFS server. To this end, the NFS server must be properly installed and configured. Chapter 6 showed how to build your target’s root filesystem. Though Chapter 8 showed how to prepare this filesystem for use in the target, the root filesystem we created in Chapter 6 does not need any special preparation for use by the NFS server.
The NFS server daemon is available in two flavors: as a standalone user application or as a part of the kernel. Besides being faster, the latter is also the standard way most distributions are configured. In addition to the NFS server itself, you need to have the NFS utilities installed. Usually, there is an nfs-utils package as part of your distribution. Use the following command to identify whether nfs-utils is installed:
$ rpm -q nfs-utils
nfs-utils-0.3.1-13
With the nfs-utils installed, you need to make sure that the appropriate configuration files are present and that the corresponding services are started.
The main file we need to configure for the NFS server is /etc/exports. Entries in this file describe the directories each host or set of hosts can access. As an example, here is the entry in my /etc/exports for my control module:
/home/karim/ctrl-rootfs 192.168.172.10(rw,no_root_squash)
This entry states that the machine with address 192.168.172.10 has
read and write (rw
) access to the
/home/karim/ctrl-rootfs directory, which is the
path to the root filesystem we built for the target in Chapter 6. In addition, the
no_root_squash
argument indicates that the server
should allow the remote system to access the directory with its root
privileges. These are very powerful rights that we are granting to
the target. If we have total control over access to the device, as is
the case in most development setups, there is obviously no security
risk. If, however, the target’s location is less
secure or if it is directly connected to the Internet, for example,
you may prefer to use the default root_squash
instead. In that case, the target will not be able to write to most
of its own root filesystem, though it will still be able to read and
write to all directories and files that are readable and writable by
anybody. In practical terms, however, the target’s
operation will be very limited.
Because offering the NFS service also involves the risk of network abuse, it is often pertinent to use some minimal protection mechanisms to avoid intrusions. One simple way to do this is to customize the /etc/hosts.deny and /etc/hosts.allow files to restrict access to network services. For example, here is the /etc/hosts.deny file for my Red Hat-based host:
# # hosts.deny # portmap: ALL lockd: ALL mountd: ALL rquotad: ALL statd: ALL
and here is my /etc/hosts.allow file:
# # hosts.allow # portmap: 192.168.172.10 lockd: 192.168.172.10 mountd: 192.168.172.10 rquotad: 192.168.172.10 statd: 192.168.172.10
The rules specified in this files restrict access to the various file-sharing services. Together, these files indicate that only the machine with address 192.168.172.10 can use the NFS services. This is fine in the case of my setup, since I don’t want to share my workstation with anyone else. Even if you do not customize /etc/hosts.deny and /etc/hosts.allow, I encourage you to take security issues to heart and use whichever means necessary, such as backups, to protect your work.
Once the configuration files are created, you can start the portmapper service, which is required by the NFS server:
# /etc/init.d/portmap start
Finally, you can start the NFS server itself:
# /etc/init.d/nfs start
If you would like more information on the configuration of remote boot using NFS, see the two Diskless root NFS HOWTOs on the issue at the LDP. Also, you may be interested by the NFS HOWTO, also at the LDP.
Because there is already ample documentation on the installation, configuration, and use of LILO, I will cover only its specific use in embedded PC-like systems. Specifically, I will provide the instructions to use on the host to install LILO on a storage device meant to be used in the target.
The installation of LILO on a target’s storage device requires the use of the removable storage setup as explained in Chapter 2. In this scenario, the target’s storage device is removed from the target and connected to the host’s own hardware to be programmed. Hence, the target’s storage device is controlled by the host’s operating system like any other host device. The target’s storage device is therefore seen as an extra storage device for the host. It can be seen, for example, as a secondary IDE disk (/dev/hdb) or as a primary SCSI disk (/dev/sda). Regardless of the way it is seen by the host’s kernel, LILO needs to be used in a specific way to install itself on this secondary storage and not on the host’s boot media, as is the default.
As
we discussed in Chapter 8, CF devices are quite
peculiar in this regard, because they can be seen on the host as a
SCSI disk (/dev/sd
X
)
when accessed through a USB CF reader, while being seen on the target
as an IDE disk
(/dev/hd
X
) when
accessed through a CF-to-IDE or CF-to-PCMCIA adapter. The
configuration file example I provide below takes care of this issue
by using the appropriate BIOS and kernel flags so that the disk seen
as a SCSI disk on the host can boot normally as an IDE disk once put
back in the target.
In the following, I assume that the storage device where LILO will be installed is accessible on your host, and that you are using LILO Version 22.3 or later. If you are using an earlier version, an important command will fail, as I will explain shortly. Follow these steps to install LILO on a secondary IDE or SCSI storage device on your host:
Create appropriate /dev entries in your target’s root filesystem for the storage device where LILO is to be installed. This is not the storage device as it will be accessed once in your target. Rather, this is the storage device entry used by the host to access the designated storage device. If, for example, you want to install LILO on /dev/sda (usually the first SCSI hard disk in your system), there must be a /dev/sda entry on your target’s root filesystem. It is very likely that this entry does not correspond to a valid device on your target. Indeed, it is possible that the disk accessed as /dev/sda on the host may be accessed as /dev/hda once on the target. Nevertheless, you must create the /dev/sda entry in your target’s root filesystem for LILO to use when running on the host. The reasons for this will soon become evident. For more information on the relationship between /dev entries and the actual physical storage devices, see Chapter 3 of Running Linux.
Create a LILO configuration file on your target root filesystem. To avoid damaging your host’s configuration when installing LILO on the target’s storage device, put your LILO configuration in /etc/target.lilo.conf on your target’s root filesystem instead of the usual /etc/lilo.conf. Hence, if you accidentally issue a LILO command that modifies your host, the tool will complain about a missing file and no damage will be done to your host.
Here is a sample /etc/target.lilo.conf to boot my DAQ module from a CF card:
boot = /dev/sda disk = /dev/sda bios = 0x80 image = /boot/bzImage-2.4.18 root = /dev/sda1 append = "root=/dev/hda1" label = Linux read-only
In this case, the CF card is accessed
through a USB CF reader and is visible on my host as a SCSI disk
through /dev/sda. On the target, however, it
will be accessed through a CF-to-IDE adapter and will be visible as
an IDE drive through /dev/hda. If you use a
normal LILO configuration file to configure LILO, it would guess the
BIOS ID of the disk it is operating on, and would use that ID at
startup to make access requests to the BIOS. Since, in this case, it
is operating on a SCSI disk, it would assume a SCSI BIOS ID and would
make access requests for such a disk. Since no such disk exists on
the target, the BIOS would return an error and LILO would fail to
boot. The trick in the configuration file above lies in the
bios = 0x80
line. This informs LILO that it is
booting from the disk with BIOS ID 0x80, which is the first IDE drive
in the system. Because of the confusion between SCSI and IDE, I must
also append a root=/dev/hda1
option to the
kernel’s boot parameters. Otherwise, the kernel
would fail to find its root filesystem and crash while trying to
mount it.[5]
Alternatively, if you want to install LILO on /dev/hdb, replace the /dev/sda entries above with /dev/hdb. In this case, you won’t need to append the root=/dev/hda1 option to the kernel’s boot instructions, because the disk appears as IDE both on the host and the target.
When LILO is run with the configuration file above, it opens the host’s /dev/sda device and installs itself there. Because this configuration file is located in ${PRJROOT}/rootfs/etc/target.lilo.conf instead of /etc/lilo.conf, special options must be used with LILO to provide it with the location of this alternative configuration file. I will present the complete LILO command line to use in this configuration shortly.
For a complete discussion of how LILO is installed on an alternative
storage device, see the Installing hdc
to Boot as
hda
and Using bios=
section in
the LILO mini-HOWTO provided by the LDP.
If necessary, partition the storage device using fdisk.
Create filesystems on the storage device for the filesystem types you selected using the appropriate filesystem creation tools. For an ext2 filesystem, for example, use mke2fs.
Mount the root filesystem partition on an appropriate directory in /mnt.
Copy the root filesystem to its designated partition using
cp -a. The root filesystem must contain the
kernel image referenced by the
/etc/target.lilo.conf
file created earlier,
/boot/bzImage-2.4.18 in this case.
Install LILO on the storage device. For my DAQ module’s storage device, for example, which is mounted as /mnt/cf on my host, I use the following command:
# lilo -r /mnt/cf -C etc/target.lilo.conf
Warning: etc/target.lilo.conf should be owned by root
Warning: LBA32 addressing assumed
Added Linux *
This
command instructs lilo to use the
chroot( )
system call to change its root
directory to /mnt/cf directory and to use the
etc/target.lilo.conf configuration file found in
that directory. The command programs the devices specified in the
target.lilo.conf configuration file. The
/dev entries specified in the configuration file
are located starting from the root directory entry,
/mnt/cf. If /dev/sda must
be programmed, for example, LILO attempts to open and program
/mnt/cf/dev/sda.
If you had forgotten to create the /dev entries specified in target.lilo.conf on your target’s root filesystem, this command will fail. It will also fail if there is no /tmp directory on your target’s root filesystem. Furthermore, if you are using a LILO version earlier than 22.3, the command will report the following error and fail:
Fatal: open /boot/boot.b: No such file or directory
This error message is due to the fact that, prior to Version 22.3, LILO’s components were separated across different files, some of which were .b files. Since 22.3, all .b files are part of the lilo binary.
Unmount the root filesystem partition.
You can now remove the storage device from your host, either by shutting down the host and removing the hard disk or by removing the CF card from the CF reader, instaling it in your target, and booting it.
Since the use of GRUB with conventional disk devices is already amply covered in the GRUB manual, we will mainly concentrate on the installation and use of GRUB with DOC devices. Before I start covering the details of how to compile and use GRUB with a DOC device, I must warn you that an improper configuration of GRUB for your DOC can render your system unbootable. Let’s see why this happens and how it can be avoided.
As I explained in Chapter 7 when describing the use of the doc_loadbios command, DOC devices contain a ROM program called the IPL that is detected as a BIOS extension at startup and is executed by the BIOS. When it runs, this IPL installs another program, the SPL. To boot from a DOC device using GRUB, the SPL must be replaced by a version of GRUB specifically tailored to boot from a DOC.
Since there may be other BIOS extensions in the system, the SPL loaded by the IPL cannot boot the system right away. Instead, it must install a Terminate and Stay Resident (TSR) program that will lay dormant until the BIOS is ready to boot the system. In the case of GRUB, the GRUB SPL replaces the BIOS’s bootstrap interrupt, INT 19h, with a custom interrupt handler that will execute the rest of the GRUB code to finish booting from the DOC device. Hence, the other BIOS extensions get to run and GRUB is called only when the system is ready to be booted.
The problem with this scheme, however, is that the default bootstrap handler installed by the BIOS never gets a chance to run, and any boot configuration option you may have selected in your BIOS—such as booting from disk or floppy first—will be completely ignored by GRUB when its handler is invoked. This is fine if the configuration file on the DOC is correct. At worst, you would then boot using the DOC, change the configuration file in Linux, or completely remove GRUB from the DOC to set the system as you desire.
If you make any mistakes in the GRUB configuration file that result in boot failure, however, you will be unable to restart your system normally without finding a way to disable the replacement of the bootstrap interrupt handler at startup. There are four known ways to do this:
You can physically remove the DOC from the system before starting it. The problem with this choice is that your only way to reprogram the DOC thereafter, if you do not have access to a hardware DOC programer, is to insert the DOC after the system has been started. In other words, you would have to connect the DOC to a live electronic circuit. Needless to say, neither the DOC nor the electronic circuits interfacing with it have been designed for this sort of manipulation. Also, I neither encourage you to try this nor take any responsibility if you are crazy enough to do it. However, a few courageous people on the MTD mailing list have reported that they successfully inserted their DOC in a running system in this way to reprogram it.
If jumpers are available for configuring the address region to which the DOC device is mapped, you can try removing the jumpers completely and starting the system. In some cases, such as when using the ISA DOC evaluation board provided by M-Systems, this will result in the BIOS not recognizing the IPL and, hence, not running it. In other cases, however, this may result in a system hang. If this trick works for you, you will be able to boot the system using the BIOS’s configuration. However, to access the DOC again once the system is running, you will have to insert the jumper while the system is powered on. Again, though this is reported to work, the hardware was not designed for this, I don’t encourage you to do it, and I take no responsibility whatsoever for any possible outcome.
The configuration of GRUB allows it to use the ROM BASIC interrupt, INT 18h, instead of the bootstrap interrupt. Lately, in addition to being the ROM BASIC interrupt, INT 18h is sometimes used for network boot. When configured to use this interrupt, GRUB would kick in only if the BIOS configuration is set to network boot or if there are no boot devices set in the BIOS. This approach has a few drawbacks. First, it requires changing the BIOS configuration every time you want to switch from booting from the DOC to booting from a hard disk. This can be time-consuming during development. In addition, the use of INT 18h by recent BIOSes is not standardized, as the case of the BIOSes using it to provide network boot demonstrates.
Having seen the above choices while writing this book, your author decided to find a “cleaner” way of doing things. Hence, I set out digging in some of my old DOS and BIOS hacking books and came up with a solution that’s both elegant and simple. Basically, instead of replacing the default bootstrap interrupt handler outright, my modified GRUB SPL makes a copy of the original handler, replaces it with the GRUB bootstrap handler, and lets the BIOS continue looking for other extensions in the system. When GRUB’s bootstrap handler is invoked, it then checks whether the user is holding down the Ctrl key. If so, the original bootstrap handler is restored, and the BIOS is left to continue the bootstrap using the boot configuration chosen by the user. If the Ctrl key isn’t held down, GRUB continues its normal procedure to load whatever is on the DOC. As you can see, this solution does not involve any dangerous hardware manipulations; save, maybe, for people suffering from carpal tunnel syndrome.
For obvious reasons, I strongly encourage you to use the last solution. This enhancement is, however, fairly recent at the time of this writing and you will only find it starting with GRUB patch grub-2002-10-08-doc.patch, which is available in the MTD CVS. I will explain how this option is enabled during GRUB’s configuration in the next section.
Having covered the dangers of using GRUB to boot from a DOC, let’s discuss the building, installation, and use of GRUB with a DOC.
As I said earlier, you will need an x86 host to build GRUB. The following instructions assume that you are using such an x86 host. GRUB will fail to build or will create unusable binaries on any other type of host.
To start, download GRUB into your ${PRJROOT}/bootldr directory and extract it there. Then copy the GRUB patch from the ${PRJROOT}/sysapps/mtd/patches directory to the GRUB directory in ${PRJROOT}/bootldr. In the case of my DAQ module, for example, I used GRUB 0.92 and the grub-2002-02-19-doc.patch patch. Now apply the patch to GRUB:
$cd ${PRJROOT}/bootldr/grub-0.92
$patch -p0 < grub-2002-02-19-doc.patch
Because this patch was originally meant for GRUB 0.90, there were some warnings and one failure when applying it to 0.92. The failure in this case was in ChangeLog and can therefore be ignored.
If you want to use the Ctrl key method discussed in the previous section to avoid having to hotplug your DOC, use the grub-2002-10-08-doc.patch patch or a later version against a GRUB version retrieved from the CVS repository. Because the CVS repository is constantly changing, however, this patch may not apply cleanly to the latest CVS contents. To get the patch to apply as cleanly as possible and have the resulting source tree compile, for example, I had to retrieve the GRUB sources from the CVS repository as they were on October 10, 2002 and then manually edit a couple of files in the source code. To retrieve the code as it was on the date I mentioned, I used the following command:
$cvs -z3 -d:pserver:[email protected]:/cvsroot/grub
> co -D"10/10/02" grub
With the code patched, you are ready to build GRUB. First, create the Makefile using the automake tools:
$ aclocal && automake && autoconf
Now, configure GRUB to build for the DOC:
$./configure --enable-diskonchip-2000
> --enable-diskonchip-ctrlbypass
> --enable-ext2fs
> --disable-ffs --disable-xfs --disable-jfs --disable-vstafs
> --disable-reiserfs --disable-minix --disable-fat
This command line disables GRUB’s support for all filesystems except ext2 and enables support for the DOC 2000 device. It also enables the Ctrl key bypass method I described in the previous section using the - -enable-diskonchip-ctrlbypass option. There are a few other configuration options relevant to the DOC. If you are using DOC Millennium, for example, you may want to use the - -enable-diskonchip-mil256 or - -enable-diskonchip-mil512 option, depending on whether your DOC Millennium is using 256- or 512-byte page sizes. You can also use the - -enable-diskonchip-biosnetboot option to boot GRUB on the network boot interrupt instead of the bootstrap interrupt as described earlier. For a complete description of the options available for configuring GRUB for the DOC, have a look at the README_DiskOnChip created in the GRUB package directory when the DOC patch was applied earlier.
Once the configuration is done, you can build GRUB:
$ make
Once the compilation is done, the stage1/grub_firmware file will contain the GRUB image to be written to the DOC. Copy this file to ${PRJROOT}/images/grub_firmware-0.92 for future use:
$ cp stage1/grub_firmware ${PRJROOT}/images/grub_firmware-0.92
I have already covered the installation of the GRUB bootloader image in Section 7.1.3.5. Follow the instructions given in that section to install the GRUB image created here on your DOC device.
As with LILO, GRUB uses a configuration file to determine the boot media and kernel it has to boot. Unlike LILO, however, you do not need to run the GRUB binary to parse and update its configuration. Instead, the GRUB configuration file, menu.lst, is placed as-is in the /boot/grub directory of the target’s root filesystem and is read by GRUB at startup. To configure GRUB to boot from a DOC, this is the file that we must create.
As an example, here is a simple menu.lst file for booting from a DOC device:
timeout 5 default 0 title DiskOnChip 2000 Boot kernel (dc0,0)/boot/bzImage-2.4.18 root=/dev/nftla1 title HD Boot kernel (hd0,0)/boot/bzImage-2.4.18 root=/dev/hda1
This file states that there are two boot possibilities. The first,
which is also the default, involves booting kernel
/boot/bzImage-2.4.18 from the first partition of
the first DOC, dc0
. The second involves booting a
kernel by the same name as the previous item from the first partition
of the first hard disk, hd0
. For each
configuration, the root=
option indicates the
device where the booting kernel will find its root filesystem.
This configuration is useful during development, since it allows you to choose between booting from the DOC and from your hard disk. On a production system, you probably want to remove the entry for the hard disk and set the timeout to zero so that booting from the DOC becomes the only possible option.
You can further modify GRUB’s configuration and allow for a number of boot options. Look at GRUB’s manual for a complete description of the configuration file format.
As I said earlier, U-Boot is a richly documented bootloader. The README file included with the package, for example, covers the use of U-Boot extensively. Among other things, it discusses the package’s source code layout, the available build options, U-Boot’s command set, and the typical environment variables used in U-Boot. In the following, I will cover the essential aspects of U-Boot and provide practical examples of its use. An in-depth discussion of U-Boot would, however, require a book of its own. For this reason, I encourage you to print a copy of the README provided with U-Boot and have a look at the other documentation written by the project maintainer.
Start by downloading and extracting the latest version of U-Boot in your ${PRJROOT}/bootldr directory. As of this writing, the latest U-Boot version is 0.2.0. Once extracted, move to the package’s directory:
$ cd ${PRJROOT}/bootldr/u-boot-0.2.0
Before you can build U-Boot, you need to configure it for your
target. The package includes a number of preset configurations for
quite a few boards. So, a configuration may very well exist for your
target already. Look at the README file to see
if your board is supported. For each supported board,
U-Boot’s Makefile includes a
BOARD_NAME
_config
target, which is used to configure U-Boot’s build
for the designated board. The configuration target for the TQM860L
board I use for my control module, for example, is
TQM860L_config
. Once you have determined the
proper Makefile target to use, configure U-Boot’s
build process:
$ make TQM860L_config
Now, build U-Boot:
$ make CROSS_COMPILE=powerpc-linux-
In addition to generating bootloader images, the build process will compile a few tools to be used on the host for conditioning binary images before downloading them off to the target to a running U-Boot. Table 9-2 lists the files generated during U-Boot’s compilation.
Filename |
Description |
System.map |
The symbol map |
u-boot |
U-Boot in ELF binary format |
u-boot.bin |
U-Boot raw binary image that can be written to the boot storage device |
u-boot.srec |
U-Boot image in Motorola’s S-Record format |
You can now download the U-Boot image onto your target’s boot storage device using the appropriate procedure. If you already have U-Boot, or one its ancestors (PPCBoot or ARMBoot) installed on your target, you can use the installed copy to update U-Boot to a new version, as we shall see in Section 9.5.10. If you have another bootloader installed, follow the procedures described in that bootloader’s documentation for updating bootloaders. Finally, if you have no bootloader whatsoever installed on your target, you need to use a hardware programming device, such as a flash programmer or a BDM debugger, to copy U-Boot to your target.
Whichever method you use to copy the actual bootloader image to your target, make a copy of the relevant bootloader images to your ${PRJROOT}/images directory. For my control module for example, I copy the images as follows:
$cp System.map ${PRJROOT}/images/u-boot.System.map-0.2.0
$cp u-boot.bin ${PRJROOT}/images/u-boot.bin-0.2.0
$cp u-boot.srec ${PRJROOT}/images/u-boot.srec-0.2.0
If you intend to debug U-Boot itself, copy the ELF binary also:
$ cp u-boot ${PRJROOT}/images/u-boot-0.2.0
Finally, install the host tool generated by the U-Boot build:
$ cp tools/mkimage ${PREFIX}/bin
Once U-Boot is properly installed on your target, you can boot it while being connected to the target through a serial line and using a terminal emulator to interface with the target. As I said in Chapter 4, not all terminal emulators interact cleanly with all bootloaders. In the case of U-Boot, avoid using minicom for file transfers, since problems may occur during such transfers.
Here is a sample boot output for my control module:
U-Boot 0.2.0 (Jan 27 2003 - 20:20:21) CPU: XPC860xxZPnnD3 at 80 MHz: 4 kB I-Cache 4 kB D-Cache FEC present Board: TQM860LDB0A3-T80.201 DRAM: 16 MB FLASH: 8 MB In: serial Out: serial Err: serial Net: SCC ETHERNET, FEC ETHERNET PCMCIA: No Card found Hit any key to stop autoboot: 5
As you can see, U-Boot prints version information and then provides some detail regarding the hardware it is running on. As soon as it boots, a five second timer starts ticking at the last output line. If you do not press a key during those five seconds, U-Boot boots its default configuration. By pressing a key, you get a prompt:
=>
One of the first things you probably want to try is obtaining help from U-Boot:
=> help
askenv - get environment variables from stdin
autoscr - run script from memory
base - print or set address offset
bdinfo - print Board Info structure
bootm - boot application image from memory
bootp - boot image via network using BootP/TFTP protocol
bootd - boot default, i.e., run 'bootcmd'
cmp - memory compare
coninfo - print console devices and informations
cp - memory copy
crc32 - checksum calculation
date - get/set/reset date & time
dhcp - invoke DHCP client to obtain IP/boot params
diskboot- boot from IDE device
echo - echo args to console
erase - erase FLASH memory
flinfo - print FLASH memory information
go - start application at address 'addr'
help - print online help
ide - IDE sub-system
iminfo - print header information for application image
loadb - load binary file over serial line (kermit mode)
loads - load S-Record file over serial line
loop - infinite loop on address range
md - memory display
mm - memory modify (auto-incrementing)
mtest - simple RAM test
mw - memory write (fill)
nm - memory modify (constant address)
printenv- print environment variables
protect - enable or disable FLASH write protection
rarpboot- boot image via network using RARP/TFTP protocol
reset - Perform RESET of the CPU
run - run commands in an environment variable
saveenv - save environment variables to persistent storage
setenv - set environment variables
sleep - delay execution for some time
tftpboot- boot image via network using TFTP protocol
and env variables ipaddr and serverip
version - print monitor version
? - alias for 'help'
As you can see, U-Boot has a lot of commands. Fortunately, U-Boot also provides per-command help:
=> help cp
cp [.b, .w, .l] source target count
- copy memory
When U-Boot appends the [.b, .w, .l]
expression to
a command, this means that you need to append one of the indicated
strings to the command to invoke the desired version of the command.
In the case of cp, for example, there are three
versions, cp.b, cp.w, and
cp.l, for copying bytes, words, and longs,
respectively.
U-Boot is
strict in its argument parsing. It expects most values to be provided
in hexadecimal form. In the case of the cp
command, for example, this means that the source address, the target
address, and the byte count must be provided in hexadecimal values.
You don’t need to prepend or append those values
with any sort of special characters, such as
“0x” or
“h”. If your source address is
0x40000000, for example, simply type 40000000
.
U-Boot accepts any unique subset of characters that starts a command name. If you want to use the erase command, for example, you can type just the first three letters, era, since erase is the only command to start with those three first letters. On the other hand, you can’t type lo and expect U-Boot to understand it, since there are three commands that start with those letters: loadb, loads, and loop.
Once U-Boot is up and running, you can configure it by setting the appropriate environment variables. The use of U-Boot environment variables is very similar to the use of environment variables in Unix shells, such as bash. To view the current values of the environment variables on your target, use the printenv command. Here is a subset of the environment variables found on my control module:
=> printenv
bootdelay=5
baudrate=115200
loads_echo=1
serial#=...
ethaddr=00:D0:93:00:05:E3
netmask=255.255.255.0
ipaddr=192.168.172.10
serverip=192.168.172.50
clocks_in_mhz=1
stdin=serial
stdout=serial
stderr=serial
Environment size: 791/16380 bytes
Each environment variable has a different meaning. Some environment
variables, such as bootdelay
,
serial#
, or ipaddr
, have
predetermined uses that are recognized by U-Boot itself. See the
README file for a complete discussion of
U-Boot’s environment variables and their meanings.
As with Unix shells, you can add environment variables in U-Boot. To do so, you must use the setenv command. Here is an example session where I add a few environment variables to my control module (the third command must be entered as a single line, even though it appears broken on the page):
=>setenv rootpath /home/karim/ctrl-rootfs
=>setenv kernel_addr 40100000
=>setenv nfscmd setenv bootargs root=/dev/nfs rw nfsroot=$(serverip):$(rootpath) ip=$(ipaddr):$(serverip):$(gatewayip):$(netmask):$(hostname)::off panic=1; bootm $(kernel_addr)
=>setenv bootcmd run nfscmd
In this case, I set U-Boot to boot from
the kernel found at 0x40100000 and to mount its root filesystem using
NFS. Notice that I used the character to tell
U-Boot that the character following
should not
be interpreted as a special character. This is how the
nfscmd
looks like, for example, after U-Boot has
read it:
=> printenv nfscmd
nfs2cmd=setenv bootargs root=/dev/nfs rw nfsroot=$(serverip):$(rootpath)
ip=$(ipaddr):$(serverip):$(gatewayip):$(netmask):$(hostname)::off panic=1;bootm
$(kernel_addr)
The setenv command adds the environment variables to the current session only. Hence, if you reset the system, any environment variable you set only with setenv will be lost. For the environment variables to survive reboots, they must be saved to flash. This is done using the saveenv command:
=> saveenv
Saving Enviroment to Flash...
Un-Protected 1 sectors
Erasing Flash...
. done
Erased 1 sectors
Writing to Flash... done
Protected 1 sectors
Be careful when using saveenv, since it will save all the environment variables currently defined, even those you may have been using temporarily. Before using saveenv, use printenv to take a look at the currently defined environment variables to make sure you are saving only the necessary variables. If you want to delete a variable, simply use setenv on the variable without providing any values. Here’s an example:
=>setenv RAMDisk_addr 40500000
=>printenv RAMDisk_addr
RAMDisk_addr=40500000 =>setenv RAMDisk_addr
=>printenv RAMDisk_addr
## Error: "RAMDisk_addr" not defined
Note that the
=
character is not treated as a special character
by setenv. In fact, it is seen as another
character in the string making up the environment variable, as we saw
earlier in this section. The following command, for example, is
flawed (notice the extra =
displayed by
printenv in comparison to the same
printenv shown in the previous capture):
=>setenv RAMDisk_addr = 40500000
=>printenv RAMDisk_addr
RAMDisk_addr= = 40500000
U-Boot environment variables can be used
to create boot scripts. Such boot scripts are actually environment
variables containing a set of U-Boot command sequences. By using a
combination of the run command and the
;
(semicolon) operator, you can make U-Boot run
boot scripts. The environment variables I set in the previous
section, for instance, are actually part of a boot script,
nfscmd
.
The key to the way the script I provided in the previous section
works is the bootcmd
environment variable. This
variable is recognized by U-Boot as the script to run automatically
when the system is booted. I set this variable as run
nfscmd
. In other words, U-Boot should
run the nfscmd
script to boot the system. In turn,
this environment variable is a set of commands of its own. First, it
sets the bootargs
environment variable, which
U-Boot passes to the kernel as its boot parameters, and then uses the
bootm command to boot the kernel located at
$(kernel_addr)
. The semicolon separates commands.
The use of the
$(
VAR_NAME
) operator
tells U-Boot to replace the entire string with the value of the
VAR_NAME
environment variable. Hence, when
nfscmd
runs, $(kernel_addr)
is
replaced by 40100000
, which is the value I set
earlier. In the same way, $(rootpath)
is replaced
by /home/karim/ctrl-rootfs
, and the rest of the
environment variables included in nfscmd
are
replaced by their respective values.
Though it would
have been possible to set bootcmd
to contain the
entire boot script instead of using run nfscmd
, it
would have been much harder then to specify alternative boot scripts
at the boot command line. By using the run
command in the bootcmd
script, multiple boot
scripts can coexist within U-Boot’s environment
variables. You can then change the system’s default
boot using:
=>setenv bootcmd run
OTHER_BOOT_SCRIPT
Or you can run boot scripts directly from the command line without
changing the value of the bootcmd
environment
variable:
=>run
OTHER_BOOT_SCRIPT
Scripts are a very useful feature of U-Boot and you should use them whenever you need to automate a certain task in U-Boot.
Since the raw flash is not structured like a filesystem and does not contain any sort of file headers, binary images downloaded to the target must carry headers for U-Boot to recognize their content and understand how to load them. The mkimage utility we installed earlier was packaged with U-Boot for this purpose. It adds the information U-Boot needs to binary images while attaching a checksum for verification purposes.
While the use of image headers is not a technical requirement for a bootloader, such headers are very convenient both during development and in the field. Hence, their use by U-Boot.
To see the typical use of mkimage, type the command without any parameters:
$ mkimage
Usage: mkimage -l image
-l = => list image header information
mkimage -A arch -O os -T type -C comp -a addr -e ep -n name
-d data_file[:data_file...] image
-A = => set architecture to 'arch'
-O = => set operating system to 'os'
-T = => set image type to 'type'
-C = => set compression type 'comp'
-a = => set load address to 'addr' (hex)
-e = => set entry point to 'ep' (hex)
-n = => set image name to 'name'
-d = => use image data from 'datafile'
-x = => set XIP (execute in place)
For example here is how I create a U-Boot image of the 2.4.18 kernel I compiled for my control module:
$cd ${PRJROOT}/images
$mkimage -n '2.4.18 Control Module'
> -A ppc -O linux -T kernel -C gzip -a 00000000 -e 00000000
> -d vmlinux-2.4.18.gz vmlinux-2.4.18.img
Image Name: 2.4.18 Control Module Created: Wed Feb 5 14:19:08 2003 Image Type: PowerPC Linux Kernel Image (gzip compressed) Data Size: 530790 Bytes = 518.35 kB = 0.51 MB Load Address: 0x00000000 Entry Point: 0x00000000
The command takes quite a few flags, but their meaning is easily understood by looking at the usage message provided by mkimage. Note that the name of the image, provided in the -n option, cannot be more than 32 characters. Any excess characters will be ignored by mkimage. The rest of the command line tells mkimage that this is a gzipped PPC Linux kernel image that should be loaded at address 0x00000000 and started from that same address. The image being provided in input is vmlinux-2.4.18.gz and the U-Boot-formatted image will be output to vmlinux-2.4.18.img.
RAM disk images can be processed in a similar fashion:
$mkimage -n 'RAM disk'
> -A ppc -O linux -T ramdisk -C gzip
> -d initrd.bin initrd.boot
Image Name: RAM disk Created: Wed Feb 5 14:20:35 2003 Image Type: PowerPC Linux RAMDisk Image (gzip compressed) Data Size: 470488 Bytes = 459.46 kB = 0.45 MB Load Address: 0x00000000 Entry Point: 0x00000000
In this case, the number of parameters is shorter, since we
don’t need to specify start and load addresses. Note
that the image type has changed to ramdisk
.
We can also create a
multi
-type image that combines both the kernel
image and a RAM disk. In that case, the files included are listed
sequentially using a colon separator:
$mkimage -n '2.4.18 Ctrl and Initrd'
> -A ppc -O linux -T multi -C gzip -a 00000000 -e 00000000
> -d vmlinux-2.4.18.gz:initrd.bin
> vmlinux-2.4.18-initrd.img
Image Name: 2.4.18 Ctrl and Initrd Created: Wed Feb 5 14:23:29 2003 Image Type: PowerPC Linux Multi-File Image (gzip compressed) Data Size: 1001292 Bytes = 977.82 kB = 0.95 MB Load Address: 0x00000000 Entry Point: 0x00000000 Contents: Image 0: 530790 Bytes = 518 kB = 0 MB Image 1: 470488 Bytes = 459 kB = 0 MB
Once you have prepared an image with
mkimage, it is ready to be used by U-Boot and
can be downloaded to the target. As we’ll see below,
U-Boot can receive binary images in a number of different ways. One
way is to use images formatted in Motorola’s
S-Record format. If you intend to use this format, you need to
further process the images generated by mkimage
by converting them to the S-Record format. Here is an example
conversion of the multi
-type image generated
above:
$powerpc-linux-objcopy -I binary -O srec
> vmlinux-2.4.18-initrd.img vmlinux-2.4.18-initrd.srec
If you have properly configured a server to provide the target with DHCP, TFTP, and NFS services, as I explained earlier, you can boot your target remotely. Back from U-Boot’s prompt on my control module, here is how I boot my target remotely, for example:
=> bootp
BOOTP broadcast 1
DHCP client bound to address 192.168.172.10
ARP broadcast 1
TFTP from server 192.168.172.50; our IP address is 192.168.172.10
Filename '/home/karim/vmlinux-2.4.18.img'.
Load address: 0x100000
Loading: ################################################### ...
done
Bytes transferred = 530854 (819a6 hex)
The bootp command issues a request that is answered by the DHCP server. Using the DHCP server’s answer, U-Boot contacts the TFTP server and obtains the vmlinux-2.4.18.img image file, which it places at address 0x00100000 in RAM. You can verify the image’s header information using the iminfo command:
=> imi 00100000
## Checking Image at 00100000 ...
Image Name: 2.4.18 Control Module
Created: 2003-02-05 19:19:08 UTC
Image Type: PowerPC Linux Kernel Image (gzip compressed)
Data Size: 530790 Bytes = 518.3 kB
Load Address: 00000000
Entry Point: 00000000
Verifying Checksum ... OK
As you can
see, the information printed out by iminfo on
the target is very similar to that printed out on the host by
mkinfo. The OK
string
reported for the checksum means that the image has been downloaded
properly and that we can boot it:
=> bootm 00100000
## Booting image at 00100000 ...
Image Name: 2.4.18 Control Module
Created: 2003-02-05 19:19:08 UTC
Image Type: PowerPC Linux Kernel Image (gzip compressed)
Data Size: 530790 Bytes = 518.3 kB
Load Address: 00000000
Entry Point: 00000000
Verifying Checksum ... OK
Uncompressing Kernel Image ... OK
Linux version 2.4.18 (karim@Teotihuacan) (gcc version 2.95.3 20010315 ...
On node 0 totalpages: 4096
zone(0): 4096 pages.
zone(1): 0 pages.
zone(2): 0 pages.
Kernel command line: root=/dev/nfs rw nfsroot= ...
Decrementer Frequency: 5000000
Calibrating delay loop... 79.66 BogoMIPS
...
VFS: Cannot open root device "" or 02:00
Please append a correct "root=" boot option
Kernel panic: VFS: Unable to mount root fs on 02:00
<0>Rebooting in 180 seconds..
In this
case, the kernel panics because it is unable to find any root
filesystem. To solve this problem, we must use the environment
variables to create a boot script for passing appropriate boot
options to the kernel. The following commands create a new boot
script, bootpnfs
, and modify the special
bootcmd
script, as we did in Section 9.5.3, in order for the system to
boot using BOOTP/DHCP, TFTP, and NFS:
=>setenv bootpnfs bootp; setenv kernel_addr 00100000; run nfscmd
=>printenv bootpnfs
bootpnfs=bootp; setenv kernel_addr 00100000; run nfscmd =>setenv bootcmd run bootpnfs
=>printenv bootcmd
bootcmd=run bootpnfs
In this case, the bootpnfs
script automatically
executes the bootp instruction we used earlier
in this section to obtain a kernel from the TFTP server. It then uses
the nfscmd
script we created in Section 9.5.3 to boot this kernel. The
value of kernel_addr
is changed so that the
nfscmd
script would use the kernel loaded using
TFTP, not the one located at 40100000.
If you use the boot command now, U-Boot will boot entirely from the network. It will download the kernel through TFTP and mount its root filesystem on NFS. If you would like to save the environment variables we just set, use the saveenv command before rebooting the system, otherwise, you will have set the same variables again at the next reboot.
Booting from the network is fine for early development and testing. For production use, the target must have its kernel stored in flash. As we will see shortly, there a few ways to copy a kernel from the host to the target and store it to flash. Before you can copy any kernel image, however, you must first choose a flash region to store it and erase the flash region for the incoming kernel. In the case of my control module, I store the default kernel between 0x40100000 and 0x401FFFFF. Hence, from U-Boot’s prompt, I erase this region:
=> erase 40100000 401FFFFF
Erase Flash from 0x40100000 to 0x401fffff
........ done
Erased 8 sectors
The simplest way to install a kernel in the target’s flash is to first download it into RAM and then copy it to the flash. You can use the tftpboot command to download a kernel from the host to RAM:
=> tftpboot 00100000 /home/karim/vmlinux-2.4.18.img
ARP broadcast 1
TFTP from server 192.168.172.50; our IP address is 192.168.172.10
Filename '/home/karim/vmlinux-2.4.18.img'.
Load address: 0x100000
Loading: ################################################### ...
done
Bytes transferred = 530854 (819a6 hex)
When
tftpboot is run, it adds the
filesize
environment variable to the existing
environment variables and sets it to the size of the file downloaded:
=> printenv filesize
filesize=819a6
You can use this environment variable in subsequent commands to avoid typing in the file size by hand. Don’t forget to erase this environment variable before saving the environment variables, or it, too, will be saved.
In addition to tftpboot, you can use the loadb command to download images to the target:
=> loadb 00100000
## Ready for binary (kermit) download ...
At this point, U-Boot suspends and you must use the terminal emulator on the host to send the image file to the target. In this case, U-Boot expects to download the data according to the kermit binary protocol, and you must therefore use kermit to download a binary image to U-Boot. Once the transfer is done, U-Boot will output:
## Total Size = 0x000819a6 = 530854 Bytes ## Start Addr = 0x00100000
Here, too, U-Boot will set the
filesize
environment variable to the size of the
file downloaded. As we did earlier, you may want to use the
iminfo command to verify that the image has been
properly downloaded.
Once the image is in RAM, you can copy it to flash:
=>cp.b 00100000 40100000 $(filesize)
Copy to Flash... done =>imi 40100000
## Checking Image at 40100000 ... Image Name: 2.4.18 Control Module Created: 2003-02-05 19:19:08 UTC Image Type: PowerPC Linux Kernel Image (gzip compressed) Data Size: 530790 Bytes = 518.3 kB Load Address: 00000000 Entry Point: 00000000 Verifying Checksum ... OK
Alternatively, instead of downloading the image to RAM first using tfptboot or loadb and then writing it to flash, you can download the image directly to flash using loads. In this case, the host sends the image to the target in S-Record format. In comparison to the two previous methods, however, downloading an S-Record file is extremely slow. In most cases, it is preferable to use tftpboot or loadb instead.[6]
To download S-Record files, you will need to use the cu terminal emulator to transfer them to the target, because the other terminal emulators don’t interact properly with U-Boot when downloading this sort of file. When connected through cu, use the following commands:
=>loads 40100000
## Ready for S-Record download ...~>vmlinux-2.4.18.srec
1 2 3 4 5 6 7 8 9 10 11 12 13 14 ... ... ...176 33177 33178 33179 33180 33181 [file transfer complete] [connected] ## First Load Addr = 0x40100000 ## Last Load Addr = 0x401819A5 ## Total Size = 0x000819A6 = 530854 Bytes ## Start Addr = 0x00000000
The ~>
string shown
here is actually part of the input you have to type. It is actually
the cu command used to initiate a file download.
As before, you can verify the image once it’s in memory:
=> imi 40100000
## Checking Image at 40100000 ...
Image Name: 2.4.18 Control Module
Created: 2003-02-05 19:19:08 UTC
Image Type: PowerPC Linux Kernel Image (gzip compressed)
Data Size: 530790 Bytes = 518.3 kB
Load Address: 00000000
Entry Point: 00000000
Verifying Checksum ... OK
Every time you want to load a new image to flash, you have to start back at the erase command shown in the beginning of this section.
The first step in booting from a RAM disk is to download the RAM disk from the host and install it on the target’s flash. Many of the commands are the same as those shown and explained in previous sections. Here is how I do this for my control module:
=>tftpboot 00100000 /home/karim/initrd.boot
ARP broadcast 1 TFTP from server 192.168.172.50; our IP address is 192.168.172.10 Filename '/home/karim/initrd.boot'. Load address: 0x100000 Loading: ################################################### ... done Bytes transferred = 470552 (72e18 hex) =>imi 00100000
## Checking Image at 00100000 ... Image Name: RAM disk Created: 2003-02-05 19:20:35 UTC Image Type: PowerPC Linux RAMDisk Image (gzip compressed) Data Size: 470488 Bytes = 459.5 kB Load Address: 00000000 Entry Point: 00000000 Verifying Checksum ... OK =>printenv filesize
filesize=72e18 =>imi 40200000
## Checking Image at 40200000 ... Bad Magic Number =>erase 40200000 402FFFFF
Erase Flash from 0x40200000 to 0x402fffff ........ done Erased 8 sectors =>cp.b 00100000 40200000 $(filesize)
Copy to Flash... done =>imi 40200000
## Checking Image at 40200000 ... Image Name: RAM disk Created: 2003-02-05 19:20:35 UTC Image Type: PowerPC Linux RAMDisk Image (gzip compressed) Data Size: 470488 Bytes = 459.5 kB Load Address: 00000000 Entry Point: 00000000 Verifying Checksum ... OK
Since I had already installed a kernel, I can boot the kernel available in flash with the RAM disk I just installed:
=> bootm 40100000 40200000
## Booting image at 40100000 ...
Image Name: 2.4.18 Control Module
Created: 2003-02-05 19:19:08 UTC
Image Type: PowerPC Linux Kernel Image (gzip compressed)
Data Size: 530790 Bytes = 518.3 kB
Load Address: 00000000
Entry Point: 00000000
Verifying Checksum ... OK
Uncompressing Kernel Image ... OK
## Loading RAMDisk Image at 40200000 ...
Image Name: RAM disk
Created: 2003-02-05 19:20:35 UTC
Image Type: PowerPC Linux RAMDisk Image (gzip compressed)
Data Size: 470488 Bytes = 459.5 kB
Load Address: 00000000
Entry Point: 00000000
Verifying Checksum ... OK
Loading Ramdisk to 00f2c000, end 00f9edd8 ... OK
Linux version 2.4.18 (karim@Teotihuacan) (gcc version 2.95.3 20010 ...
On node 0 totalpages: 4096
zone(0): 4096 pages.
zone(1): 0 pages.
zone(2): 0 pages.
Kernel command line:
Decrementer Frequency: 5000000
Calibrating delay loop... 79.66 BogoMIPS
...
RAMDISK driver initialized: 16 RAM disks of 4096K size 1024 blocksize
...
RAMDISK: Compressed image found at block 0
...
VFS: Mounted root (ext2 filesystem).
...
Here, too, we can use environment variables to automate the booting process. Also, instead of using separate images for the kernel and the RAM disk, we could use a single image containing both, such as the one we created in Section 9.5.5. As I said earlier, U-Boot is a very flexible bootloader with many possible configurations. Though we cannot hope to cover all its possibilities here, feel free to experiment with U-Boot to obtain the setup that suits you best.
Before booting a kernel from a CF card using U-Boot, you need to properly partition and populate the CF card. Use pdisk or fdisk to partition the CF device, depending on your host. Since U-Boot does not recognize any disk filesystem, you will need to create a few small partitions to hold raw binary images and one large partition to hold your root filesystem, as I explained in Chapter 7.
For my control module, for example, I used a 32 MB CF card on which I created three partitions using fdisk: two 2 MB partitions to hold one stable kernel and one experimental kernel, and one 30 MB partition to hold my root filesystem. To copy the kernels to their respective partitions, I used the dd command:
#dd if=vmlinux-2.4.18.img of=/dev/sda1
1036+1 records in 1036+1 records out #dd if=vmlinux-2.4.18-preempt.img of=/dev/sda2
1040+1 records in 1040+1 records out
I formatted /dev/sda3 using mke2fs, mounted it on /mnt/cf, and copied the root filesystem to it using the techniques described in the previous chapter.
After I inserted the CF card in the PCMCIA port using a CF-to-PCMCIA adapter, here was the output of U-Boot at startup:
U-Boot 0.2.0 (Jan 27 2003 - 20:20:21) CPU: XPC860xxZPnnD3 at 80 MHz: 4 kB I-Cache 4 kB D-Cache FEC present Board: TQM860LDB0A3-T80.201 DRAM: 16 MB FLASH: 8 MB In: serial Out: serial Err: serial Net: SCC ETHERNET, FEC ETHERNET PCMCIA: 3.3V card found: SunDisk SDP 5/3 0.6 Fixed Disk Card IDE interface [silicon] [unique] [single] [sleep] [standby] [idle] [low power] Bus 0: OK Device 0: Model: SanDisk SDCFB-32 Firm: vde 1.10 Ser#: 163194D0310 Type: Removable Hard Disk Capacity: 30.6 MB = 0.0 GB (62720 x 512) Hit any key to stop autoboot: 5
U-Boot identifies the storage device at startup. U-Boot provides a wide range of ide commands for manipulating IDE storage devices. You can see these commands by typing the help command:
=> help ide
ide reset - reset IDE controller
ide info - show available IDE devices
ide device [dev] - show or set current device
ide part [dev] - print partition table of one or all IDE devices
ide read addr blk# cnt
ide write addr blk# cnt - read/write `cnt' blocks starting at block `blk#'
to/from memory address `addr'
We can further use U-Boot’s command line to get more information regarding the device:
=> ide part
Partition Map for IDE device 0 -- Partition Type: DOS
Partition Start Sector Num Sectors Type
1 62 4154 83
2 4216 4154 83
3 8370 54312 83
This command reads the partition table of the CF device and prints it out. In this case, the partition printed out by U-Boot fits the description provided earlier.
Loading a kernel image from one of the partitions on the CF device is done using the diskboot command. This command takes two arguments: the address where the kernel is to be loaded and a partition identifier. The latter is a concatenation of the device number and the partition number on that device separated by a colon. This is how I load the kernel image found on partition 1 of device 0 to address 0x00400000:
=>diskboot 00400000 0:1
Loading from IDE device 0, partition 1: Name: hda1 Type: U-Boot Image Name: 2.4.18 Control Module Created: 2003-02-05 19:19:08 UTC Image Type: PowerPC Linux Kernel Image (gzip compressed) Data Size: 530790 Bytes = 518.3 kB Load Address: 00000000 Entry Point: 00000000 =>imi 00400000
## Checking Image at 00400000 ... Image Name: 2.4.18 Control Module Created: 2003-02-05 19:19:08 UTC Image Type: PowerPC Linux Kernel Image (gzip compressed) Data Size: 530790 Bytes = 518.3 kB Load Address: 00000000 Entry Point: 00000000 Verifying Checksum ... OK
Once the kernel is loaded, you can use
the bootm command to boot that kernel. This can
also be automated by setting the autostart
environment variable to yes
. In that case,
diskboot will automatically boot the kernel it
loads:
=>setenv autostart yes
=>disk 00400000 0:1
Loading from IDE device 0, partition 1: Name: hda1 Type: U-Boot Image Name: 2.4.18 Control Module Created: 2003-02-05 19:19:08 UTC Image Type: PowerPC Linux Kernel Image (gzip compressed) Data Size: 530790 Bytes = 518.3 kB Load Address: 00000000 Entry Point: 00000000 Automatic boot of image at addr 0x00400000 ... ## Booting image at 00400000 ... Image Name: 2.4.18 Control Module Created: 2003-02-05 19:19:08 UTC Image Type: PowerPC Linux Kernel Image (gzip compressed) Data Size: 530790 Bytes = 518.3 kB Load Address: 00000000 Entry Point: 00000000 Verifying Checksum ... OK Uncompressing Kernel Image ... OK Linux version 2.4.18 (karim@Teotihuacan) (gcc version 2.95.3 ... On node 0 totalpages: 4096 ...
As we did in Section 9.5.3 and Section 9.5.6, you can script the bootup from the CF device by setting the appropriate U-Boot environment variables. Also, if you wish, you can write to the disk directly from U-Boot using the ide write command. Have a look at the help output and the documentation for more information regarding the use of U-Boot’s IDE capabilities.
U-Boot is like any other open source project; it continues to evolve over time as contributions are made and bug fixes are integrated to the codebase. Consequently, you may feel the need to update your target’s firmware version. Fortunately, because U-Boot runs from RAM, it can be used to update itself. Essentially, we have to download a new version to the target, erase the old firmware version, and copy the new version over it.
There are obvious dangers to this operation, because a mistake or a power failure will render the target unbootable. Hence, utmost caution must be used when carrying out the following steps. Make sure you have a copy of the original bootloader you are about to replace so that you can at least fall back to a known working version. Also, seriously consider avoiding the replacement of your firmware if you have no hardware means to reprogram the target’s flash if the upgrade fails. If you do not have access to a BDM debugger or a flash programmer, for example, there is a great risk that you will be left with a broken system if one of the following steps fails. Dealing with buggy software is one thing; ending up with unusable hardware is another.
Once you have taken the necessary precautions, download the U-Boot image into RAM using TFTP:
=> tftp 00100000 /home/karim/u-boot.bin-0.2.0
ARP broadcast 1
TFTP from server 192.168.172.50; our IP address is 192.168.172.10
Filename '/home/karim/u-boot.bin-0.2.0'.
Load address: 0x100000
Loading: #################################
done
Bytes transferred = 166532 (28a84 hex)
If you do not have a TFTP server set up, you can also use the terminal emulator to send the image:
=> loadb 00100000
## Ready for binary (kermit) download ...
## Start Addr = 0x00100000
Unlike other images we have downloaded to the target, you cannot use the imi command to check the image, since the U-Boot image downloaded was not packaged on the host using the mkimage command. You can, however, use crc32 before and after copying the image to flash to verify proper copying.
Now, unprotect the flash region where U-Boot is located so you can erase it (in this case, U-Boot occupies the flash region from 0x40000000 to 0x4003FFFF):
=> protect off 40000000 4003FFFF
Un-Protected 5 sectors
Erase the previous bootloader image:
=> erase 40000000 4003FFFF
Erase Flash from 0x40000000 to 0x4003ffff
... done
Erased 5 sectors
Copy the new bootloader to its final destination:
=> cp.b 00100000 40000000 $(filesize)
Copy to Flash... done
Erase the
filesize
environment variable set during the
download:
=> setenv filesize
Save the environment variables:
=> saveenv
Saving Enviroment to Flash...
Un-Protected 1 sectors
Erasing Flash...
. done
Erased 1 sectors
Writing to Flash... done
Protected 1 sectors
At this stage, the new bootloader image has been installed and is ready to be used. Until you issue the reset command, however, you can still use the old U-Boot currently running to fix any problems that may have occurred during the update. Once you are satisfied that every step of the update has gone through cleanly, you can go ahead and restart the system:
=> reset
U-Boot 0.2.0 (Jan 27 2003 - 20:20:21)
CPU: XPC860xxZPnnD3 at 80 MHz: 4 kB I-Cache 4 kB D-Cache FEC present
Board: TQM860LDB0A3-T80.201
DRAM: 16 MB
FLASH: 8 MB
In: serial
Out: serial
Err: serial
Net: SCC ETHERNET, FEC ETHERNET
PCMCIA: No Card found
Hit any key to stop autoboot: 5
If you can see the U-Boot boot message again, U-Boot has been successfully updated. Otherwise, there has been a problem with the replacement of the firmware and you need to reprogram the flash device using the appropriate hardware tools.
Sometimes, kernel images that used to boot with the older bootloader version will fail to boot with newer versions. When upgrading from a PPCBoot version prior to 1.0.5 to Version 1.0.5 or later, for example, kernels prior to 2.4.5-pre5 may fail to boot. In that case, the reason behind the problem is in the way U-Boot passes the clock speed to the kernel. Prior to kernel 2.4.5-pre5, kernels expected to receive the speed in MHz, while later kernels expect to receive the speed in Hz. To this end, PPCBoot 1.0.5 passes the clock speed to kernels in Hz. Kernels that expect to receive it in MHz, however, fail to boot. In practice, the boot process will start as it would normally, but the system will freeze right after U-Boot finishes uncompressing the images for startup. You will, therefore, see something like:
...
Entry Point: 00000000
Verifying Checksum ... OK
Uncompressing Kernel Image ... OK
Nothing will be output after that, and
there will be no responses to any input from the terminal. To solve
the problem, you need to tell the newer version of U-Boot to keep
passing the clock speed in MHz to the older kernels. This is done by
setting the clocks_in_mhz
environment variable to
1:
=>setenv clocks_in_mhz 1
=>saveenv
Though this sort of problem does not occur for every upgrade, changes in the kernel sometimes require significant changes to the tools that interface with it. Given that such problems are difficult to figure out if you are not involved in the actual development of each project, I strongly encourage you to keep in touch with the rest of the U-Boot users by subscribing to the U-Boot users mailing list from the project’s web site and to read announcements of new versions carefully.
[1] See LART description in Appendix B.
[2] The ELDK is an open source development and target distribution.
[3] RedBoot is part of the eCos source code tree and requires some of the code provided by that OS to provide its own services. Hence, RedBoot’s development is tied to, but not entirely dependent on, eCos’ development. Some platforms supported by RedBoot, for example, aren’t supported by eCos.
[4] For the example to fit in the printed page’s width, I avoid using the complete /home/karim/control-project/control-module/... path. Use the actual complete path for your own development.
[5] Normally, you shouldn’t
need to append a root=
option to the
kernel’s boot parameters if you already have a
root
line in your image description. In this case,
however, the software involved takes for granted that disks cannot
change types, and fails to configure the boot process properly
without the double declaration.
[6] The loadb command and, by default, the tftpboot command can’t be used to download directly to flash. Though U-Boot can be configured at compile time to allow direct flash download using tftpboot, direct flash download using loadb is not supported.
13.58.8.127