Virtualization: Up Against the Wall

Ed wraps up his digital picture frame project, which led him delving into the ins-and-outs of virtualization.


May 07, 2007
URL:http://www.drdobbs.com/embedded-systems/virtualization-up-against-the-wall/199300104

Ed is an EE and author in Poughkeepssie, NY. Contact him at [email protected] with "Dr Dobb's" in the subject to avoid spam filters.


In our last episode, I described how the challenges of cross-compiling a deeply embedded system might drive you to virtualization. Now, we'll see how this works while converting an old laptop into a digital picture frame (DPF).

I agree we're playing tennis with the net down, but this project can be more challenging than you expect if you succumb to feature creep. Indeed, you can get as much embedded experience as you'd like and perhaps a bit more.

You'll find the grisly low-level commands and more detailed descriptions in the download file accompanying this column (see "Resource Center," page 5). They should provide a starting point for your own efforts.

Introducing the Players

I used five different PC-class systems, both real and virtual, during the course of this project. My desktop, "shiitake," runs 64-bit SUSE Linux 10.0 with a comfy keyboard, large displays, and the USB ports. The QEMU emulator runs on "button," a 32-bit SUSE 10.1 box. QEMU hosts the development system and the digital picture frame testbed, a pair of virtual machines known as "develop" and "pixie." Finally, pixie's hard-drive image goes directly into the DPF on the wall.

Figure 1 shows the DPF's hardware from the rear. Basically, I discarded all the black plastic bits from an IBM ThinkPad 560Z, then mounted the remainder on an acrylic sheet with the display on one side and system board and keyboard (removed for the photo) on the other. The 2-GB Compact Flash card in the upper right emulates an ordinary IDE drive holding the system software and images.

[Click image to view at full size]

Figure 1: The back of the DPF shows the system board covered with its CPU heatsink.

Figure 2 is the front view, which is basically a picture in a wood frame. The flimsy frame attaches firmly to the acrylic sheet that suspends the whole affair from the wall.

[Click image to view at full size]

Figure 2: The front of the DPF looks remarkably like a picture in a frame. Ain't science grand?

On the software side, I intended to run QEMU on shiitake, but Intel/AMD's x86_64 architecture doesn't include the Virtual-86 mode found in 32-bit x86 processors. I also encountered several annoyances while attempting to compile QEMU/KQEMU as x86_64 programs. Rather than fight, I simply installed QEMU on button and pulled its user interface across my LAN to shiitake with ssh -X button.

Driving on Virtual

QEMU emulates a complete desktop-class PC with system and VGA BIOS code from the Bochs project, peripherals typical of a low-end PC, and linkage to some of the host machine's actual hardware. I used only the video and disk interfaces, although the emulated NIC can access SMB-shared files on the host.

Because pixie's hard-disk image must eventually fit on the CF card, the first step is measuring the card. The command /sbin/fdisk -ul /dev/sdc displays the raw device capacity in bytes: 2,079,350,784 for my card. Note that shiitake has two SATA drives that put the CF card at /dev/sdc, but your system will be different. I stored the CF size in an environment variable CFsize=2079350784 to avoid typos. (Hint: Use your mouse to highlight the value and middle-click-copy to the command line.)

Listing One (a) shows how to create drive images. The count=0 seek=<size> parameters produce a sparse file occupying only the disk space required for nonzero sectors. The initial hard-drive image thus requires essentially no space and the final images will be about half a gig.

(a) 
dd if=/dev/zero of=develop.hd bs=1 count=0 seek=$CFsize
dd if=/dev/zero of=uttpdos.fd bs=1K count=0 seek=1440

(b) 
/sbin/mkdosfs uttpdos.fd
sudo mount -o loop,uid=ed uttpdos.fd /mnt/loop
cp uttpfdos.exe /mnt/loop
Listing One

Listing One (b) shows how to set up a floppy filesystem and copy files using the loopback device. The uid=ed parameter sets the owner to my userid, simplifying the copy. This column's download file contains cfg-devel.fd and cfg-pixie.fd, the floppy-disk images I used to configure those systems, which should save you some typing.

Listing Two (a) shows how to fire up QEMU for the FreeDOS installation. Watching DOS install itself in a Linux window is less weird than watching Windows in a Linux window, but we won't go there. The FreeDOS installation will see a completely blank drive and offer you its disk partitioner; a 10-MB partition suffices for a minimal installation and the ThinkPad utilities.

 
(a)
qemu -kernel-kqemu -fda uttpdos.fd -fdb blank.fd -hda develop.hd 
             -cdrom fdfullcd.iso -boot cdrom

(b) 
qemu -kernel-kqemu -fda cfg-devel.fd -hda develop.hd 
             -cdrom slackware-11.0-install-d1.iso -boot d

(c) 
qemu -kernel-kqemu -fda cfg-devel.fd -hda develop.hd 
             -cdrom slackware-11.0-install-d1.iso -boot d
bare.i root=/dev/hda2 noinitrd ro   (boot Slackware from hard drive)
ctrl-alt-2          (get to QEMU monitor)
change cdrom slackware-11.0-install-d2.iso
ctrl-alt-1          (return to Slackware install)
mount /dev/hdc /mnt/cdrom
installpkg /mnt/cdrom/extra/grub/grub-0.97-i486-2.tgz
grub-install —no-floppy /dev/hda
mount /dev/fd0 /mnt/floppy
cp /mnt/floppy/config/menu.lst /boot/grub

(d) 
qemu -kernel-kqemu -fda cfg-devel.fd -hda develop.hd
Listing Two

After installing FreeDOS, extract the utilities from their EXE wrapper to "floppy drive b:" using some applied VM magic:

a:uttpfdos b:

then copy the results to a directory on the equally unreal hard drive with:

mkdir ThinkPad
copy b:*.* ThinkPad

Those utilities will not run in the VM, of course, but they'll be ready to configure the real ThinkPad.

When you install Slackware with the QEMU command line in Listing Two (b), use cfdisk to create a pair of 1-GB ext2 partitions for system and image storage; we'll later resize them for pixie. Select ext2 rather than ext3 filesystems, because we don't need a robust journal.

Create a mount point and mount the floppy image before starting the Slackware install program:


mkdir /fd
mount /dev/fd0 /fd
setup

My cfg-devel.fd floppy image has tagfiles that produce a bare-bones Slackware: Install the A, AP, D, K, L, N, and X groups with the tagpath set to /fd/tagfiles. The floppy has some other config files you'll find useful, including an automatic root login. That actually makes sense here, as you're always doing dangerous system manipulations. Get over it.

I have never had much luck with lilo, Slackware's boot manager of choice, and wasn't surprised when it choked during this installation. Listing Two (c) shows the one-time dance required to start from Slackware CD 1, boot the hard-drive kernel, insert the CD 2 image, install and configure grub, and finally reboot normally. You can back up the hard-drive image by just copying the develop.hd file: A virtual machine makes trial-and-error learning much less painful.

You must shut down Slackware using halt or shutdown, because just quitting QEMU is exactly the same as pulling the plug on a physical system. Filesystem damage is a clear and present danger.

After verifying that the development system boots properly in the VM, do a smoke test. Shut down Slackware, exit QEMU, unmount the CF card, and copy the entire develop.hd image:

sudo dd if=develop.hd of=/dev/sdc bs=1M

The bs=1M parameter dramatically improves throughput, although the USB adapter and CF card may limit the maximum rate. My setup runs at about 10 MB/s with a 50X card.

Pop the CF card and IDE adapter into the ThinkPad's hard-drive connector and turn it on, at which point grub should boot just as it did in the QEMU VM. Fire up FreeDOS and use the ThinkPad PS2 utility to enable Presentation mode and set the serial port to COM1 for use as a console. Reboot to Slackware, which should also behave just as it did in the VM.

At this point you have a functional Slackware system to install the DPF programs and sample images. You'll use the VM for the next steps, but it's comforting to see the ThinkPad track the VM's progress.

Tweaking the Code

The entire third partition, hda3, of the laptop's hard drive holds the JPG images, and I've included some NASA space scenery to get you started. However, because the loopback device can't handle a partition table, you can't mount the hard drive image like a floppy. Listing Three (a) shows how to do it.

(a) 
/sbin/fdisk -ul develop.ha  (my hd3 is at 2209536 sectors)
sudo mount -o loop,offset=$((512*2209536)) develop.hd /mnt/loop
sudo cp images/*jpg /mnt/loop
sudo umount /mnt/loop

(b) 
cp /mnt/floppy/fbida-2.06.tar.gz /tmp
cd /tmp/
tar zxvf fbida-2.06.tar.gz
cd fbida-2.06
make
make install
fbi -u -t 3 -noverbose -readahead -autozoom /media/images/*jpg
Listing Three

Use fdisk -ul to list the start of each partition in units of 512-byte sectors; you can tuck those values into variables to save typing. Next, feed the third partition's starting address into the mount command's offset parameter and mount it on /mnt/loop. Then you can copy the files into the image and unmount it, using sudo as needed for root privileges. You could adjust the partition's ownership and permissions if you prefer.

Copy the fbi viewer's tar.gz file to a floppy image and follow Listing Three (3) to install it. Depending on the GCC version, remove the -Wno-pointer-sign CFLAGS option near the top of its GNUmakefile. The download file has notes on some other tweaks.

I recompiled the kernel to use the ThinkPad's Pentium II CPU, add built-in APM support, and omit unused modules and features. My .config file leaves only the floppy and CD support needed for the VM, but you may want to add networking and other creature comforts.

Recompiling and building modules for that configuration takes 321 seconds on a 2.8-GHz Pentium 4 HT using KQEMU's kernel acceleration and 330 seconds without. Omitting the KQEMU module entirely slows the VM to 1954 seconds. Recompiling from the same disk image on the ThinkPad's 233-MHz Pentium II provides 1218 seconds to do something else. I cannot provide a "native" compilation on button for comparison, as setting up cross-compilation was what drove me to QEMU in the first place.

Unaccelerated QEMU thus converts a peppy P4 into a 145-MHz P2, but with full acceleration the VM chugs along like an 884-MHz P2. QEMU claims to run at nearly native speed and I suppose the 3x I found is close enough. Remember that the compiler and kernel run with the 486 instruction set, so further optimization is obviously possible.

Incidentally, switching to a blank console with Ctrl-Alt-F2 dramatically speeds kernel compilation by not scrolling torrents of 2.4 kernel messages across the VESA framebuffer.

The kernel accelerator only works for x86 code, so I'd expect the QEMU ARM or MIPS VM to run at a tiny fraction of "native" speed. On the other hand, those microcontrollers have relatively low performance and you may find the VM produces similar wall-clock results.

Putting a development system into a VM won't solve all your problems, but it does remove much of the configuration complexity. In particular, a virtual network to a file server can eliminate the floppy shuffle, let you use your normal desktop hardware, and make the whole process relatively painless.

Tuning the Target

A DPF must start the image viewer automatically, run with a read-only filesystem, and automatically copy images from a USB stick. Auto-starting a program is trivial, but the other changes make the system unusable for further development. I simply copied develop.hd to create pixie.hd and modified that drive image. The modified files are in the cfg-pixie.fd floppy image.

I tweaked the rc.S startup script to remount the root filesystem read-only; copy /tmp, /var, /dev, and /etc to four tempfs filesystems in RAM; then mount those copies as read/write filesystems atop the read-only originals. Programs can thus write data normally, but that data vanishes when the power goes away. If the system has enough RAM, this works like a champ.

Listing Four (available electronically) shows the usb-storage hotplug script that reads images from the USB stick. This task was complicated by the need to remount the root filesystem in read/write mode. I indulged the luxury of just rebooting at the end of the script to get everything running again.

The find command fetches images from all directories on the USB stick, as its root directory can hold only 100-odd files. The script lowercases the filenames so the image viewer can simply display *jpg files; fbi can actually handle many other image formats, but I didn't need them.

After verifying that on the ThinkPad, I removed Slackware's kernel source and development packages, shrank its partition to 400 MB, and expanded the third partition to fill the remainder. While 400 MB isn't a particularly svelte system and you can do much better, I resized 500 camera images to 800×600 and found they occupy only 41 MB. There's room for 18,000 more pictures in 1.5 GB.

Copy the final disk image to the CF card and fire it up. The 560Z's LCD isn't as good as contemporary panels, but for 20 bucks it's unbeatable. Give it a try and learn something while you do!

Last Tab

Use ImageMagick's mogrify utility to resize entire directories of images. It's no good for a single image, but it makes short work of (a copy of) your entire collection.

I wedged the 560Z's power switch in the ON position so it starts up when it's plugged in. APM reduces the power dissipation to 500mA at 16.5 V, about 10 W including losses in the wall wart. That's slightly more than a single incandescent night light and, in fact, half the power goes to the LCD backlight.

After this success, convert a PDA into a DPF belt buckle (egokast.com).

Yup, Jefferson Airplane, Volunteers, "We Can Be Together," 1969.

Resources

Another eBay experience (www.truetex.com/ebayfraud.htm).

QEMU home (www.qemu.com).

FreeDOS project (www.freedos.org).

Slackware (www.slackware.com).

ThinkPad DOS config (www-307.ibm.com/pc/support/site.wss/RMIE-3AXE3E.html).

ThinkPad tpctl (tpctl.sourceforge.net).

fbi picture viewer (linux.bytesex.org/ fbida).

zgv picture viewer (svgalib.org/rus/zgv).

Linux on Laptops (www.linux-laptop.net).

Eviscerating a ThinkPad 560Z (virtig01.net/personal/works/PictureFrame-HowTo.php).

ThinkPad info (www.thinkwiki.org).

Master Boot Record (en.wikipedia.org/wiki/Master_boot_record).

GRUB (www.pixelbeat.org/docs/disk).

Disk image creation (darkdust.net/marc/diskimagehowto.php).

Slackware boot sequence (openskills.info/infobox.php?IDbox=1042).

Linux remote serial consoles (tldp.org/ HOWTO/Remote-Serial-Console-HOWTO).

Automatic login (linuxgazette.net/issue72/chung.html).

Hotplug (linux-hotplug.sourceforge.net).

Writing udev rules (www.reactivated.net/writing_udev_rules.html).

ImageMagick image manipulation (www.imagemagick.org).

Terms of Service | Privacy Statement | Copyright © 2024 UBM Tech, All rights reserved.