uClinux flash device mini howto ******************************* Author: Bernhard Kuhn, Lineo Inc. Revision: 0.1 Abstract: This document describes how to set up the Motorola M5272C3 evaluation board 'Tarifa' to boot from flash and how to boot from a cramfs partition instead of an kernel-attached romfs image. This paper presumes that you already know how to boot Linux on Tarifa from RAM with an romfs image as root filesystem attached to the kernel image. Content: o Choosing a bootloader o The Flash Device Partition layout o Installing Colilo o Attaching the Linux-Image to Colilo, saving flash memory o Other Boot strategies o Generating a cramfs images o Creating an empty romfs image o Creating a compressed kernel for flashing o System recovery using the BDM interface cable o Unresoled Issues o List of Resources o (No) Warranty o Thanks Choosing a bootloader ===================== The Tarifa board (Motorola M5272C3 evaluation board) is shipped with a pre-installed bootloader called "dBUG". This bootloader allows the user to download images from a tftp server to memory (RAM) starting at 0x20000 (refer to the "dn" command in the dBUG manual) and to execute the kernel from there ("go 20000"). Additionaly, downloaded images can be moved to flash memory (7 x 256KB starting at 0xffe40000, see "upuser" in the Tarifa/dBUG manual). Those who don't want to remove the pre-installed bootloader can choose to install a bootloader-kernel-rootfs combination in the topmost one megabyte (0xfff00000 to 0xffffffff) of the flash device and after altering jumper 13 to position 2-3, the M5272C3 boots from there (but this option limits the available amount of flash memory to only one megabyte: the area from 0xffe00000 to 0xffeffffff is just a mirror of the topmost one megabyte in this mode). As dBUG (as pre-installed) cannot be configured to automatically start the kernel, you will have to install another bootloader to have a kernel-kickstarter and in order to make fully use of the two megabytes of flash memory the Tarifa board provides. The bootloader prefered in this document is called "Colilo" and is available under the terms of the GPL. Unfortnuatly, Colilo is not able to load images via the tftp mechanism, so dBUG is probably the better choice during development. For the first steps, you might want to have dBUG booted by default (which is located at the first 256KB of the flash memory from 0xffe00000 to 0xffe3ffff) and invoke colilo (that resides at the first 256KB of the topmost one megabyte from 0xfff00000 to 0xfff3ffff) by typing "go fff00400". So switching jumper 13 allows you to either choose booting from dBUG (and subsequently starting colilo) or colilo directly. The Flash Device Partition layout ================================= The uClinux-distribution (as is) from www.uclinux.org makes use of the block memory device driver (linux/drivers/block/blkmem.c). This driver already provides flashing algorithms that allows the user to write to a broad range of flash device (refer to blkmem.c, and the flashw/netflash utilities in the uClinux-distribution user tree for more information on that topic). But the Memory Technology Device drivers (linux/drivers/mtd) are offering more options and probably will be the better supported drivers for flash devices in the future. This paper concentrates on MTD. In this context, please note that the journaling flash file system (jffs) apparently does only work in combination with MTD drivers, but not with the blkmem driver. The standard uClinux-2.4.x kernel (CVS version) can be compiled that way that it recognises the 2 MByte flash on the Tarifa board using the "physmap" driver (start=0xffe0000, size=0x200000, buswidth=2). But in this case, there is only one big 2MB partition. This would make the process of flashing the bootloader, kernel and rootfs seperatly more complex. For this reason, i have introduces a dedicated mapping driver for the Tarifa board [TARIFAMAP]. BTW.: generating a mapping device driver file is rather easy: just copy "physmap.c", add the partition table and replace the add_mtd_device() call in init_physmap() by an apropriate add_mtd_partitions()-call (compare physmap.c and tarifa.c for details). Here is the list of the pre-defined partitions: mtd0 / rom0: 0xffe00000-0xffe03fff : "boot (16K)" mtd2 / rom1: 0xffe80000-0xffefffff : "kernel (512K)" mtd4 / rom2: 0xfff00000-0xffffffff : "rootfs (1024K)" mtd6 / rom3: 0xffe04000-0xffe05fff : "spare (8K)" mtd8 / rom4: 0xffe06000-0xffe07fff : "spare (8K)" mtd10 / rom5: 0xffe40000-0xffe7ffff : "spare (256K)" mtd12 / rom6: 0xffe00000-0xffffffff : "complete (2048K)" mtd14 / rom7: 0xfff00000-0xfff3ffff : "boot J13 (256K)" mtd16 / rom8: 0xfff40000-0xfffbffff : "kernel J13 (512K)" mtd18 / rom9: 0xfffc0000-0xffffffff : "rootfs J13 (256K)" First of all, you may have recognized that the minor numbers for the MTD character device files (major 90) do not correspond to those of the mtdblock device files (major 31, also known as /dev/rom*) for a reason i don't know - maybe you can tell me :-) Additionaly, the mapping looks a little bit fragmented. This is due to the fact that the first 256KB memory block on the flash device of the Tarifa board is fragmented in in smaller eraseable flash blocks for bootloaders and configuration space. BTW.: the 224KByte from 0xffe08000 to 0xfffe3ffff is not directly mappable (the MTD driver will complain that the mapping is not block aligned), but can be accessed via mtd12/rom6, if necessary. mtd14, mtd16 and mtd18 are only necessary when playing around with jumper 13: if you are just using the topmost one megabyte of the flash, then you don't have the need to delete the pre-installed dBUG bootloader (if you don't have a BDM interface cable, this might be the best option for you, since otherwise you probably cannot restore a working bootloader once you have accidently flashed a non-working bootloader, kernel or root filesystem). Attention: overwritting flash partitions that already contain data doesn't work. You will have to check out the "erase [] []" command (loacted in mtd/utils) from [MTDUTILS] (or just download a recent version of erase.c from [ERASESRC]). Cross-compile erase.c manualy by typing somewhat like # m68k-elf-gcc -m5200 -O2 -D__linux__ -D__uClinux__ -D__ELF__ -DNO_MM \ -o erase erase.c -Wl,-elf2flt,"-T /opt/uClinux/m68k-elf/lib/elf2flt.ld" -lc Alternatively, you can download an executable FLAT file for tarifa from [ERASECMD]. Copy the binary into your romfs/bin directory. It is a little bit confusing that if you are accessing the flash via /dev/mtd12, then you have eight blocks of 256KB each, instead of the fragmented layout decribed above. So to erase the flash device completly, you have to type # erase /dev/mtd12 0 8 (8 Blocks of 256KB each, staring at Block 0) Installing Colilo ================= Ensure that you have a m68k-elf-toolchain installed on your host system. Then download Colilo from [COLILOSRC] and patch it [COLILOPATCH] in order to compile Colilo bootable from the topmost one megabyte by uncommenting "TOP1MB = y" in the Makefile (this is the recommended first step before overwritting the pre-installed dBUG bootloader). The patch is also necessary if you like to have Colilo located in the lower one megabyte, because the unpatched version would search the (compressed) image at 0xffe20000, while the pre-defined kernel partition starts at 0xffe40000 according to the partition layout descibed above - flash partitions always have to be flash erase block aligned! If you don't use the RPMs provided at [M68KRPMS] for the compiler toolchain, then you also have to modifiy the entries CF_ROOT and GCC_EXEC_PREFIX. Additonaly, ensure that the option "CONFIG_M5272C3 = 1" is uncommented. You also my like to uncomment "BOOTDEBUG = 1" to get some serial output from Colilo during the boot process. Additionaly, you may like to uncomment "CONFIG_UI = 1". This will provide you with a simple command line tool (but then, you are probably better off with dBUG). As the (lower) bootloader partition is only 16 KByte in size, you cannot flash Colilo to /dev/mtd0 if it is bigger than that - in this case, use /dev/mtd12 instead, but be aware that you might not be able to use /dev/rom1 to /dev/rom2 any more, because these partitions are overlapping with the installed bootloader. These issues certainly don't arrise when using the 256KB bootloader partition on the topmost one megabyte ([COLILOIMAGEUI]). Now, just type "make" and you should optain a file named "colilo.bin". Build a kernel+romfs that includes MTD support. MTD has to be without caching or read only block device support compiled in, or there will be conflicts with the blockmem device driver which uses the same major number. Ensure that you have direct character MTD support enabled in order to access the flash partitions anyhow. Before building the kernel, patch it in order to the flash partitions described above in this document. BTW.: don't forget to have MTD partitioning support, the CFI driver, the command set for for AMD CFI flash devices and the mapping driver for the Tarifa board enabled. If you are now a little bit confused about which kernel configuration options have to be enabled, then you can find an example .config file at [CONFROMFS]. Alternativly, download a precompiled image from [ROMFSIMAGE]. After downloading the image (kernel+romfs) to the target RAM (via dBUG) and executing it from there as usual ("go 20000") the system should start from the kernel-attached root filesystem (romfs). After configuring the network and nfs-mounting the directory where the precompiled colilo.bin resides, you can move colilo.bin to it's destination partition (/dev/mtd*) on the flash device using the command "dd" (i.e. dd if=colilo.bin of=/dev/mtd14) In case you didn't already generated the mtd character device files in your romfs/dev directory (with i.e. touch "@mtd0,c,90,0"), you can temporarily generate them, i.e. with "mknod /tmp/mtd0 c 90 0". Attaching the Linux-Image to Colilo, saving flash memory ======================================================== You can edit Colilo in main.c (look for "#define IMAGE_ADDR 0xffe80000" in line 172) so that it searches the (compressed) kernel at 0xffe04000, using all the "spare" partitions. In this case, you have to flash Colilo+Linux as a combined image to /dev/mtd12. Generate this combined image with the following command sequence: # BS=16 # alignement: 16 KByte # dd if=/dev/zero bs=1024 count=$BS of=null.bin # cat colilo.bin null.bin > colilo-null.bin # dd if=colilo-null.bin bs=1024 count=$BS of=colilo-aligned.bin # cat colilo-aligned.bin imagez.bin > imagez-moreflash.bin If colilo grows bigger than 16 KByte then adjust the "BS" value (i.e. to 32 KByte) and line 172 in main.c (i.e. #define IMAGE_ADDR 0xffe08000). On the target, delete the first 512 KB of flash memory and transfer the combined image (don't forget to setup the network and nfs-mount the directory where the images resides): # erase /dev/mtd12 0 2 # dd if=imagez-moreflash.bin of=/dev/mtd12 Now feel free to use the 512KB partition intended for the kernel (/dev/rom1) for other purposes. Other Boot strategies ===================== There are a lot of options on how to boot the kernel and on how to access to root filesystem. Among them, i have noted down a few with their pros and cons: 1) Booting from dBUG and loading kernel+romfs to RAM ---------------------------------------------------- This is probably the best boot method during development, because dBUG offers you to download the kernel+romfs via ethernet from a tftp server. Find an sample image at [ROMFSIMAGES] (unpack with bunzip2 before moving to /tftpboot) 2) Booting from Colilo and kernel+romfs decrompressed into RAM -------------------------------------------------------------- This variant is simple to handle, but the romfs is always decompressed to RAM. This may be critical if you have limited resources. 3) Booting from Colilo, kernel decrompessed into RAM and cramfs in ROM ---------------------------------------------------------------------- As flash devices are usualy more expensive than DRAM, it is a good idea to have the kernel stored compressed in the flash and decompressed by colilo into DRAM. Also, executing the kernel from the 32-bit wide DRAM is usualy faster than executing it from the 16-bit wide flash memory. Note: Having the cramfs in flash makes rootfs updates rather difficult, because when erasing the old cramfs (in order to flash the new one to the partition), the kernel may go crasy, because the rootfs was mounted at that time. I didn't yet worked out a strategy on how to update a cramfs in place. If you intend to have a simple flash update option, then you are probably better off with boot strategy 2). If you like, you can play arround with pre-compiled images downloadable from [CRAMFSIMAGES]. 4) Booting from Colilo, kernel executed from ROM and cramfs in ROM ----------------------------------------------------------------- Although it is IMHO better to have the kernel decompressed to RAM, you may like to run the kernel from ROM. To archive this capability, you will have to patch the kernel [ROMEXEC] and compile it with the option "(ROM) kernel executes from". Please note, that this patch currently only works with dBUG ("upuser" and "go ffe40400"). To be able to automatically boot the kernel from ROM, either colilo has to be adapted a little bit (just jump to 0xffe40400 after controller initialisation), or you could forget that bootloader at all and initialize the controller in the file crt0_rom.S of the kernel (would be pretty easy, but was not yet done). BTW: If you are using an attached romfs instead of a seperate cramfs partition, then even the user space binaries are executable in place (XIP) thanks to the FLAT binaries. Note: Having the kernel booted from ROM makes it even harder to do remote updates, because deleting the flash partition while the kernel is running from there will lead you into serious trouble :-) 5) Using Jumper 13: options 2)-4) in topmost 1 MByte of ROM ----------------------------------------------------------- If you don't wan't to delete dBUG, then you can also boot from the topmost 1MB of the flash by setting jumper 13 to position 2-3, or by typing "go fff00400" after booting from dBUG (jumper 13 set to 1-2). Have a look at [CRAMFSIMAGES1MB] for example images (use default cramfs images). Generating a cramfs images ========================== In order to generate a big endian cramfs on an little endian host, you have to patch mkcramfs.c (to be found in i.e. linux-2.4.x/scripts/cramfs). A recent patch against a recent mkcramfs.c [MKCRAMSRC] can be found at [MKCRAMPATCH]. Patch and compile the sources for the host: # patch mkcramfs-2.4.12.c < mkcramfs-2.4.12-endianessaware.c.patch # gcc -O2 -o mkcramfs mkcramfs-2.4.12.c -lz # cp mkcramfs /usr/local/bin # chmod a+x /usr/local/bin Now generate a romfs directory as usaly. If you have done that from within the uClinux-distribution, then the device files "@*" in the /dev directory won't be suitable. You will either have to regenerate them as real device nodes manualy (with "mknod"), or you can use a simple shell script [CONVDEVNODES] that does the some job automatically (just execute it in within the romfs/dev directory. You will have to be root to do so). Now generate the cramfs image by typing: # mkcramfs -Nb romfs cramfs.img This image can then be transfered to the flash partition with the "dd" command: boot the target with the "romfs-version" described above, setup the network, nfs-mount to directory where the cramfs image resides and type something like "dd if=cramfs.img of=/dev/mtd18". Don't forget to erase the partition before flashing. Creating an empty romfs image ============================= Usualy, an romfs image is attached to the kernel image. When using a root filesystem ontop of a cramfs in within an flash partition, then you certainly don't need to wast flash memory by attaching a romfs full of binaries and data to the kernel. But the problem is that crt0_ram.S for Coldfire always tries to relocate an attached romfs after the .bss section. So the kernel very likly crashes if no romfs is attached at all (because it reads some nonsens romfs image size information and tries to relocate megabytes of a non-existent romfs image). The solution is to just use a very small pseude-romfs image file [EMPTYROMFS] (16 Bytes in size) generated from a simple shell script [MKEMPTYROMFS]. Creating a compressed kernel for flashing ========================================= If you are using the uClinux-distribution from uclinux.org, then just replace "romfs.img" in the "images" directory with the empty romfs image described above and type "make image" in the top level directory of the distribution. Alternativly, you can create the image manualy with the following complex command sequence (in case you have set up your own build environement): ADDR=`m68k-elf-objdump --headers $LINUXKERNEL_ELF | \ grep .init | cut -d' ' -f 13,15 | xargs printf "0x%s 0x%s\n" | \ xargs printf "%d + %d\n" |xargs expr |xargs printf "0x%x\n"`;\ m68k-elf-objcopy --add-section=.romfs=$ROMFS_IMG \ --adjust-section-vma=.romfs=$${ADDR} --no-adjust-warnings \ --set-section-flags=.romfs=alloc,load,data \ $LINUXKERNEL_ELF $IMAGE_ELF 2> /dev/null m68k-elf-objcopy -O binary $LINUXKERNEL_ELF $LINUXKERNEL_BIN cat $LINUXKERNEL_BIN $ROMFS_IMG > $IMAGE_BIN ../uClinux-distribution/tools/cksum -b -o 2 $IMAGE_BIN >> $IMAGE_BIN gzip -c -9 $IMAGE_BIN > $IMAGEZ_BIN ../uClinux-distribution/tools/cksum -b -o 2 $IMAGEZ_BIN >> $IMAGEZ_BIN You then can flash the compressed kernel (plus empty romfs image) with i.e. "dd if=imagez.bin of=/dev/mtd16". Don't forget to have the mtdblock device driver enabled but the blkmem device driver disabled. [CONFCRAMFS] gives you an example for a convenient kernel .config file. Also, don't forget to change the root device accordingly to where you have stored the cramfs image: invoke the kernel configuration tool (i.e. "make menuconfig") and change "Processor type and features ---> Kernel Boot Parameter" to i.e. "CONSOLE=/dev/ttyS0,19200 root=1f09" in case you have transfered the cramfs image to /dev/mtd18 (/dev/rom9). System recovery using the BDM interface cable ============================================= If you have accidently damaged the bootloader on the flash, or the newly flashed kernel (or the cramfs image) doesn't work as expected and you can't re-flash the system from dBUG or a properly running linux system any more, then you have to recover the bootloader, the kernel or the cramfs using an BDM interface cable: First, generate a RAM-kernel with MTD support and an attached romfs to boot from (described somewhere above) Ensure that the kernel comes along without MTD block device interface, not to interfere with the blkmem device for the romfs - but ensure that you have direct character flash device access compiled in. Alternativly, you may use flashw/netflash in combination with the block memory device driver - but in this case you will have to add some partition information in blkmem.c manualy. Another alternative is to download a pre-compiled ELF file from [ROMFSIMAGEELF]. With this image, you can again access all flash partitions. If Colilo is ok, but the kernel doesn't boot properly, the DRAM (where to download kernel+romfs) was correctly initialised after power up and you can begin downloading the ELF file to the target using the BDM interface cable: m68k-bdm-elf-gdb image.elf [...] (gdb) target bdm /dev/bdmcf0 (gdb) load (gdb) set $pc=0x20000 (gdb) c If the bootloader is broken and the DRAM was not properly initialised during power on, then you first have to execute a simple memory initialisation program ([DRAMINIT],[DRAMINITELF]) using the builtin 4KB SRAM before you can download and execute your kernel from DRAM. m68k-bdm-elf-gdb image.elf [...] (gdb) target bdm /dev/bdmcf0 (gdb) set $rambar = 0x20000001 (gdb) set $mbar = 0x10000001 (gdb) load boot.elf (gdb) set $pc=0x20000400 (gdb) c [...] (gdb) load (gdb) set $pc=0x20000 (gdb) c Please note, that this rescue procedure usualy doesn't work out of the box! I always had to bother arround loading the draminit routing, the kernel+romfs image and the draminit routine again several times until the kernel was pleased enough to start. YMMV Unresoled Issues ================ o minor numbers for MTD character device drivers don't match those tolled in /proc/mtd (but those of the MTD block device driver do) o I didn't got jffs working conveniently: the kernel crashes after writing something to the partition. (the Partition was erased before mounting with "-t jffs"). List of Resources ================= [TARIFAMAP] Mapping driver for M5272C3 http://www.rcs.ei.tum.de/~kuhn/uclinux/coldfire/tarifa/20011119/kernel/patches/uClinux-2.4.x-M5272C3-MTDpartitions.patch [MTDUTILS] MTD sources and utilities (CVS) http://www.linux-mtd.infradead.org [ERASECMD] erase executable for MCF5272 http://www.rcs.ei.tum.de/~kuhn/uclinux/coldfire/tarifa/20011119/mtd-erase/bin/erase [ERASESRC] erase sources for MTD http://www.rcs.ei.tum.de/~kuhn/uclinux/coldfire/tarifa/20011119/mtd-erase/erase.c [COLILOSRC] Colilo sources mirrored snapshot from 20011106 http://www.rcs.ei.tum.de/~kuhn/uclinux/coldfire/tarifa/20011119/colilo/colilo-20011106.tar.gz [COLILOPATCH] Patch to search (compressed) image at 0xffe40000/0xfff40000 http://www.rcs.ei.tum.de/~kuhn/uclinux/coldfire/tarifa/20011119/colilo/colilo-20011106-tarifa.patch [M68KRPMS] m68k-elf-toolchain RPMs for RedHat 6.2 (x86) http://www.rcs.ei.tum.de/~kuhn/uclinux/uClinux-m68k-elf-toolchain/20010718/RPMS [CONFROMFS] kernel .config example for MTD support (using an attached romfs) http://www.rcs.ei.tum.de/~kuhn/uclinux/coldfire/tarifa/20011119/kernel/sample-config/config-romfs [ROMEXEC] Patch to run kernel in flash memory http://www.rcs.ei.tum.de/~kuhn/uclinux/coldfire/tarifa/20011119/kernel/patches/uClinux-2.4.x-M5272C3-bootfromrom.patch [MKCRAMSRC] Sources for mkcramfs (non-endianess aware) http://www.rcs.ei.tum.de/~kuhn/uclinux/coldfire/tarifa/20011119/mkcramfs/mkcramfs-2.4.12.c [MKCRAMPATCH] Patch to make mkcramfs endianess aware http://www.rcs.ei.tum.de/~kuhn/uclinux/coldfire/tarifa/20011119/mkcramfs/mkcramfs-2.4.12-endianessaware.c.patch [CONVDEVNODES] Script to convert bogus device files into real device files http://www.rcs.ei.tum.de/~kuhn/uclinux/coldfire/tarifa/20011119/utils/convdev.sh [EMPTYROMFS] Empty romfs image http://www.rcs.ei.tum.de/~kuhn/uclinux/coldfire/tarifa/20011119/emptyromfs/romfs.img [MKEMPTYROMFS] Script to generate an empty romfs image http://www.rcs.ei.tum.de/~kuhn/uclinux/coldfire/tarifa/20011119/emptyromfs/mkemptyromfs.sh [ROMFSIMAGES] Sample kernel+romfs with MTD driver for M5272C3 http://www.rcs.ei.tum.de/~kuhn/uclinux/coldfire/tarifa/20011119/images/boot_romfs/image.bin.bz2 [ROMFSIMAGEELF] Sample kernel+romfs with MTD driver for M5272C3, ELF version http://www.rcs.ei.tum.de/~kuhn/uclinux/coldfire/tarifa/20011119/images/boot_romfs/image.elf.bz2 [CRAMFSIMAGES] Some sample colilo, kernel and cramfs images for M5272C3 http://www.rcs.ei.tum.de/~kuhn/uclinux/coldfire/tarifa/20011119/images/boot_cramfs/default [CRAMFSIMAGES1MB] Some sample colilo, kernel and cramfs images for M5272C3 in topmost one megabyte http://www.rcs.ei.tum.de/~kuhn/uclinux/coldfire/tarifa/20011119/images/boot_cramfs/TOP1MB [DRAMINIT] Sources for initialising DRAM from SRAM http://www.rcs.ei.tum.de/~kuhn/uclinux/coldfire/tarifa/20011119/draminit/draminit-5272.tgz [DRAMINITELF] Binary for initialising DRAM from SRAM (use gdbinit.draminit) http://www.rcs.ei.tum.de/~kuhn/uclinux/coldfire/tarifa/20011119/draminit/tarifa.elf (NO) Warranty ============= I certainly cannot provide any warranty. However this document was put together with best intensions, i cannot held responsible for any demage (physicaly or mentaly) that my result by following the instructions given above. Thanks ====== Many thanks to the developers at Snapgear, namely David McCullough and Greg Ungerer for providing the execelent uClinux-Distribution. Thanks are also certainly going to Travis Griggs from Key Technology Inc. for his version of Colilo for the M5272C3. Additionaly, I definitly have to thank Vipin Malik for providing the mtd-jffs-HOWTO, which was a good starting point for understanding how to handle MTD.