[LWN Logo]

From:	"paulmoody" <paulmoody@onaustralia.com.au>
To:	<linux-embedded@waste.org>
Subject: embedded linux ( redhat 4.2 )
Date:	Fri, 1 May 1998 00:37:00 +0930

Hi.

This is my full bore embedded linux system.

miniHOWTO Embedded Linux 1.1a

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

Title :	One approach to an embedded Linux.

Paul Moody 04 1998

-----------------------------------------------
Application OS	:	Redhat Linux 4.2
-----------------------------------------------
Revision History.

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 

paulmoody@onaustralia.com.au
paulmoody@bigpond.com
pmoody@vccbapg6.telstra.com.au
-----------------------------------------------

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 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

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)

	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 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.
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.

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 workspace1 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
			

		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 2.0.30
				... produces a initial ramdisk image "initrd" 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 an 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 to initrd.img again 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 ram.img and initrd.img  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 !!!!!

			# 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 >