In my recent attempt to run Meego on the HP touchpad I needed to see how Cyanogen Mod's installer works.

The way it works is that you make you touchpad boot on a custom uImage they provide. This custom uImage is a multi-image uImage containing both the kernel and an initrd.

What I wanted to do is extract the initrd and customize it to fit me needs.

The thing is that at the moment the source for this initrd (and the script it contains) are not available. So here is how I extracted the thing.

First of all we need information on the layout of the uImage. To do that let's run :

 % mkimage -l ACMEInstaller                                                                                                                                                                   
 Image Name:   test-multi-image
 Created:      Sun Oct 16 21:29:20 2011
 Image Type:   ARM Linux Multi-File Image (uncompressed)
 Data Size:    9084743 Bytes = 8871.82 kB = 8.66 MB
 Load Address: 00000000
 Entry Point:  00000000
 Contents:
    Image 0: 3808324 Bytes = 3719.07 kB = 3.63 MB
    Image 1: 5276407 Bytes = 5152.74 kB = 5.03 MB

Ok what we get from that is that this image contains image0 and image1 so how do we extract them ?

First off let's have a look at the strcture of an uimage file here

Here's the important part :

"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 - except for the last file).

The structure is basically this one :

[uImage hdr (64 bytes)][image0 size(4bytes)][image1 size(4 bytes)][(uint32_t)0(4 bytes)]

As we can see in the file, the header is 7x4 + 4 + 32 = 64 bytes We then need to add the 2 image sizes + the ending (uint32_t)0 which make up 12 bytes and we get a grand total of 76 bytes. If we had had 3 images packed in the image it would have been 80 bytes, you get the logic.

So to get only the 2 images without the header we do :

dd if=ACMEInstaller of=ACMEImages ibs=1 skip=76

This gives us a file with the 2 images, how do we separate them now ? That's the easy part : mkimage -l gave us the size of each image so to get to each one :

dd if=ACMEImages of=ACMEzImage ibs=1 count=3808324
dd if=ACMEImages of=ACMEinitrd ibs=1 skip=3808324

Now we have our 2 images but as you can see if you do a

file ACMEinitrd

it is still recognized as an uImage (this might be specific to the acme uImage which is a multi-image file containing a kernel uimage and an initrd uimage). This is because each image in the initial uImage is also a uImage so to get to the raw data we need to strip the header. The normal header of a uImage is 64 bytes long so here we go :

 dd if=ACMEinitrd of=ACMEinitrd-real ibs=1 skip=64

To confirm that we have the raw data :

% file ACMEInitrd-real                                                                                                                                                                      
ACMEInitrd-real: Linux rev 0.0 ext2 filesystem data (mounted or unclean), UUID=975370b5-4647-4fb7-bdd2-3d8a9bd2486d

Now we just need to mount it and have fun.