Thursday, January 10, 2013


Repurposing an old laptop with tinycore linux:

    low power, low cost, low noise using a compact flash card


What to do with those ancient laptops?  I always feel guitly disposing of them, knowing they cost near $3000 when new.  But what use can a pentium serve at this point?

I had a need to run a simple application to send a few commands out the serial port periodically.  I wanted this to be a low-cost, low-power, low-noise solution.  So, with this old laptop, a 16MB compact flash card I had lying around and a CF-IDE adapter I set to work.

Initially I had used FreeBSD but it required a rather large CF card due to the fact that I needed the linux-compat libraries to be included.  Then a few months later I came across tinycore linux.  Actually, microcore is what really interested me - requires 8MB and less than 32MB of RAM.  I love a challenge, so I set to work.

Tinycore wasn't really intended to be "installed" - the devs seem to prefer running from a CD or other media.   However, without a CD drive, I needed this to be installed to the CF card.  Turns out someone had already done most of the legwork for me.  Most of the instructions I list here are directly from that page, but I list here for my own history along with the steps I later used for setting it to my direct purpose.

1. download the microcore ISO file  and the grub extension.

2. partition and format the CF card, then mount the partition (/dev/sdc in my case):

# fdisk /dev/sdc

Delete the existing partition:

Command (m for help): d
Selected partition 1


Create a new partition, primary, first, full size of the card:

Command (m for help): n
Partition type:
   p   primary (0 primary, 0 extended, 4 free)
   e   extended
Select (default p): p
Partition number (1-4, default 1):  
Using default value 1
First sector (2048-31359, default 2048): 
Using default value 2048
Last sector, +sectors or +size{K,M,G} (2048-31359, default 31359): 
Using default value 31359


Set the partition type to 83 (linux)

Command (m for help): t
Selected partition 1
Hex code (type L to list codes): 83


Set the bootable flag for this partition:

Command (m for help): a
Partition number (1-4): 1


Write the partition table:

Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.

WARNING: Re-reading the partition table failed with error 16: Device or resource busy.
The kernel still uses the old table. The new table will be used at
the next reboot or after you run partprobe(8) or kpartx(8)
Syncing disks.


Format the partition to ext2:

# mkfs.ext2 -L TINYCORE /dev/sdc1 


3. mount the microcore ISO and copy the kernel and initramfs file to the CF card:

# cd /tmp
# mkdir tc cf
# mount /dev/sdc1 cf
# mount Core-current.iso tc
# mkdir cf/boot
# cp -a tc/boot/vmlinuz tc/boot/core.gz cf/boot

 
4. install the grub bootloader to the card:

# mkdir grub
# mount grub-0.97-splash.tcz grub
# mkdir cf/boot/grub
# cp -a grub/usr/lib/grub/i386-pc/* cf/boot/grub/


Next we add and edit the file cf/boot/grub/menu.lst (using vi)  and enter the following contents:


default 0
timeout 1
title tinycore
kernel /boot/vmlinuz opt=sda1
initrd /boot/core.gz


As per the aforementioned url, we need to link menu.lst to grub.conf and create a grub device mapping:

# ln -T cf/boot/grub/menu.lst cf/boot/grub/grub.conf
# echo "(hd0) /dev/sdc" >grub-device.map


And finally, install grub:

# grub --device-map=grub-device.map 


grub> root (hd0,0)
root (hd0,0)
 Filesystem type is ext2fs, partition type 0x83


grub> setup (hd0)
setup (hd0)
 Checking if "/boot/grub/stage1" exists... yes
 Checking if "/boot/grub/stage2" exists... yes
 Checking if "/boot/grub/e2fs_stage1_5" exists... yes
 Running "embed /boot/grub/e2fs_stage1_5 (hd0)"...  15 sectors are embedded.
succeeded
 Running "install /boot/grub/stage1 (hd0) (hd0)1+15 p (hd0,0)/boot/grub/stage2 /boot/grub/grub.conf"... succeeded
Done.
grub> quit
quit




5. install my applications on the card, modify /opt/bootlocal.sh to start my applications.

# mkdir cf/opt
# cp -R xxx cf/opt
# echo "/opt/xxx/start???" > cf/opt/bootlocal.sh
# chmod 755 cf/opt/bootlocal.sh
# umount cf tc grub

    This step involves creating a directory /opt in the root of the CF card and copying the files there.  Because we added the opt=sda1 bootcode to the bootloader, this directory will be mounted within the uncompressed initramfs filesystem in RAM at the /opt location.  (This also works for home=sda1, and there is also the automatically mounted /tce directory).
 
    I chose to use /opt because I will need to automatically start my application when the system boots.  This is most easily done by starting it via /opt/bootlocal.sh.  Having /opt be persistent in the root filesystem will allow me to change this without having to deal with the "backup" solution (which could have been used if I used /tce instead and then use mydata.tgz).  But I won't be modifying files often or having files written often, so flash longevity isn't a concern for me.
 
    Another option would have been to have a startup script in /etc and then have that file be persistent (via /opt/.filetool.lst), but I am going for minimalistic here.

As for an IP address, tinycore uses DHCP by default so my router will offer a static IP address to it.  However, I could have just as easily added an ifconfig statement to /opt/bootlocal.sh.

As a finaly note for myself, I probably could have compiled a kernel and made my own initrd image and gone even smaller or extracted the entire microcore initramfs cpio archive to the disk.  However, the advantage here is that this all took less than one hour.  Time is money.  As well, using the initramfs system ensures that everything is readonly and will not be corrupted.  Maybe in the future, remastering the initramfs to contain my application might be advantageous.
 
So, let's review: I have an old laptop that powers down the screen when the lid is closed a 16MB flash card that minimizes the noise (no hard disk) and power consumption (no hard disk).  Sure, a raspberry pi or a beagle board would have been a nice small solution, but why not use what I already had?

No comments: