Archive for the ‘Embedded Linux’ Category

Embedded x86 Linux Revisited

March 4, 2009

Now that flash is really cheap, why use squashfs?  Save some time and effort and use this in your initrd for a readonly flash file system.

A non-wordpress-butchered version is available here:

http://pastebin.com/f3655ef7f

Here it is, read my notes at the top for howto actually use it:


# Local filesystem mounting -*- shell-script -*-
#
################################################################
# File:
# /scripts/local
#
# Root, or / in these notes is the initrd's (busybox) root,
# not your system's root!
#
# You need the aufs module for this to work. To do this install
# aufs on your base install, add aufs to: /etc/initramfs-tools/modules
# Now using your target kernel run:
# mkinitramfs -o initrd.img
#
# make a directory, copy an initrd to it then cd to it and:
#
# mv initrd.img initrd.img.gz
# gunzip initrd.img.gz
#
# make sure aufs exists somewhere in /lib/modules//
# After modifying local script, etc do the following in the initrd's
# root folder where /bin and /lib etc is to create a new initrd:
#
# find ./ -print | cpio -H newc -o > ../newinitrd.img
#
# Now tell grub to use this initrd for a RO root filesystem
#
# Note fstab gets hosed, if you need an fstab, make sure this
# script reflects that. I use an fstab for the default initrd for RW
# and none for RO, but you can make this script use a different one for
# RO if you want.
################################################################
# Parameter: device node to check
# Echos fstype to stdout
# Return value: indicates if an fs could be recognized
get_fstype ()
{
local FS FSTYPE FSSIZE RET
FS="${1}"

# vol_id has a more complete list of file systems,
# but fstype is more robust
eval $(fstype "${FS}" 2> /dev/null)
if [ "$FSTYPE" = "unknown" ] && [ -x /lib/udev/vol_id ]; then
FSTYPE=$(/lib/udev/vol_id -t "${FS}" 2> /dev/null)
fi
RET=$?

if [ -z "${FSTYPE}" ]; then
FSTYPE="unknown"
fi

echo "${FSTYPE}"
return ${RET}
}

# Parameter: Where to mount the filesystem
mountroot ()
{
[ "$quiet" != "y" ] && log_begin_msg "Running /scripts/local-top"
run_scripts /scripts/local-top
[ "$quiet" != "y" ] && log_end_msg

wait_for_udev 10

# If the root device hasn't shown up yet, give it a little while
# to deal with removable devices
if [ ! -e "${ROOT}" ] || ! $(get_fstype "${ROOT}" >/dev/null); then
log_begin_msg "Waiting for root file system"

# Default delay is 180s
if [ -z "${ROOTDELAY}" ]; then
slumber=180
else
slumber=${ROOTDELAY}
fi
if [ -x /sbin/usplash_write ]; then
/sbin/usplash_write "TIMEOUT ${slumber}" || true
fi

slumber=$(( ${slumber} * 10 ))
while [ ! -e "${ROOT}" ] \
|| ! $(get_fstype "${ROOT}" >/dev/null); do
/bin/sleep 0.1
slumber=$(( ${slumber} - 1 ))
[ ${slumber} -gt 0 ] || break
done

if [ ${slumber} -gt 0 ]; then
log_end_msg 0
else
log_end_msg 1 || true
fi
if [ -x /sbin/usplash_write ]; then
/sbin/usplash_write "TIMEOUT 15" || true
fi
fi

# We've given up, but we'll let the user fix matters if they can
while [ ! -e "${ROOT}" ]; do
# give hint about renamed root
case "${ROOT}" in
/dev/hd*)
suffix="${ROOT#/dev/hd}"
major="${suffix%[[:digit:]]}"
major="${major%[[:digit:]]}"
if [ -d "/sys/block/sd${major}" ]; then
echo "WARNING bootdevice may be renamed. Try root=/dev/sd${suffix}"
fi
;;
/dev/sd*)
suffix="${ROOT#/dev/sd}"
major="${suffix%[[:digit:]]}"
major="${major%[[:digit:]]}"
if [ -d "/sys/block/hd${major}" ]; then
echo "WARNING bootdevice may be renamed. Try root=/dev/hd${suffix}"
fi
;;
esac
echo "Gave up waiting for root device. Common problems:"
echo " - Boot args (cat /proc/cmdline)"
echo " - Check rootdelay= (did the system wait long enough?)"
echo " - Check root= (did the system wait for the right device?)"
echo " - Missing modules (cat /proc/modules; ls /dev)"
panic "ALERT! ${ROOT} does not exist. Dropping to a shell!"
done

# Get the root filesystem type if not set
if [ -z "${ROOTFSTYPE}" ]; then
FSTYPE=$(get_fstype "${ROOT}")
else
FSTYPE=${ROOTFSTYPE}
fi

[ "$quiet" != "y" ] && log_begin_msg "Running /scripts/local-premount"
run_scripts /scripts/local-premount
[ "$quiet" != "y" ] && log_end_msg

if [ "${readonly}" = "y" ]; then
roflag=-r
else
roflag=-w
fi

# FIXME This has no error checking

modprobe ${FSTYPE}
##########################################################################
###### Mod'd by Brian Phelps aka Electronjunkie ##########################

mkdir /root/.tmpfs
mkdir /root/.rootfs

mount -r -t ext2 /dev/sda1 /root/.rootfs

modprobe aufs
modprobe loop
mount -t tmpfs -o size=20M tmpfs /root/.tmpfs

mount -t aufs -o br:/root/.tmpfs=rw:/root/.rootfs=ro none /root/
mv /root/etc/fstab /root/etc/fstab.defunct

#########################################################################

# FIXME This has no error checking
# Mount root

[ "$quiet" != "y" ] && log_begin_msg "Running /scripts/local-bottom"
run_scripts /scripts/local-bottom
[ "$quiet" != "y" ] && log_end_msg
}

Advertisements

Embedded x86 Linux

October 11, 2007

Another Update: Check out the new version without squashfs here.
Updated!  I modified the squashfs and init so now the entire init script is executed properly, before it would work, but we were missing a few things in the final init stage.

DebianThis rough draft howto describes my experience, minus most of the goof-ups, of how you can setup a small x86 embedded system. A typical linux box that boots grub does the following:

  • Read the MBR
  • load the kernel pointed to by the bootloader
  • load the initial ram disk
  • execute an init script who’s main purpose is to set the environment up so that the real root file system can be mounted
  • then it mounts the FS and executes the real init script, but only after the preliminary init mounts the real root file system read/write.

Confused yet? It gets worse if you must use a read only file system like an IDE/CF flash disk. The preliminary init (ran from initial ram disk) must mount the real file system (usually squashfs) read only. It also sets up a read/write FS in RAM so that the system may store and use things later like /proc, /dev, and /var. After creating both read only and read/write file systems (FS) it merges them with the unionfs/aufs kernel function in init. Then it switches root and executes the real init. There fortunately are many “LiveCD” scripts that set this up for you automatically. These init scripts (like casper in Debian) are overkill and can break an embedded system whose environment is known ahead of time. Its a bit like using this toilet paper dispenser in a mission critical application, like after eating the Habenero Hotwings and drinking 5 pints of beer from the local pub.

Also I hate all the autodetecting that comes with most live cds, power glitches and other things can trick it and it is slooowwww, Embedded systems must be reliable! Mine are 500MHz dinosaurs with no electro-mechanical parts whatsoever.

I like to boot the target filesystem root on the target hardware as an actual r/w FS first and set everything up the way I want it. This has the side effect of also testing my hardware configuration and allows me to make major changes quickly.

Then I halt and mount the target on another host to freeze the system into my own read-only install. Remember! It must be readonly if we are to run off of flash in the end, b/c of the limited writes.

Here we go………….

First create skeleton debian install:
Usage: debootstrap [OPTION]… <suite> <target> [<mirror> [<script>]]

% debootstrap sid fs-root-debian-sid

Put this file system on a drive and boot your real hardware. Set everything up the best you can (Minor changes can bee made later, don’t worry).

Back at the host:

chroot to new install or boot the real system hardware using a non flash hard drive:

install squashfs-tools, kernel, and same versions of squashfs and unionfs kernel modules
You may have to fix /etc/resolv.conf for this and other apt based installations
# apt-get install kernel-image-xxx unionfs-modules-xxx squashfs-modules-xxx squashfs-tools

unchroot, do:

Create the boot-dir:

# mkdir -p fs-boot/boot/grub

chroot, do:
# apt-get install grub

make sure mkinitramfs and busybox is installed

unchroot, do:

Copy the boot loader

# cp -a fs-root/usr/lib/grub/i386-pc/* fs-boot/boot/grub/

Copy the kernel over:

$ cp -a fs-root/boot/* fs-boot/boot/

Create the squashed FS

% mksquashfs fs-root fs-squashfs.squashfs -all-root # Makes all files owned by root

On the chrooted target, install initramfs-tools
# apt-get install initramfs-tools

Now the tricky part, edit init scripts, then create the initramfs:

chroot to the fs-root and create our squashfs script:
# vim /usr/share/initramfs-tools/scripts/squashfs

modify it to look like the included file “squashfs_script”, some highlights are:

# This is how we mount the rootfs
# substitute /dev/sda1 for what it will be on the target upon boot, I’m using a usb flashdrive
mount -r -t ext2 /dev/sda1 /.tmpfs/.mnt
losetup /dev/loop0 /.tmpfs/.mnt/boot/fs-squashfs.squashfs
mount -r -t squashfs /dev/loop0 /.tmpfs/.sqfs

# Here we create the final rootfs
mount -w -t unionfs -o dirs=/.tmpfs/.overlay=rw:/.tmpfs/.cdrom=ro:/.tmpfs/.sqfs=ro unionfs /.union

# And switch over to the new FS and run the real init, This is done as the last line of the default debian etch init script, not the squashfs script, you should comment out the old last line:

# Chain to real filesystem
maybe_break init
#exec run-init ${rootmnt} ${init} “$@” <${rootmnt}/dev/console >${rootmnt}/dev/console
exec run-init /.union /sbin/init “$@” </.union/dev/console >/.union/dev/console

Now, still crooted as the target, edit /boot/grub/menu.lst to be:

# menu.lst – See: grub(8), info grub, update-grub(8)
default 0
timeout 5

title Debian live
root (hd0,0)
kernel /boot/vmlinuz vga=791 root=/dev/loop0 ramdisk_size=100000 boot=squashfs #username=user hostname=debian persistent
initrd /boot/file1.img
boot
# Note the boot=squashfs tells init to execute scripts/squashfs
# root=/dev/loop0 is our readonly root squashfs mounted in the initscript
# ramdisk_size=100000 gives the kernel (and us) some space (100M) to work with our unionfs

We’re almost done, now make the initramfs, recall we are still chrooted

# mkinitramfs -o file1.img <kernel-version-here>
please put your kenel version int the appropriate spot above (whatever string is appended to /lib/modules on the target)

Exit from chroot and copy the resulting file1.img to your targets’ boot directory /fs-boot/boot/

# cp file1.img /fs-boot/boot/

Now copy fs-root and fs-boot files to your production device, I’m using a usb flash drive (I assume is partitioned this way):

# cp -a fs-boot/* /mnt/sda1/
# cp -a fs-root/fs-squashfs.squashfs /mnt/sda1/

Make sure that the /proc /dev and /sys directories are empty, they will be filled later by the last stages of init on the unionfs

Install grub to the target device so it will boot, I will not cover that here, its covered everywhere else on the net quite well

I usually like to test the setup under vmware or qemu, as it can save time when debugging.

Comments? Mistakes? Help me make this better. I welcome all non-spam feedback.

Making Your Computer Your Slave with Linux

August 25, 2007

Mr. Slave

And learn some stuff too while you’re at it.

Or how I learned to stop fearing my PC

Linux taught me how computers and networking works through hands-on experience, I was/am constantly trying to do stuff with Linux that I have had no experience with. I knew what I had been taught in school about computers, but that often aint nothing compared to what I learn by trying to do things I had never really done before.

Linux will teach you much about computers and their capabilities, which is necessary in the real world for any EE. Embedded Linux is also the way the embedded industry is headed. Here is a simple time-line of my recent (2004), but fun Linux/computing addiction, with example projects along the way. Warning this may get lengthy:

1. Heard about Linux from fellow geek in lab, heard it was a free OS to use along with compatable free versions of Photoshop, MS Word/Office, Matlab, h/pspice, verilog simulator, firefox w/ flashplayer, etc. Check this out for more info:

linuxquestions wiki on this subject

I heard some things were much easier, some things harder, no spyware/viruses, better security, blah blah you’ve heard this all before. You should try dual booting.

2. Installed it on an old PC and used it as my primary desktop machine as dual boot. Googled any problems/errors I had such as printing, etc. Some things were a pain, but I learned some things about software and hardware/networking that I had never known before. Usually its pretty fun and valuable to fix problems you run into yourself.

3. Decided to Setup an ssh server at home (really easy) that I could access anywhere. Created a simple web page that had php scripting enabled (so you can build interactive web sites and/or control your computer from a web page). Setup an email server (easy to do, very tough to keep out spam). Learned much about setting up and traversing firewalls/routers. Learned about setting up ssh tunnels, so you could do anything from anywhere on your private LAN through ssh. Learned lots about security too.

4. Setup a full C/C++ build environment so I can compile any program I have sourcecode to from places like sourceforge.net, etc. Play around with various scripting languages like Perl, Python, especially Bash.

5. Having taken C++, learned to use libraries to build my own short simple but powerful programs that access sound card hardware and other hardware, click buttons on the screen without a mouse (from anywhere on the net), and even wrote some simple networked servers/clients that can talk to each other on a home LAN.

6. Found out that many wireless routers (like the old Linksys WRT54G) run or can run Linux (openwrt.org). Downloaded the Openwrt SDK (Software Development Kit) for building custom software for it in C. Found out that the routers also usually have 2 serial ports and 4-8 GPIO (General Purpose Input Output) for LED’s and switches. I wrote a simple program to stream audio from another PC on a LAN to the serial port on the WRT. I had a $40 wireless speaker with WPA-PSK encryption. Used two or three simple 70-80 line C programs to do it. Fun stuff.

7. Recently started putting small Linux installs on Fanless, Hard disk-drive-less (use a usb stick), computers that cost under $200. They have VGA and full audio outputs and have no moving parts. In the pro-audio world this is pretty fscking awesome b/c it will last 10 years if it is kept out of water/beer (beer is for the equipment installer, not the equipment) and at a reasonable temp.

8. I also use gnu-octave (open source version of matlab) on Linux to crunch numbers / simulate simple DSP algorithms such as Sigma-Delta Modulators, FIR/IIR filters and architectures for FPGA’s or C code, and play w/ the amazing FFT and its DCT cousins (discrete cosine transform) which has applications in audio analysis and compression.

9. I run vmware server under Linux now so that what few Windows apps I must use, I can use them from a virtual machine (simulated computer on a computer like Parallels for the Mac) in Linux. I no longer dual-boot the two OS’s. VMWare can access USB, serial/parallel ports, and sound card access. Can’t kill windows off my PC entirely b/c unfortunately in the pro-audio world, much of the pro audio equipment is MS Windows only configurable, which is sad, but thats what happens when there is a government dependent/sponsored monopoly in a particular industry, they become “defacto standards” whether they are actually better or not. The linux kernel is capable of running uninterrupted for years at a time, and some machines have been doing so. It is very robust.

Also the command prompt or “shell” (Bash) in Linux/Unix is very, very powerful and eye-opening. It is basically a programming/scripting interface to programs. You can do things with it that will blow your mind once you learn your way around. You can use programs that they were never designed for specifically, unlike GUI programs in windows.

Example:
I have done things like encode audio from the soundcard (mic input), as an mp3, streamed it to another computer over a network and played it out the sound at the remote location (home), all with general purpose applications with one long command (mp3 encoder, ssh, mp3 decode to sound card at home). Apps in the *nix world have “standard input” and “options” and “standard output” among other interfaces and can be “connected” together with pipes and manipulated in more ways than you or even the original designers imagined. GUI (Windows) programs can’t compare. Wanna download a file without opening a browser?

file example:
$ curl http://example.com/file.mp3 > file.mp3

puts the file.mp3 in your present directory

What programs are listening on which ports:

$ sudo lsof -nPi

Find all files recursively in a directory with the string “gtk.h” and print the name of the file and line it is on:

$ grep -rn "gtk\.h" *

Linux is for people who want to know their computer better. It is a different approach to computing. It will help you eliminate your fear of the Computer, and even make it your slave. I use Ubuntu now, but almost any distribution gets you going fast (CentOS, PCLinux, Suse, Fedora, etc). Avoid slackware or gentoo unless you are really gung-ho about spending hours reading a manual, installing and getting a usable system. I know that statement will get me death threats, but I believe they have their place, and its not with a newbie unless they have help. If the newbie wants to learn the hard stuff all at once, they can use gentoo or slack, but I still prefer the simplicity of an ubuntu install and maintenence.

This is a living document and more will be added later.

ARM-based Open Embedded Linux Platform

June 24, 2007

Check out the Linuxstamp over at opencircuits. This is a great project that aims to make a simple (I hope they keep it simple), small, inexpensive ARM (with MMU!) platform that can run on POE. I can’t wait to build one. It looks like a fun project.

screenshot-2.png

Here are the features:

  • Atmel AT91RM9200 processor (Arm9 processor with MMU)
  • 32MB SDRAM (Only limited by 1x 54-TSOP SDRAM chip)
  • 8MB SPI Dataflash
  • 1x 10/100 Ethernet
  • 1x USB host port (allows wifi adapters, flash drives and other USB devices to be used)
  • 1x SD card slot
  • Serial debug port access through FTDI USB/Serial converter
  • JTAG port
  • 2-Layer PCB design
  • POE capable (48v -> 5v Power supply can be implemented on a motherboard)

They have posted the Eagle CAD files and the BOM. I really am happy to run across a design like this.

Most ARM platforms capable of running embedded Linux are fairly expensive and have lots of extra useless garbage ($150 or more). This one is supposed to be like $75 including the board. It is using a 2-layer board, but it might be OK if the groundplane is respected well. They seem to be confident it will be OK. I am a bit worried about how the RAM/Flash buses will act up with no enclosed planes, but my experience in highspeed PCB design is nonexistent, but I do try to understand the theory behind it. It will likely be OK with the traces kept short.

I am very interested in seeing this design work. Its difficult to design a computer motherboard from scratch because there is just a ton of supporting hardware and connections. I imagine it will be fun to try to get it to boot. Good thing there’s JTAG.