Background:

u-boot uImage files have a 64-byte header defined in image.h as follows:

#define IH_MAGIC    0x27051956    /* Image Magic Number     */
#define IH_NMLEN    32            /* Image Name Length      */

typedef struct image_header {
    uint32_t    ih_magic;         /* Image Header Magic Number */
    uint32_t    ih_hcrc;          /* Image Header CRC Checksum */
    uint32_t    ih_time;          /* Image Creation Timestamp  */
    uint32_t    ih_size;          /* Image Data Size           */
    uint32_t    ih_load;          /* Data     Load  Address    */
    uint32_t    ih_ep;            /* Entry Point Address       */
    uint32_t    ih_dcrc;          /* Image Data CRC Checksum   */
    uint8_t     ih_os;            /* Operating System          */
    uint8_t     ih_arch;          /* CPU architecture          */
    uint8_t     ih_type;          /* Image Type                */
    uint8_t     ih_comp;          /* Compression Type          */
    uint8_t     ih_name[IH_NMLEN];    /* Image Name            */
} image_header_t;

According to the u-boot README in the section “More About U-Boot Image Types”:

“Multi-File Images” start with a list of image sizes, each
image size (in bytes) specified by an “uint32_t” in network
byte order. This list is terminated by an “(uint32_t)0”.
Immediately after the terminating 0 follow the images, one by
one, all aligned on “uint32_t” boundaries (size rounded up to
a multiple of 4 bytes).

 

Install uboot-mkimage from ports:

$ cd /usr/ports/devel/u-boot
$ make install clean

List image header:

$ mkimage -l nova-installer-image-broadway.uImage
Image Name:   nova-installer-image-broadway-43
Created:      Wed Dec 31 16:00:00 1969
Image Type:   ARM Linux Multi-File Image (uncompressed)
Data Size:    12566392 Bytes = 12271.87 kB = 11.98 MB
Load Address: 0x00000000
Entry Point:  0x00000000
Contents:
   Image 0:  2610004 Bytes = 2548 kB = 2 MB
   Image 1:  9956376 Bytes = 9723 kB = 9 MB

This image contains two files, so it is a multi-file image.  To extract the two child image files, we must first chop off or skip over the 64-byte header + 4-byte image 0 size + 4 byte image 1 size + 4 byte null terminator = first 76 bytes.  Next we’ll extract Image 0  (2610004 bytes long in this example) and image 1 (9956376 bytes long in this example).  Note that these two files are also uImage files!

Skip first 76 bytes and extract length of first image:

$ dd if=nova-installer-image-broadway.uImage of=kernel.uImage bs=1 skip=76 count=2610004
2610004+0 records in
2610004+0 records out
2610004 bytes transferred in 46.503855 secs (56124 bytes/sec)

Now I’ll skip 76 bytes + the size of the first image to get the second image:

$ dd if=nova-installer-image-broadway.uImage of=ramdisk.uImage bs=1 skip=2610080
9956376+0 records in
9956376+0 records out
9956376 bytes transferred in 168.836628 secs (58970 bytes/sec)

Let’s look at the kernel image header:

$ mkimage -l kernel.uImage
Image Name:   Linux-2.6.29-palm-shank
Created:      Wed Dec 31 16:00:00 1969
Image Type:   ARM Linux Kernel Image (uncompressed)
Data Size:    2609940 Bytes = 2548.77 kB = 2.49 MB
Load Address: 0x00208000
Entry Point:  0x00208000

And the ramdisk image header:

$ mkimage -l ramdisk.uImage
Image Name:   ramdisk
Created:      Wed Dec 31 16:00:00 1969
Image Type:   ARM Linux RAMDisk Image (uncompressed)
Data Size:    9956312 Bytes = 9722.96 kB = 9.50 MB
Load Address: 0x00000000
Entry Point:  0x00000000

Now let’s pluck off the 64-byte header from the ramdisk:

$ dd if=ramdisk.uImage of=ramdisk bs=64 skip=1
155567+1 records in
155567+1 records out
9956312 bytes transferred in 2.952196 secs (3372511 bytes/sec)

And examine it:

$ file ramdisk
ramdisk: gzip compressed data, was "nova-installer-image-broadway-4", from Unix, last modified: Fri Apr 15 12:01:11 2011, max compression

Now extract it:

 zcat ramdisk > nova-installer-image-broadway-4

And examine it again:

$ file nova-installer-image-broadway-4
nova-installer-image-broadway-4: Linux rev 0.0 ext2 filesystem data

So it’s an ext2 filesystem.  Let’s mount it under FreeBSD:

$ kldload ext2fs
$ mdconfig -a -t vnode -f nova-installer-image-broadway-4
md0
$ mount -t ext2fs /dev/md0 /mnt

Let’s add a file full of random garbage just for fun:

$ dd if=/dev/random of=/mnt/garbage bs=1M count=1
1+0 records in
1+0 records out
1048576 bytes transferred in 0.237938 secs (4406931 bytes/sec)
$ ls /mnt
bin        dev        garbage    lib        media      opt        sbin       tmp        var
boot       etc        home       md5sums.gz mnt        proc       sys        usr

Now it’s time to unmount the file and package everything back together:

$ umount /mnt
$ mdconfig -d -u 0

Don’t forget to gzip the ramdisk image…

$ gzip nova-installer-image-broadway-4

First create the ramdisk uImage:

$ mkimage -A arm -T ramdisk -C none -n ramdisk -d nova-installer-image-broadway-4.gz ramdisk.uImage
Image Name:   ramdisk
Created:      Wed Jun 20 23:34:59 2012
Image Type:   ARM Linux RAMDisk Image (uncompressed)
Data Size:    11036471 Bytes = 10777.80 kB = 10.53 MB
Load Address: 0x00000000
Entry Point:  0x00000000

Now combine the kernel image and ramdisk image into the final one:

$ mkimage -A arm -T multi -C none -n Linux-2.6.29-palm-shank -d kernel.uImage:ramdisk.uImage nova-installer-image-broadway.uImage
Image Name:   Linux-2.6.29-palm-shank
Created:      Wed Jun 20 23:40:05 2012
Image Type:   ARM Linux Multi-File Image (uncompressed)
Data Size:    13646551 Bytes = 13326.71 kB = 13.01 MB
Load Address: 0x00000000
Entry Point:  0x00000000
Contents:
   Image 0:  2610004 Bytes = 2548 kB = 2 MB
   Image 1: 11036535 Bytes = 10777 kB = 10 MB

Note how the overall image size and image 1 size are 1MB larger than the original from the beginning.

 

Now let’s test it with novacom.  Restart the phone and hold the volume-up key to enter bootie the bootloader.  now:

novacom boot mem:// < nova-installer-image-broadway.uImage

 

Wait a few seconds, then launch novaterm and verify that we booted to the new ramdisk with the 1M garbage file: