Compact Flash HOWTO Der Herr Hofrat FSMLabs Data GmbH v0.1, 13 Apr 2002 Last UPDATE 19 Apr 2002 This HOWTO briefly describes how to use Compact Flash with Linux and how to access it for configuration on your desk-top system. ______________________________________________________________________ Table of Contents 1. Copyright 2. Homepage 3. Introduction 4. Prerequisites 4.1 Tools you will need 4.2 Kernel configuration 5. Different types of adapters 5.1 Direct IDE disk adapters 5.2 USB CF-readers 5.3 PCMCIA CF-readers 6. Setting up a boot CF 6.1 Boot loaders 6.2 Minimum Filesystem 7. Maintenance issues 7.1 Dumping filesystems 7.2 Updating filesystems 8. Supported Hardware 8.1 Devices known to work 8.2 Devices known NOT to work 9. FAQs/Wish list 10. Credits 11. Appendix A - CF Technology infos and links 12. Appendix B - Resource links ______________________________________________________________________ 1. Copyright Copyright (c) 2002 Der Herr Hofrat (der.herr@hofr.at), All rights reserved. This is free document; you can redistribute it and/or modify it under the terms of version 1.2 of the GNU Free Documentation License . 2. Homepage You might want to check back to the CF-HOWTO home-page at to see if there's a newer version around. Comments and feedback to Der Herr Hofrat 3. Introduction CF-disks are becoming a quite frequently used mass-storage media, with the technology being used for mass-market products like Digital Cameras prices have dropped to a level where they are very attractive as a solid state media for home-brew embedded Linux/RTLinux systems. This HOWTO covers the basics of accessing CF disks under the GNU/Linux operating system and the first steps of setting up a system on such a device. It does not cover filesystem issues or filesystem design for embedded systems though. 4. Prerequisites To use the CF readers around you will need a current Linux kernel. There are 2.2.X USB patches around that work, but the easier way is to grab the current 2.4.X kernel from ftp://ftp.kernel.org/pub/linux/kernel/v2.4/ 4.1 Tools you will need Aside from the standard tools you will find on any GNU/Linux system (fdisk dd, mkfs.ext2, etc) a few other tools may be helpful. * mtools for setting up msdos filesystems * syslinux to boot from msdos filesystems * MTD utilities for jffs/jffs2 If you want to use PCMCIA adapters for accessing the CF then you will need the pcmcia-cs packages - but probably it is easier to take a pre-patched kernel from a stock distribution (Debian,Mandrake,RH,SuSE,etc.) as they generally have PCMCIA patched in and the tools integrated cleanly. for the 2.2.X series pcmcia-cs-3.1.X is about 10 kernel patches and a big mess to get it working cleanly - if your really want to do it: patch-list for 2.2.14: pcmcia-cs-3.1.8-config.patch pcmcia-cs-3.1.8-script.patch pcmcia-cs-3.1.8.tar.gz pcmcia-cs-3.1.3-3com.patch pcmcia-cs-3.1.4-xircom.patch pcmcia-cs-2.8.8-network.script patch-list for 2.2.17: pcmcia-cs-3.1.23-config.patch pcmcia-cs-3.1.23-script.patch pcmcia-cs-3.1.23.tar.gz pcmcia-cs-3.1.3-3com.patch pcmcia-cs-3.1.4-xircom.patch pcmcia-cs-2.8.8-network.script for 2.4.X kernel there should be no need to do much patching (at least for 2.4.4++). 4.2 Kernel configuration For direct IDE-disks there is nothing special to do - you simply configure ide-disk support as a module (if your system otherwise DOES NOT need IDE) For USB writers you will obviously need USB support, additionally you need to select usb-storage support which only is available if you have selected SCSI support before ! So for 2.2.X kernel assuming that you have no SCSI devices in the system you would select: SCSI support ---> SCSI support? --- SCSI support type (disk, tape, CD-ROM) SCSI disk support (NEW) < > SCSI tape support (NEW) < > SCSI CDROM support (NEW) SCSI generic support (NEW) --- Some SCSI devices (e.g. CD jukebox) support multiple LUNs [ ] Probe all LUNs on each SCSI device (NEW) [*] Verbose SCSI error reporting (kernel size +=12K) (NEW) USB support ---> Support for USB [*] USB verbose debug messages ... UHCI (intel PIIX4, VIA, ...) support OHCI (Compaq, iMacs, OPTi, SiS, ALi, ...) support ... USB Mass Storage support [*] USB Mass Storage verbose debug ... File systems ---> DOS FAT fs support MSDOS fs support Minix fs support For 2.4.X kernels it will look almost the same . SCSI support ---> SCSI support x x --- SCSI support type (disk, tape, CD-ROM) x x SCSI disk support x x (40) Maximum number of SCSI disks that can be loaded as modules x x < > SCSI tape support x x < > SCSI OnStream SC-x0 tape support x x < > SCSI CD-ROM support x x SCSI generic support x x --- Some SCSI devices (e.g. CD jukebox) support multiple LUNs x x [ ] Enable extra checks in new queueing code x x [ ] Probe all LUNs on each SCSI device x x [*] Verbose SCSI error reporting (kernel size +=12K) x x [ ] SCSI logging facility x x USB support ---> [*] USB verbose debug messages x x --- Miscellaneous USB options x x [ ] Preliminary USB device filesystem x x --- USB Controllers x x UHCI Alternate Driver (JE) support x x OHCI (Compaq, iMacs, OPTi, SiS, ALi, ...) support x x --- USB Device Class drivers x x < > USB Audio support x x USB Mass Storage support x x [*] USB Mass Storage verbose debug x x File systems ---> DOS FAT fs support x x MSDOS fs support x x Minix fs support This will then produce the USB modules and the SCSI modules, the CF-disk writer is accessed as SCSI device. You should end up with these modules usb: usb-ohci.o usb-uhci.o usbcore.o usb-storage.o You will need either usb-ohci.o or usb-uhci.o and usbcore.o + usb-storage.o loaded to access the usb-reader. scsi: scsi_mod.o sd_mod.o scsi_debug.o sg.o After loading the USB modules you will need scsi_mod.o to enable scsi and sd_mod.o to access the CF as SCSI-disk, scsi_debug.o will only be needed if you have some problems (it might give you a clue). fs: fat.o msdos.o minix.o fat.o + msdos.o will be need to access msdos filesystems and minix.o only to access minix filesystems. 5. Different types of adapters To get access to the CF there are a few possibilities: 5.1 Direct IDE disk adapters * for CF directly connected to the IDE cable via an adapter simply enable ide-disks in the kernel - BUT DON'T UNPLUG THE CF IN A RUNNING SYSTEM especially if your root-filesystem is on an IDE disk - if its on SCSI you need to compile IDE and IDE-disk support as a module. To cleanly remove a CF at runtime you must (assuming CF is primary master): * close all open files on the CF (normally that means to cd out of the directory tree on the CF...) * umount the disk rtl4: # umount /mnt/cf-disk * remove the IDE-modules from the kernel with rtl4: # rmmod ide-disk rtl4: # rmmod ide-probe rtl4: # rmmod ide-mod to reconnect the freshly inserted CF as an IDE-disk in a running-SCSI system: rtl4: # modprobe ide-disk rtl4: # fdisk /dev/hda Just to have said it explicitly - if your system is operating from IDE you better not pull-out/pup-in CF-disks on a direct IDE adapter there is no way the system will live very long if you try this. So if your system lives on IDE during operation a direct IDE-CF adapter will be no use to you. One more warning - if you use a 3.5" adapter (40 pin) on the PC-side then the power-supply lines are separately connected as the CF-disk is a 44-pin 2.5" IDE that has the power-lines in the socket. This external power-supply better come from the system you are operating the disk on as you will otherwise experience ground-loops and IDE-cables don't like that. 5.2 USB CF-readers Unfortunately I only have experience with one device - so this will ma by not be as general as it should be for a HOWTO but I hope this will change basically you only need the scsi usb and fs kernel modules mentioned in the kernel config section. You simply insmod it all and are set rtl4: # modeprbe sd_mod rtl4: # modprobe usb-storage rtl4: # modprobe msdos (assuming that none of these are compiled into the kernel) after this pop in the CF and access it as a regular SCSI disk. rtl4: # fdisk /dev/sda Unable to read /dev/sda rtl4: # fdisk /dev/sda Command (m for help):q rtl4: # You will sometime see the "Unable to read /dev/sda" right after you changed the media - this is due to the way the usb detects the disconnect/connect and is something I experienced with all media quite frequently (it does not alway occur though). If you enabled debugging you will see the following in dmesg in the case of a correct connection usb-storage: queuecommand() called usb-storage: *** thread awakened. usb-storage: Command START_STOP (6 bytes) usb-storage: 1b 00 00 00 01 00 13 c0 a0 03 fc c3 usb-storage: Bulk command S 0x43425355 T 0x1e Trg 0 LUN 0 L 0 F 0 CL 6 usb-storage: Bulk command transfer result=0 usb-storage: Attempting to get CSW... usb-storage: Bulk status result = 0 usb-storage: Bulk status Sig 0x53425355 T 0x1e R 0 Stat 0x0 usb-storage: scsi cmd done, result=0x0 usb-storage: *** thread sleeping. usb-storage: queuecommand() called usb-storage: *** thread awakened. usb-storage: Command ALLOW_MEDIUM_REMOVAL (6 bytes) usb-storage: 1e 00 00 00 01 00 00 00 00 00 00 00 usb-storage: Bulk command S 0x43425355 T 0x1f Trg 0 LUN 0 L 0 F 0 CL 6 usb-storage: Bulk command transfer result=0 usb-storage: Attempting to get CSW... usb-storage: Bulk status result = 0 usb-storage: Bulk status Sig 0x53425355 T 0x1f R 0 Stat 0x0 usb-storage: scsi cmd done, result=0x0 usb-storage: *** thread sleeping. usb-storage: queuecommand() called usb-storage: *** thread awakened. usb-storage: Command READ_10 (10 bytes) usb-storage: 28 00 00 00 00 00 00 00 02 00 00 00 usb-storage: Bulk command S 0x43425355 T 0x20 Trg 0 LUN 0 L 1024 F 128 CL 10 usb-storage: Bulk command transfer result=0 usb-storage: usb_stor_transfer_partial(): xfer 1024 bytes usb-storage: usb_stor_bulk_msg() returned 0 xferred 1024/1024 usb-storage: usb_stor_transfer_partial(): transfer complete usb-storage: Bulk data transfer result 0x0 usb-storage: Attempting to get CSW... usb-storage: Bulk status result = 0 usb-storage: Bulk status Sig 0x53425355 T 0x20 R 0 Stat 0x0 usb-storage: scsi cmd done, result=0x0 usb-storage: *** thread sleeping. usb-storage: queuecommand() called usb-storage: *** thread awakened. usb-storage: Command ALLOW_MEDIUM_REMOVAL (6 bytes) usb-storage: 1e 00 00 00 00 00 8c c3 82 02 00 00 usb-storage: Bulk command S 0x43425355 T 0x21 Trg 0 LUN 0 L 0 F 0 CL 6 usb-storage: Bulk command transfer result=0 usb-storage: Attempting to get CSW... usb-storage: Bulk status result = 0 usb-storage: Bulk status Sig 0x53425355 T 0x21 R 0 Stat 0x0 usb-storage: scsi cmd done, result=0x0 usb-storage: *** thread sleeping. In case of an error as mentioned above ...snip... usb-storage: Attempting to get CSW... usb-storage: Bulk status result = 0 usb-storage: Bulk status Sig 0x53425355 T 0x23 R 0 Stat 0x0 usb-storage: -- Result from auto-sense is 0 usb-storage: -- code: 0x70, key: 0x6, ASC: 0x28, ASCQ: 0x0 usb-storage: Unit Attention: (unknown ASC/ASCQ) usb-storage: scsi cmd done, result=0x2 usb-storage: *** thread sleeping. I/O error: dev 08:00, sector 0 usb-storage: *** thread awakened. usb-storage: Command ALLOW_MEDIUM_REMOVAL (6 bytes) usb-storage: 1e 00 00 00 00 00 8c c3 82 02 00 00 ...snip... This is in here because this error does not indicate that there is anything wrong with your CF-medium if this happens right after changing devices - it does indicate a media problem if it occurs persistent ! 5.3 PCMCIA CF-readers The PCMCIA-CF adapters use the ide_cs binding to access the CF as IDE-disk if you pop it into the PCMCIA-port you should see something like the folowing on ARM: arm1: # dmesg hda: SanDisk SDCFB-64, ATA DISK drive ide0 at 0xf6000000-0xf6000007,0xf600000e on irq 55 hda: 125440 sectors (64 MB) w/1KiB Cache, CHS=490/8/32 Partition check: hda: hda1 ide_cs: hda: Vcc = 5.0, Vpp = 0.0 And on an x86 with a PCMCIA-ISA card the dmesg output will give you something like: Intel PCIC probe: Cirrus PD6710 rev 00 ISA-to-PCMCIA at port 0x3e0 ofs 0x00 host opts [0]: [ring] [65/6/0] [1/15/0] ISA irqs (default) = 3,4,5,7,9,10,12 polling interval = 1000 ms cs: IO port probe 0x0c00-0x0cff: excluding 0xcf8-0xcff cs: IO port probe 0x0800-0x08ff: clean. cs: IO port probe 0x0100-0x04ff: excluding 0x230-0x23f 0x378-0x37f 0x4d0-0x4d7 cs: IO port probe 0x0a00-0x0aff: excluding 0xa30-0xa3f the output from the PCMCIA-CF adapter will be one of the tertiary or quartery disks in IDE systems, on SCSI-only systems it will be a primary disk. So for my IDE-based system (system disk is /dev/hda, /dev/hdb=CD-ROM, and /dev/hdc is an additional non-boot IDE-disk, the CF-Card ends up as tertiary-master disk (/dev/hde) - syslog should have recorded something like: ---snip /var/log/messages--- Apr 13 12:15:52 rtl12 cardmgr[120]: socket 0: ATA/IDE Fixed Disk Apr 13 12:15:52 rtl12 cardmgr[120]: executing: 'modprobe ide_cs' Apr 13 12:15:54 rtl12 kernel: hde: SanDisk SDCFB-64, ATA DISK drive Apr 13 12:15:54 rtl12 kernel: ide2 at 0x100-0x107,0x10e on irq 3 Apr 13 12:15:54 rtl12 kernel: hde: SanDisk SDCFB-64, 61MB w/1kB Cache, CHS=490/8/32 Apr 13 12:15:54 rtl12 kernel: hde: hde1 Apr 13 12:15:54 rtl12 kernel: ide_cs: hde: Vcc = 5.0, Vpp = 0.0 Apr 13 12:15:54 rtl12 cardmgr[120]: executing: './ide start hde' Apr 13 12:42:25 rtl12 kernel: ide2: unexpected interrupt, status=0x00, count=2 Apr 13 12:42:26 rtl12 cardmgr[120]: shutting down socket 0 Apr 13 12:42:26 rtl12 cardmgr[120]: executing: './ide stop hde' The config entries for a PCMCIA-CF card simply needs the vendor to map to ide_cs - so in your /etc/pcmcia/config you will need the entries for device mapping ide_cs: device "ide_cs" class "ide" module "ide_cs" and the card mapping for your card: card "Simple Tech Compact Flash" version "STI Flash" bind "ide_cs" when you mount the CF on the PCMCIA adapter you will get some messages like rtl4: # mount -t ext2 /dev/hda1 /mnt/ide rtl4: # dmesg VFS: Disk change detected on device ide0(3,1) hda: hda1 VFS: Disk change detected on device ide0(3,1) hda: hda1 EXT2-fs warning: mounting unchecked fs, running e2fsck is recommended and df should then show the device as a regular IDE disk /dev/hda in this case: rtl4: # df /dev/hda1 60664 22250 35282 39% /mnt/ide One problem you will regularly see is warnings about unchecked filesystems being mounted - this error message for some reason occurs even if you run fsck.ext2 right before mounting it, as I experienced this with a number of different media I assume this is not a handling problem but in some way PCMCIA specific (have not figured it out yet) so the EXT2-fs warning above is due to this problem - if you have a solution, pleas let me know. 6. Setting up a boot CF 6.1 Boot loaders As this document is X86 centered we will only cover syslinux, LILO and GRUB - hope to get feedback on other setups and architectures using CF-disks as boot-media. syslinux: Syslinux is probably one of the easiest to use boot-loaders and it has some interesting features for embedded systems (boot-help screens) - it also is a very small boot-loader so for systems with very limited storage this can be relevant (<4MB CF-disk partition for the boot-image), it also runs from a FAT12 filesystem which is extremely limited and unusable as a runtime filesystem but perfectly OK for a boot-medium, and FAT12 has a small overhead for the filesystem layer so if you have only a hand full of files on your boot-medium it probably is a good choice. ---syslinux.cfg--- default linux prompt 1 timeout 600 display boot.msg F1 boot.msg F2 help.msg label linux kernel zimage append=load_ramdisk=1 initrd=ramdisk.gz From this config file you can see the minimum set of files we will need on the boot-medium. So this would boot the kernel unpack the ramdisk imaga and boot up the system. Note that ldlinux.sys is created by running syslinux and not by copying it from some other image ! rtl4:~ # ls /mnt boot.msg help.msg initrd.gz ldlinux.sys syslinux.cfg zimage boot.msg is the file that will be displayed before the boot: prompt and help.msg will be displayed if you push at the boot-prompt, by pressing you can get the boot.msg again. This is quite handy for embedded systems as you can give the users a few pages of info at the boot-prompt all ready. for details on the parameters check the syslinux home-page (. (there seems to be no syslinux man-page ??) LILO: To get a LILO based system working we need to create a basic lilo.conf and we need to create the device node that will be used at runtime by the system. Even though during setup the filesystem is /dev/sda1 we must pass /dev/hda and /dev/hda1 to lilo (assuming that the CF-disk will be the first IDE device in the embedded system). ---lilo.conf-- boot =/dev/hda install =/boot/boot.b map =/boot/map read-write prompt backup =/dev/null compact initrd =ramdisk.gz label =linux root =/dev/hda1 For an explanation of these parameters, see LILO's user documentation. and the lilo(8) and lilo.conf(5) man page. You will probably also want to add an append=... line to this file to customize lilo to fit your system. Save this file as lilo.conf. create a fresh filesystem on the first partition of the CF-disk rtl4:~ # mkfs.ext2 -i 8192 -m 0 /dev/sda1 The ``-i 8192'' specifies that we want one inode per 8192 bytes. The -m 0 tells mkfs.ext2 not to reserve any space for the super user (by default 5% of the disk-space is reserved for root, which is a good idea if you have enough space to allow that). Next, mount the filesystem, remove the lost+found directory, and create dev and boot directories for LILO: rtl4:~ # mount -t ext2 /dev/sda1 /mnt/ide-cf rtl4:~ # rm -rf /mnt/ide-cf/lost+found rtl4:~ # mkdir /mnt/ide-cf/{boot,dev,tmp} Next, create devices /dev/null ,/dev/hda and /dev/hda1. Instead of looking up the device numbers, you can just copy them from your hard disk using -R: rtl4:~ # cp -pR /dev/{null,hda,hda1} /mnt/ide-cf/dev or rtl4:~ # mknod /dev/ide-cf/dev/hda b 3 0 rtl4:~ # mknod /dev/ide-cf/dev/hda1 b 3 1 rtl4:~ # mknod /dev/ide-cf/dev/null c 1 3 LILO needs a copy of its boot loader, boot.b, which you can take from your hard disk. It is usually kept in the /boot directory. rtl4:~ #cp -p /boot/boot.b /mnt/ide-cf/boot/ Finally, copy in the LILO configuration file you created in the last section, along with your kernel. Both can be put in the root directory: rtl4:~ # cp lilo.conf vmlinuz /mnt/ide-cf/ Everything LILO needs is now on the kernel filesystem, so you are ready to run it. LILO's -r flag is used for installing the boot loader on some other root: rtl4:~ # cd /mnt/ide-cf/ LILO should run without error: rtl4:/mnt/ide-cf # lilo -v -C etc/lilo.conf -r /mnt/ide-cf/ LILO version 21.7-5, Copyright (C) 1992-1998 Werner Almesberger Linux Real Mode Interface library Copyright (C) 1998 Josh Vanderhoof Development beyond version 21 Copyright (C) 1999-2001 John Coffman Released 06-May-2001 and compiled at 22:38:15 on Sep 23 2001. Reading boot sector from /dev/hda Merging with /boot/boot.b Boot image: /boot/vmlinuz Added linux * /dev/null exists - no backup copy made. Writing boot sector. rtl4:/mnt/ide-cf # after which the kernel filesystem at /mnt/ide-cf should look something like this: ./ drwxr-xr-x 2 root root 1024 Apr 7 08:58 boot drwxr-xr-x 2 root root 1024 Apr 6 18:43 dev drwxr-xr-x 2 root root 1024 Apr 6 21:15 etc drwxr-xr-x 2 root root 12288 Apr 6 20:27 lost+found ./boot: -rw-r--r-- 1 root root 5768 Apr 6 21:11 boot.b -rw------- 1 root root 15360 Apr 7 08:58 map -rw-r--r-- 1 root root 961250 Apr 6 18:29 vmlinuz ./dev: brw-rw---- 1 root disk 3, 0 Apr 7 08:58 hda brw-rw---- 1 root disk 3, 1 Sep 24 2001 hda1 crw-rw-rw- 1 root root 1, 3 Feb 9 13:01 null ./etc: -rw-r--r-- 1 root root 267 Apr 6 21:15 lilo.conf ./tmp: Do not worry if the file sizes are different from yours - relevant is that the permissions and the major/minor/file-type are the same. 6.2 Minimum Filesystem First lets format a normal ext2 filesystem on the first partition of the compact flash. rtl4:~ # mkfs.ext2 /dev/sda1 rtl4:~ # df Filesystem 1k-blocks Used Available Use% Mounted on /dev/hda6 18627528 4128740 13921896 23% / /dev/hda5 52627 3550 46269 8% /boot /dev/sda1 7558 13 7155 1% /mnt this shows you that the filesystem is mounted and it also shows you that ext2 has a substantial overhead - but it's OK in cases where there is enough disk-space - this HOWTO will try to give you a kick-start at setting up a filesystem. A full coverage of how to build a space-optimized filesystem is out of the scope of this HOWTO. cd into the new filesystem location and start creating a minimum filesystem rtl4:~ # cd /mnt rtl4:/mnt # rm -rf lost+found rtl4:/mnt # mkdir {dev,lib,bin} rtl4:/mnt # ls . .. bin dev lib now you should have the three directories dev lib and bin first we will copy a few device files to play with. rtl4:/mnt # cp -pR /dev/null dev/ rtl4:/mnt # cp -pR /dev/zero dev/ next we will need at least libc on the filesystem, but as we are not going to do any application debugging on the embedded filesystem we can use striped libs ! rtl4:/mnt # cd lib/ rtl4:/mnt/lib # cp /lib/libc.so.6 ./ rtl4:/mnt/lib # ls -l -rwxr-xr-x 1 root root 1384168 Mar 18 11:46 libc.so.6 rtl4:/mnt/lib # strip libc.so.6 -rwxr-xr-x 1 root root 1241560 Mar 18 11:47 libc.so.6 still large but better... to make sure all apps find libc we need to add some sym-links . rtl4:/mnt/lib # ln -s libc.so.6 libc rtl4:/mnt/lib # ln -s libc.so.6 libc.so rtl4:/mnt/lib # ls -l lrwxrwxrwx 1 root root 9 Mar 18 11:46 libc -> libc.so.6 lrwxrwxrwx 1 root root 9 Mar 18 11:46 libc.so -> libc.so.6 -rwxr-xr-x 1 root root 1241560 Mar 18 11:47 libc.so.6 so libc should now be accessible for every app that we will put into our embedded filesystem. But what other libs do we need ?? the ldd command from the binutils package will show us what libs an application is linked to - as we need at least a shell we will start with bash. rtl4:/mnt/lib # ldd /bin/bash libreadline.so.4 => /lib/libreadline.so.4 (0x40027000) libhistory.so.4 => /lib/libhistory.so.4 (0x4004f000) libncurses.so.5 => /lib/libncurses.so.5 (0x40056000) libdl.so.2 => /lib/libdl.so.2 (0x400a0000) libc.so.6 => /lib/libc.so.6 (0x400a4000) /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000) so bash requires quite a lot of additional libs ! copy and link them into the embedded filesystems lib directory. rtl4:/mnt/lib # cp /lib/libreadline.so.4 ./ rtl4:/mnt/lib # cp /lib/libhistory.so.4 ./ rtl4:/mnt/lib # cp /lib/libncurses.so.5 ./ rtl4:/mnt/lib # cp /lib/libdl.so.2 ./ rtl4:/mnt/lib # cp /lib/ld-linux.so.2 ./ rtl4:/mnt/lib # ln -s libreadline.so.4 libreadline.so rtl4:/mnt/lib # ln -s libhistory.so.4 libhistory.so rtl4:/mnt/lib # ln -s libncurses.so.5 libncurses.so rtl4:/mnt/lib # ln -s libdl.so.2 libdl.so rtl4:/mnt/lib # ls -l drwxr-xr-x 2 root root 448 Mar 18 11:48 . drwxr-xr-x 5 root root 160 Mar 18 11:45 .. -rwxr-xr-x 1 root root 94543 Mar 18 11:48 ld-linux.so.2 lrwxrwxrwx 1 root root 9 Mar 18 11:46 libc -> libc.so.6 lrwxrwxrwx 1 root root 9 Mar 18 11:46 libc.so -> libc.so.6 -rwxr-xr-x 1 root root 1241560 Mar 18 11:47 libc.so.6 lrwxrwxrwx 1 root root 10 Mar 18 11:48 libdl.so -> libdl.so.2 -rwxr-xr-x 1 root root 14653 Mar 18 11:48 libdl.so.2 lrwxrwxrwx 1 root root 15 Mar 18 11:48 libhistory.so -> libhistory.so.4 -rwxr-xr-x 1 root root 28417 Mar 18 11:48 libhistory.so.4 lrwxrwxrwx 1 root root 15 Mar 18 11:48 libncurses.so -> libncurses.so.5 -rwxr-xr-x 1 root root 319449 Mar 18 11:48 libncurses.so.5 lrwxrwxrwx 1 root root 16 Mar 18 11:48 libreadline.so -> libreadline.so.4 -rwxr-xr-x 1 root root 187322 Mar 18 11:48 libreadline.so.4 that looks OK now - but it's large, so lets at least strip it all. rtl4:/mnt/lib # strip * will be a bit better . rtl4:/mnt/lib # cd ../bin rtl4:/mnt/bin # ls rtl4:/mnt/bin # cp /bin/bash ./ rtl4:/mnt/bin # ls -l -rwxr-xr-x 1 root root 442760 Mar 18 11:50 bash rtl4:/mnt/bin # file bash bash: ELF 32-bit LSB executable, Intel 80386, version 1, dynamically linked (uses shared libs), stripped bash is always striped (on all distributions I know at least ), so we can't do anything here rtl4:/mnt/bin # cd .. rtl4:/mnt # du -s . thats bad - an embedded filesystem that only contains bash and its 2291 K ! bad - but OK to start with - and it's easier to start with bash than with some reduced shell. lets test this filesystem before we go on, root has his home in /root so lets create a /root in the embedded filesystem. And chroot into it . This means we are running off our embedded filesystem now - not using any of the system libs or executables that are installed on the host-pc. rtl4:/mnt # mkdir root rtl4:/mnt # chroot /mnt bash-2.05# echo $USER root bash-2.05# cd / bash-2.05# echo $PWD / bash-2.05# pwd / bash-2.05# exit rtl4:/mnt # within the embedded filesystem we can't really do much , but we can do some things although there are no other executables than bash on our system - why that ?? Bash is a shell that provides a large list of built-in commands - this is to accelerate the shell and not require calling the most common shell-related commands all the time Also note that the shell prompt reverted to the compiled in default - so this bash is running without any limits or site specific configuration . Even though we had some built in commands - it was not enough to do anything serious - so next lets add a few standard commands. rtl4:/mnt # cd bin rtl4:/mnt/bin # cp /bin/ls ./ rtl4:/mnt/bin # ls -l ls -rwxr-xr-x 1 root root 47584 Sep 20 06:24 /bin/ls rtl4:/mnt/bin # file ls /bin/ls: ELF 32-bit LSB executable, Intel 80386, version 1, dynamically linked (uses shared libs), stripped rtl4:/mnt/bin # chroot /mnt back in the embedded filesystem now: bash-2.05# ls ls: error while loading shared libraries: librt.so.1: cannot open shared object file: No such file or directory bash-2.05# exit rtl4:/mnt/bin # ls failed because of missing libs - so lets copy librt.so.1 into /lib of the embedded filesystem and link it. cd ../lib cp /lib/librt.so.1 ./ ln -s librt.so.1 librt.so then we should check with ldd /bin/ls if anything else is missing ? - now this is important to note - you will not always get such a nice error message, so ldd is the better way of figuring out the mandatory library than chroot'ing and failing. and don't forget to strip the new libs . rtl4:/mnt/lib # ldd /bin/ls librt.so.1 => /lib/librt.so.1 (0x40027000) libc.so.6 => /lib/libc.so.6 (0x40039000) libpthread.so.0 => /lib/libpthread.so.0 (0x4015f000) /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000) rtl4:/mnt/lib # cp /lib/libpthread.so.0 ./ rtl4:/mnt/lib # ln -s libpthread.so.0 libpthread.so rtl4:/mnt/lib # strip * rtl4:/mnt/lib # cd .. rtl4:/mnt # du -s . even less impressive now - the filesystem has bash and ls on it and thats not a wild functionality we get for 2381 K ! rtl4:/mnt # chroot /mnt/ bash-2.05# ls -l total 3 drwxr-xr-x 2 0 0 128 Mar 18 10:54 bin drwxr-xr-x 2 0 0 128 Mar 18 10:45 dev drwxr-xr-x 2 0 0 608 Mar 18 10:58 lib drwxr-xr-x 2 0 0 64 Mar 18 10:59 root ls reports the UID/GID as numeric values - thats not very user-friendly so we need to add some system config files so that ls can resolve the UID/GID correctly - this is where we need to create /etc in the embedded filesystem. bash-2.05# exit exit rtl4:/mnt # rtl4:/mnt # mkdir etc rtl4:/mnt # cd etc rtl4:/mnt/etc # cp /etc/passwd ./ rtl4:/mnt/etc # cp /etc/shadow ./ rtl4:/mnt/etc # cp /etc/group ./ rtl4:/mnt/etc # cp /etc/gshadow ./ and because we are using bash we copy /etc/profile as well - we don't want unlimited users on an embedded system ! rtl4:/mnt/etc # cp /etc/profile ./ rtl4:/mnt/etc # cp /etc/bash.bashrc ./ /etc/bash.bashrc is specific to the shell and not everyone will need it but lets drop it in as we are using bash. rtl4:/mnt/etc # chroot /mnt bash-2.05# ls -l total 3 drwxr-xr-x 2 0 0 128 Mar 18 10:54 bin ls is still showing UID/GID in numeric form - why that ?? ldd of /bin/ls showd us the libs ls needs but it will not really show all dependencies - what we are missing is libnss_files . This is the limitation of ldd - ldd will only ensure you that the command you moved to the embedded filesystem works but possible system dependencies are not covered . bash-2.05# exit exit rtl4:/mnt/etc # rtl4:/mnt # cd ../lib rtl4:/mnt/lib # cp /lib/libnss_files.so.2 ./ rtl4:/mnt/lib # chroot /mnt bash-2.05# ls -l total 3 drwxr-xr-x 2 root root 128 Mar 18 10:54 bin success ! so the dependencies of a simple command like ls can be quite hard to figure out - note that libnss_files is not really a requirement of ls but the system needs it to resolve UID/GID correctly - you might be using nis ? so to make it really clean we need to add /etc/nsswitch.conf and then it's clean. Various functions in the C Library need to be configured to work correctly in the local environment. Traditional UNIX simply had the files /etc/passwd /etc/groups etc. other resources like NIS were compiled into libc (with static paths...), GNU C Library 2.x (libc.so.6) is based on a clean solution, derived from Sun Microsystems design, this scheme called "Name Service Switch" (NSS) has one configuration file that sets their lookup order and what databases to use in /etc/nsswitch.conf. rtl4:/mnt/lib # cd ../etc rtl4:/mnt/etc # cp /etc/nsswitch.conf ./ On embedded systems you might consider removing some of these standard features to reduce filesystem usage - but don't forget that this way of saving space can break compatibility to the desk-top system . you also need to check the config files to make sure they don't contain more than you want - the minimum nsswitch.conf to only use local \"database\" files (/etc/passwd /etc/groups etc.) is: # minimum /etc/nsswitch.conf passwd: files shadow: files group: files hosts: files dns services: files protocols: files rpc: files ethers: files publickey: files aliases: files To check other problems we will need a simply tool /usr/bin/env - we could output all variables by calling echo $... but /usr/bin/env is kind of handy so we will add it. The usual procedure , create directory - check for libs copy and strip. rtl4:/mnt # mkdir -p usr/bin rtl4:/mnt # ldd /usr/bin/env libc.so.6 => /lib/libc.so.6 (0x40027000) /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000) rtl4:/mnt # cp /usr/bin/env usr/bin/ rtl4:/mnt # strip usr/bin/env env is OK - we don't need any additional libs here. now we can start building a system - we have a shell and ls to check the system setup a bit. so we need something to create files and to dump there output to the terminal. rtl4:/mnt # cd bin rtl4:/mnt/bin # cp /bin/touch ./ rtl4:/mnt/bin # cp /bin/cat ./ rtl4:/mnt/bin # file * they are all striped already (they should be !). and if you run ldd on them it will show that we don't need any additional libs yet. add rm to remove files we can now create with cat and touch . rtl4:/mnt/bin # chroot /mnt rtl4:/mnt/bin # cp /bin/rm ./ rtl4:/mnt/bin # ldd rm libc.so.6 => /lib/libc.so.6 (0x40027000) /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000) so rm will work - file would show us that it all ready is striped. This filesystem is large and very limited but it has one clear advantage it is fully compatible with your desk-top system, everything behaves as you would expect - shell-expansion - all options to ls are there . For some embedded systems this is OK if you have the resources stick to this compatible solution, it will make life a lot easier not only during development but also during end-user operation as any body acquainted with a GNU/Linux system will have no problem handling this device. now a little cleanup: -------------------- the prompt is not nice and the hostname is missing and the system can't beep yet ... so lets add a few things. rtl4:/mnt # cp -p /etc/hosts etc/ rtl4:/mnt # chroot /mnt rtl4:/ # so now we can easily get completely confused on what system we actually are... next a console so we can beep. The beep it self is an escape sequence that is defined in /etc/bash.bashrc . rtl4:/mnt # cp -pR /dev/console dev/ rtl4:/mnt # chroot /mnt rtl4:/# beep > /dev/console So now it's recognizable as a GNU/Linux system even if not much is available - but the concept of adding executables is clear by now so you can now play with building an embedded system and learn to understand the dependencies hands-on - make your self a larger file system for this though ! 7. Maintenance issues Most of what applies to regular filesystems naturally applies to filesystems on CF-disks. A few notes on maintenance that are CF specific follow. 7.1 Dumping filesystems Commonly one will create a image file from a CF-disk once it's all set this can simply be done by dumping it with dd. rtl4: # dd if=/dev/sda of=system.img To install the image on a new identical medium you simply turn it around. rtl4: # dd if=system.img of=/dev/sda (or what ever device your CF is at) the problem that commonly arises is that one has a medium from one vendor and needs to put it on a medium from a different vendor that has different CHS values or a different size. In that case the dd will not due - even if it may complete without any error it will not boot ! The way to move things to a new medium is to set up the new medium with fdisk format the new medium and COPY the files to the new medium from the loop mounted image. But you can't loop-mount the above system.img as this is not a filesystem image but a device image. You need to dump the filesystem so: rtl4: # dd if=/dev/sda1 of=system_sda1.img Even if sda1 covers the entire device - the images are not the same. So first lets check that the necessary devices are in the kernel that is the devices for the loop device and the filesystem (msdos in this case) rtl4: # cat /proc/devices ... Block devices: 2 fd 3 ide0 7 loop rtl4: # cat /proc/filesystems ... nodev pipefs ext2 minix msdos That looks OK - so the next step is to create a partition just like you would with a regular hard-disk. rtl4: # fdisk /dev/sda create one partition, change it to type FAT12 and mark it bootable. the final p(rint) command should show you something like. Command (m for help): p Disk /dev/sda: 2 heads, 32 sectors, 245 cylinders Units = cylinders of 64 * 512 bytes Device Boot Start End Blocks Id System /dev/sda1 * 1 244 7807+ 1 FAT12 Command (m for help): q rtl4: # mformat f: rtl4: # mkdir /mnt/loop rtl4: # syslinux /dev/sda1 rtl4: # cd /tmp rtl4:/tmp # dd if=/dev/sda of=system.img 15680+0 records in 15680+0 records out rtl4:/tmp # dd if=/dev/sda1 of=system_sda1.img 15614+0 records in 15614+0 records out rtl4:/tmp # ls -l system.img system_sda1.img -rw-r--r-- 1 root root 8028160 Apr 6 13:30 system.img -rw-r--r-- 1 root root 7994368 Apr 6 13:31 system_sda1.img rtl4:/tmp # file system.img system_sda1.img system.img: x86 boot sector system_sda1.img: x86 boot sector, system SYSLINUX, FAT (12 bit) Comparing the image sizes of the device /dev/sda and the filesystem dumped from /dev/sda1 the difference is obvious. and the loop mount will fail on the system.img but work on system_sda1.img as only the second is a filesystem. So if we had dumped a fully configured filesystem from /dev/sda1 to system_sda1.img then we could copy it to the new media even if the size and CHS values due not match. first we loop mount the file that contains the filesystem image and then the new medium A note on the mformat command - you need to edit /etc/mtools.conf and let "derive-f" point to the right device. ---/etc/mtools.conf--- ... drive f: file="/dev/sda1" You might also ask "why use mtools - mkfs.msdos is available on the system" the simple answer is "mkfs.msdos doesn't work", the more detailed answer is that mkfs.msdos gets the boot-sector correct in some cases but not in all if you are interested in what is going wrong then mkfs.msdos/syslinux a CF-disk partition and dump the MBR and compare it with mformat/syslinux generated MBR - they not only differ - but the order of files looks very funny on the mkfs.msdos/syslinux fs. ..and mkdosfs is normaly a symlink to mkfs.msdos, so - No - that is no better. rtl4: # mformat f: rtl4: # mount -t msdos -o loop system_sda1.img /mnt/loop rtl4: # mount -t msdos /dev/sda1 /mnt/ide-cf rtl4: # cp -pRd /mnt/loop/* /mnt/ide-cf And then run the necessary bootloader command for the new medium. so in the case of a msdos-fs based boot-medium you would remove the old ldlinux.sys and run syslinux on the device. rtl4: # rm /mnt/ide-cf/ldlinux.sys rtl4: # umount /mnt/ide-cf rtl4: # syslinux /dev/sda1 That will reinstall a ldlinux.sys on the CF. An outline of the boot-loader setup can be found in 6.1/6.2 above. 7.2 Updating filesystems If you update a filesystem on CF in a running system and this system is not easily accessible (because it's in the middle of the desert of New Mexico where nobody lives) you need to be a bit carful. The way to do it safely, assuming that the boot-medium is not mounted at runtime, is to mount the filesystem, copy the files, umount it, and fsck the unmounted filesystem (if you are not using msdos). I would not recommend updating filesystems by dd'ing an image to the CF, this is slow (in case of power-fail the system is probably lost) and hard to check if the systems boot-loader is still valid - or you need to have the boot-loader program on the target system, which is a wast of scarce disk-space. 8. Supported Hardware This list is almost empty - if you have any other devices you know to work - let me know. Pleas include any infos on configuration and operation if they don't fit the description here. If you are looking for CF-readers/writers and adapters - check at http://www.compactflash.org/guide/guide.htm for links to vendors (but that should not mean that all those devices are known to work with Linux !!!). 8.1 Devices known to work USB: Sandisk SDDR-31 PCMCIA: Pretec Copact Adapter (most PCMCIA-CF adapters should work as CF-Cards fulfill the PCMCIA specs and thus the adapters more or less are only convectors) List of Linux supported PCMCIA controlers (from the PCMCIA-HOWTO) o Cirrus Logic PD6710, PD6720, PD6722, PD6729, PD6730, PD6732, PD6832 o Intel i82365sl B, C, and DF steps, 82092AA o O2Micro OZ6729, OZ6730, OZ6832, OZ6833, OZ6836, OZ6860, OZ6812 o Omega Micro 82C365G, 82C092G o Ricoh RF5C296, RF5C396, RL5C465, RL5C466, RL5C475, RL5C476, RL5C478 o SMC 34C90 o Texas Instruments PCI1130, PCI1131, PCI1210, PCI1220, PCI1221, PCI1225, PCI1250A, PCI1251A, PCI1251B, PCI1450 o Toshiba ToPIC95, ToPIC97 (experimental, incomplete) o Vadem VG465, VG468, VG469 o VLSI Technologies 82C146, VCF94365 o VIA VT83C469 o Databook DB86082, DB86082A, DB86084, DB86084A, DB86072, DB86082B (if uncirtain - check the PCMCIA-HOWTO and the pcmcia user mailing list) Direct IDE-connectors (any will work no logic on these things) DSP Design (www.dspdesign.com) Advantech (www.advantech.de) 8.2 Devices known NOT to work USB: Kingston PCREAD-USB/CF (at least I did not get it to work) 9. FAQs/Wish list No FAQ's yet - send me any questions you might have so this section can come to life. My wish list: * Comments on PCMCIA-CF experience would be most appreciated * Also a note on PCI/ISA PCMCIA adapters with respect to CF adapters plugged in would be helpful * additional USB devices you have working 10. Credits * The LILO setup is mostly stolen from the BootDisk-HOwTO copywrited by Tom Fawcett and Graham Chapman. 11. Appendix A - CF Technology 11.1 General technical Information about Compact Flash (consider this a plug) CompactFlash(TM) is a removable solid-state mass storage device. First introduced in 1994 by SanDisk Corporation, CF(TM) cards weigh a half ounce and are the size of a matchbook. They provide complete PCMCIA-ATA functionality and compatibility plus TrueIDE functionality compatible with ATA/ATAPI-4. At 43mm (1.7") x 36mm (1.4") x 3.3mm (0.13"), the device's thickness is less than one-half of a current PCMCIA Type II card. CF cards have 50 pins conforming to PCMCIA ATA specs. CompactFlash cards are designed with flash technology, a non-volatile storage solution that does not require a battery to retain data indefinitely. CompactFlash storage products are solid state, meaning they contain no moving parts. CF cards consume as little as five percent of the power required by small disk drives. Dual 3.3V & 5V Operation - CF and CompactFlash cards support both 3.3V and 5V operation and can be interchanged between 3.3V and 5V systems. This means that any CF card can operate at either voltage. Other small form factor flash cards may be available to operate at 3.3V or 5V, but any single card can operate at only one of the voltages Connector - The connector used with CompactFlash is similar to the PCMCIA Card connector, but with 50 pins. This 50 pin connector has shown to be quite robust even if frequently removed (but the sockets are not always that robust...) Shock - CF cards have an operating shock rating of 2,000 Gs, which is equivalent to a 10-foot drop. With typical usage, a CF card can be used for more than 100 years with no loss or deterioration of data. (what ever typical usage in this context is... take this as CF being quite reliable) Power - Typically consuming less than five percent of the power than that required to operate 1.8" and 2.5" disk drives, CF cards run at 3.3V or 5V with a single power supply. This makes them ideal for a range of current and next-generation, small-form factor consumer applications. Data Reliability - CompactFlash data is protected by built-in dynamic defect management and error correction technologies. 11.2 Performance TODO: bandwidth of real setups. 12. Appendix B - Resource Links mtools: most distributions have the mtools package included - so you can probably grab it off the next university ftp-server. but for completeness : http://mtools.linux.lu/ syslinux: most if not all distros have syslinux on it - the home-page is at http://syslinux.zytor.com/ minirtl: This is a floopy system that is based on a msdos-boot medium it can be transfered to CF with the procedure described here so if you don't want to build the filesystem from scratch you can use these images. http://www.thinkingnerds.com/projects/minirtl/minirtl.htmla Bootdisk-HOWTO: for further infos on setting up a small root-filesystem and the boot-loader configuration on floppies - but most of that is directly applicable to a CF-disk setup as well. The Bootdisk-HOWTO can be found at any HOWTO mirror site and is included on all main-stream Linux distributions. LILO: The LILO User Manual and the LILO tech manual - This document also contains an in depth description of how MBR's and Boot-sectors are structured. It also is a valuable help of sources if your attempt to boot with lilo ends with "L 01 01 01" or the like Grub: The BRUB Manual can be found at ftp.gnu.org, for details of setting up grub and trouble shooting CF-specs: For a copy of the CF specifications check at http://www.compactflash.org/specdl1.htm PCMCIA-HOWTO: Part of most (if not all) GNU/Linux distributions for the lates version check at: pcmcia-cs.sourceforge.net/ftp/doc/PCMCIA-HOWTO.html