miniHOWTO Embedded Linux 1.1c

-----------------------------------------------
 

Title : One approach to an embedded Linux.


Paul Moody 05 1998

-----------------------------------------------
Application OS : Redhat Linux 4.2
-----------------------------------------------

REVISION HISTORY

PREAMBLE

BOOT SEQUENCE

PERFORMANCE

HARDWARE

MAIN PROCEDURE
 

REVISION HISTORY  


1.1c 1998.05.08 Release html format.
   - added qualified hardware section
   - added some doc navigation

1.1b 1998.05.01 Revised draft txt format.
   - fixed minor typos and formatting
   - some addtional comments

1.1a 1998.04.30 Revised draft txt format.
   - fixed minor typos
   - converted to txt file ( due to complaints )

1.1 1998.04.29 Draft release MS word6 format.
-----------------------------------------------

Suggestions, comments and constructive abuse may be sent to




-----------------------------------------------
 

PREAMBLE  


The need for some type of embedded system arose some time ago due to our requirement
for a rugged machine controller that could provide the following features. My application
focus is in network monitoring and control of broadband telecommunications equipment.
 

1. Impervious to sudden power failure.
   ( ie no corruption of core / root filesystems )
2. Networked for integration into TCP/IP network.
3. Multiuser.
4. Powerful enough to do high level control processing.
5. Able to serve HTML, FTP, Telnet, SNMP, CORBA service requirements.
6. Zero hardware design ( we only had 3 months ) through use of generic
   components.
7. No reliance on mechanical drive technology.
8. Remote firmware configuration / updating.
9. Hardware is now vibration and high G tolerant.
10. Targets high value commercial control applications
11. Ease of implementation. Uses generic Linux releases.

We looked at all the QNXs, VxWorks, embedded NTs and other offerings the vendors dragged
out of their marketing bags but the the cost and time in terms of hardware and software
development to bring this project to fruition would have been in the order of 12 months
and over budget by several hundred percent ( our development less than 3 months ).

Having used Linux on a part time basis more out of curiosity than any real application
the idea struck me when I was reading about the INITRD ramdisk functionality of LILO and
compressed root file images. If I had a system with say 64 MB of RAM or more, then it
should be possible to boot linux from a small initial ram disk that would in turn load a
much larger ramdisk of 40 MB leaving 20 MB odd of ram for the booted system to use. The
swap partition would have to be disabled but some experimentation indicated that there
was no problem ( I dont run X though you could).
Because the root file system is now totally under the constraint of ram it removed
one source of possible failure ... the mechanical drive.
The ability to use a compressed file system allows a much smaller ( cheaper :-) ) flash
drive to be used.
Our next generation controllers feature 128M of ram and provide an embedded web server on
a single card for insertion into telco racks for alarm monitoring and control etc.
 

BOOT SEQUENCE  


LILO boots from the master boot record on the Flash device.

A compressed kernel on /dev/hda1 in /boot is unwound into ram and booted.

The kernel loads an initial ram disk initrd.img and mounts it as root.

linuxrc script is executed. This script mounts /dev/hda1 ( the flash device ) and
uncompresses a compressed 40 Mb root file system image stored as a conventional
file hda1 into a 40Mb ram disk (dev/ram).On our production system
a compressed 40Mb file system fits into a 9Mb file.

The flash device ( /dev/hda1 ) is unmounted.

When linuxrc terminates the initial ramdisk is unmounted and /dev/ram is mounted as
root.

The system now boots as per a normal boot sequence as though it was booting from
a normal drive.

No physical devices are mounted ( but are available for mounting if required )
 
 

PERFORMANCE  


Because the rootfilesystem and processes are wholly contained within the CPU /
RAM environment the system performance is very good in terms of speed and
reliability.
Because the root file system is in RAM it can withstand indefinite unplanned reboots
or power failures without corruption. Additionally you may mess about with the
structure of the ram disk file system to your hearts content because when you
reboot all your changes will disappear. You may mount conventional devices however
the core system is a corruption proof ramdisk. A hardware watchdog guards against
system hangs.
 
 

HARDWARE  


Hardware should not be a problem. The only hardware that the method I describe here is
dependant on is the amount of ram you have on board. 64 MB is probably the minimum to
begin experimenting with ( targeting a 40 MB ramdisk in the production system ).
Our boxes currently run with this much ram. Unless you are on a tight budget 64 megs
is not a big deal nowadays.

The only special hardware is the flash drive and they are not that special anyway.
The unit used for this project was the Sandisk 20 MB flash IDE drive.
Check out the company site at www.sandisk.com.
This is a flash drive with an IDE interface so no messy flashfile drivers are required.
The drive is very compact with a 1.8 " form factor.

Flash drives do suffer from one main failing and that is they have a limit to the number
of times they may be written to 400 k to 1000 k writes ) but for all practical purposes
unlimited reads.This limitation does not affect our application since the ramdisk will
only be reading from the flash at boot time.The only writes occurring would be infrequent
writes during 'firmware' upgrades or configuration file writes.

A good ( why ? because Thats what I used :) setup on which to commence development is
any motherboard which will run 'standard' Linux ( eg RedHat 4.2 ) fitted with say 64 MB
of ram. You could try it with less ram but the filesystem pruning becomes more difficult
as explained later.

The flash drive is configured as a standard IDE drive on the primary master.
( the drive has jumpers like regular hard drives )
A standard hard drive is configured as the slave.
( the hard drive will be optional when booting from flash )

/dev/hda 20 Mb Flash drive
/dev/hdb 2.1 Gb Hard drive
 

note1 : If you want to confirm that this procedure works before laying out the
cash for a flash drive just use an old conventional hard drive for hda.
( eg 20 to 40 Mb ).

note2 : This procedure can also be carried out on a single drive machine but I
will not expand on this at this time.

Qualified Hardware ( I hope to expand this area )

VME Systems Australia    supply industrial CPU cards compatible with embedded Linux.
Additionally they also have an evironmental monitoring card ( EMB ) that
not only provides temperature, multi fan speed monitoring, +5 -5 +12 -12
voltage monitoring and alarm relay output but also provides a watchdog
function. This card comes in ISA and PC104 flavours. It may be used in
conjunction with a 'normal' motherboard to provide features normally found
in more expensive 'industrial CPU boards'. Linux drivers are available for this
card & GPL'ed. ( I am plugging this card because I used it - there are others but
possibly without the drivers ).They carry the flash disks as well.

Sandisk   have the IDE flash drives.
 

DISCLAIMER
Hardware recommendations are made only on my personal experience and
are unemcumbered by any financial or other incentive to make such
recommendations. Should you purchase any item of hardware it may do
one of two things ....

1.   work

2.   become an expensive paperweight.
 
 

MAIN PROCEDURE  


1. Partition Drives

You should have ...

Flash drive /dev/hda
Standard HD /dev/hdb

You will already have done this or will do it during Linux installation.
Partitioning ...

As a minimum you will need to partition the drives as follows
( there are other poss configurations - Linux ... so many ways to do things :)

/dev/hda hda1 production ramdisk boot partition.
( ie this is the target )

/dev/hdb hdb1 a swap partition
( eg 20 Mb for 'normal' linux use )

hdb2 a linux partition
( eg 1000 Mb 'normal' linux boot partition )

hdb3 a linux partition
( eg 500 Mb workspace 1 partition )

hdb4 a linux partition
( eg 500 Mb workspace 2 partition )

note 1 : workspace 1 and 2 partitions are crucial to the setup method
describe.

note 2 : Workspace 1 and workspace 2 partitions should be identical in
size or you may have problems using dd or cat.
 

2. Install Linux to workspace1

Aim : The reason for doing this is to create a reference installation which is
quicker than reinstalling Linux if something really bad happens. You
will use workspace2 to do all the filesystem surgery.

Procedure :

2.1 Again there are a number of ways of doing this ... basically you can
install a bare system and use RPM ( Redhat Package Manager ) to
add the things you want or you can install a full system and use RPM
to remove the things you dont want.

On my system I installed LILO Base, Networking, Network utils,
Network,Management, SAMBA, HTTPD, Mail but no development,
games or X.
 

2.2 Next check that the partition does boot. ( from the LILO prompt )

note 1 : LILO is essential for this method as it enables the initial ramdisk.

2.3 Boot up 'normal' Linux.

2.4 Make mount point directories ( we use these later )

# mkdir /mnt/ws1
# mkdir /mnt/ws2
# mkdir /mnt/ram
# mkdir /mnt/flash
 

3. Copy workspace1 to workspace2

Aim : To copy the 'reference' linux partition to a 'edit' partition. Quicker
than reinstalling Linux each time SRBH.

Procedure

Boot from your 'normal' Linux ( eg hdb2 ) partition.
If workspace 1 or 2 is mounted then unmount them.
 

At the root prompt ...

3.1 # cat /dev/hdb3>/dev/hdb4

OR

# dd if=/dev/hdb3 of=/dev/hdb4 bs=1k

OR ( if your partitions are different sizes )

# mke2fs /dev/hdb4
# mount /dev/hdb3 /mnt/ws1
# mount /dev/hdb4 /mnt/ws2
# cp -av /mnt/ws1/* /mnt/ws2

3.2 # mount /dev/hdb4 /mnt/ws2

Edit /etc/fstab in /dev/hdb4

3.3 change
/dev/hdb3 / ext2 defaults 11

to

/dev/hdb4 / ext2 defaults 11

3.4 make a filesystem on the unmounted flash drive
( or target partition ) and copy /boot directory to it.

# mke2fs -m0 /dev/hda1

# mount /dev/hda1 /mnt/flash

# cp -av /mnt/ws1/boot /mnt/flash/
... copies boot and contents to flash drive. ( hda1 )
 

3.5 Edit /etc/lilo.conf to make the kernel image in /boot of hda1
the boot image for LILO booting.

sample lilo.conf

boot=/dev/hda
map=/mnt/flash/boot/map
install=/mnt/flash/boot/boot.b
prompt
timeout=50

image=/mnt/flash/boot/vmlinuz
ramdisk=40000
label=normal
root=/dev/hdb2
read-only

image=/mnt/flash/boot/vmlinuz
ramdisk=40000
label=workspace1
root=/dev/hdb3
read-only

image=/mnt/flash/boot/vmlinuz
ramdisk=40000
label=workspace2
root=/dev/hdb4
read-only

3.6. When your lilo.conf looks like above you may now run lilo
to map the boot partitions. If you do not do this the flash
boot will fail later.

3.7. Do a check reboot to check the system boots properly.
( from the kernel image on the flash drive )

3.8. # dmesg | less

check boot messages for any errors.

4. Aim : Prune filesystem in workspace2 to remove all unwanted files and directories
in your target file system. The files that will be removed depend on the
embedded application.
( and how much ram you have allocated for the ramdisk ).

Procedure :

4.1 reboot normal linux

4.2 # mount /dev/hdb4 /mnt/ws2
... mount workspace2 device

# rpm -qails --dump --root /mnt/ws2 > installed.txt

This will generate a largish text file listing all packages installed, a
description of the package, component files, directories, files sizes,
check sums etc in workspace2. ( delete this when finished with it )

4.3 Note down the packages required or to be removed.

# rpm -e --root /mnt/ws2 <packagename>
removes a package from the filesystem mounted on /mnt/ws2

# rpm -i --excludedocs --root /mnt/ws2 <packagename>
installs a package with no documentation

deleting all documentation and X11 directories is a good start and should
not cause any problems.

# rm -rfv /usr/doc
# rm -rfv /usr/man
# rm -rfv /usr/X11R6

remove all executables/libs/modules not required or that could be used by
intruders.
 

5. Aim : Check Boot workspace2

Procedure :

5.1 Run lilo again just in case you deleted something critical.

5.2 Reboot the system and choose workspace2 at the LILO prompt to
ensure no critical files have been deleted.

5.3 Reboot 'normal' and mount workspace2.

# mount /dev/hdb4 /mnt/ws2

6. Goto step 3 if something really bad happens else goto step 4 till the total
disk usage in workspace2 falls below that of the target ramdisk size
( in this case approx 40 Mb ).
It is probably a good idea to leave at least 10 Mb free on the target drive.
 

# df
... returns the space used / available on mounted devices
 

7. Aim: Copy workspace2 to a ramdisk ( /dev/ram, /dev/ram1 etc )
This is in preparation for producing the 40Mb ramdisk image file.

Procedure :
# dd if=/dev/zero of=/dev/ram bs=1k count=40000
... zeros out the ram disk - for higher compression.

# mke2fs -m0 /dev/ram 40000
... make a 40 Mb ext2 filesystem on the ramdisk

# mount /dev/ram /mnt/ram
... mount the formatted ramdisk on the mount point

# cp -av /mnt/ws2/* /mnt/ram
... copy the file structure from workspace2 to ramdisk
 

8. Aim : Edit fstab and rc.sysinit to make /dev/ram the root device and disable
swapping. We dont need swapping as we are building an embedded system
with flash firmware and no mechanical drives. There should be enough play
ram left over in 64 Mb even with a 40Mb ram disk.

Procedure :
8.1 Edit /mnt/ram/etc/fstab
change from

/dev/hdb4 / ext2 defaults 11

to

/dev/ram / ext2 defaults 11

8.2 Edit /mnt/ram/etc/rc.d/rc.sysinit

delete / comment out "swapon -a"
... near start of file

delete / comment out "swapon -a >2&1 | grep -v "busy""
... near end of file

9. Aim : Copy image of ramdisk and compress to file -> compressed image ...
ram40.img.gz

Procedure :
9.1 # cd /mnt
# df
... note down the "1024-blocks" count for /dev/ram eg 38400

# umount /dev/ram
# dd if=/dev/ram of=ram40.img bs=1k count= < eg 38400 >
... this writes an image file of the ramdisk.

# gzip -9 ram40.img
... this produces a compressed image file ... ram40.img.gz

# cp /mnt/ram40.img.gz /mnt/flash/boot/ram40.img.gz
... copy the compressed ( approx 10Mb ) image to the flash
drive.

10 Aim : Create initial ramdisk image with mkinitrd ... initrd.img. This is the small
ramdisk which will 'bootstrap' the large 40Mb ramdisk.

Procedure :
10.1 # mkinitrd /boot/initrd.img 2.0.30
... produces a initial ramdisk image "initrd.img" in /boot
... 2.0.30 is the kernel to use
 

11 Aim : Unzip initrd to ramdisk and mount. The compressed image produced by
mkinitrd is a template and will not do anything till you have changed
linuxrc. But first we will have to uncompress it to a temporary ramdisk
and mount it so we can work on it.

Procedure :
11.1 # >/dev/ram
... null the ram disk
# cd /boot
... goto the boot directory
# zcat initrd>/dev/ram
... unzip the initrd into a ram drive
# mount /dev/ram /mnt/ram
... mount the drive on /mnt/ram so we can work on it

12 Aim : Add some files and directories to the raw template file structure.

Procedure :
12.1 # cd /mnt/ram
# ls
... bin dev etc lib linuxrc

# mkdir mnt
... this is the mount point for mounting /dev/hda1 during
bootup

# cd /mnt/ram/etc
# >mtab
... create a null mtab file

# cd /mnt/ram/bin
# cp /bin/zcat ./
... copy some binaries or your linuxrc wont do much.

# cd /mnt/ram
# vi linuxrc
... edit the script using your favourite editor.

12.2 sample linuxrc

#!/bin/sh
mount -o ro /dev/hda1 /mnt
zcat /mnt/boot/ram40.img.gz > /dev/ram
umount /dev/hda1

note1 : if you need any binaries like cp or ln then copy them now to
/mnt/ram/bin ( for use by linuxrc )
note2 : if you need to refer to any weirdo devices then copy them now to
/mnt/ram/dev
(for use by linuxrc eg cp -av /dev/sda1 /mnt/ram/dev)
 

13 Aim : Unmount ramdisk and compress image file initrd.img to initrd.img.gz then
place it in /boot on hda1 ( the flash device )

Procedure :
# cd /mnt
# df
... note down the "1024-blocks" count for /dev/ram eg 1157

# umount /dev/ram
# dd if=/dev/ram of=initrd.img bs=1k count= 1157
... this writes an image file of the ramdisk.

# gzip -9 initrd
... this produces a compressed image file ... initrd.img.gz

# mount /dev/hda1 /mnt
... mount the flash device

# cp initrd.img.gz /mnt/flash/boot
... copy initrd.img.gz to /boot on the flash drive.

17 Edit lilo.conf and run LILO.
!!!!
note that the first boot image ( default ) has root=/dev/ram and
initrd=<path>/initrd.img.gz
!!!!

boot=/dev/hda
map=/mnt/flash/boot/map
install=/mnt/flash/boot/boot.b
prompt
timeout=50

image=/mnt/flash/boot/vmlinuz
ramdisk=40000
label=flash
root=/dev/ram
initrd=/mnt/flash/boot/initrd.img.gz

image=/mnt/flash/boot/vmlinuz
ramdisk=40000
label=normal
root=/dev/hdb2
read-only

image=/mnt/flash/boot/vmlinuz
ramdisk=40000
label=workspace1
root=/dev/hdb3
read-only

image=/mnt/flash/boot/vmlinuz
ramdisk=40000
label=workspace2
root=/dev/hdb4
read-only
 

18 Reboot machine - only drive mounted is the ramdisk .... Success ???.
!!!!! make sure you run lilo first before rebooting !!!!!
 

login and type ....

# mount
... you should see /dev/ram on / ext2 (rw)
none on /proc type proc (rw)

... this indicates success

Check that hda1 and any other devices are still visible and mountable by
the system.
 

19 Goto step 3 or 4 depending on whether you wish to refine the system or
in case something really bad happened.
 

< end of documentation >