The O2 Joggler is a OpenPeak tablet only available on UK.
It's a very interesting one because it has a LAN connector and is configured to boot on any bootable USB drive connected.
I took me several months (yes, seriously, it was a nightmare to buy a cheap joggler from a seller who ship to France ) but I finally bought mine on eBay.

There is a very active community of hackers around the Joggler :
Wiki, forum.... I'm not starting from nothing with a very difficult system !

FYI, Orange, in France, followed the same concept to create its own "tabbee".
Unfortunately, it is not as easy as the O2 joggler to hack.

I have no longer interest on the Joggler, Android is not stable enough on this device, so don't expect more update.


Step 0: Find needed accessories

I need 2 things to experiment on Joggler

I found my PSU on ebay and by a PNY Attaché™ Evolutive 16Go (a MicroSD hidden in a USB connector)

Note after several months on use, I suspect the Attaché Evolutive to be bad product : I failed several times to dd, badblocks or copy file from it while it's possible when I move the MicroSD on a SD adapter.


Step 1: Boot on Android Froyo.

My major requirement was : Ethernet (no Wifi!), sound and less lag as possible.
From all the Android port available, I selected the Miyu 1.2.3 Android 2.2.2

1.2.4 hasn't sound support and I suspect ICS to be slow on Joggler.


I so downloaded the image available on the forum since it includes a lot of fixes on Miyu 1.2.3 (english, system time sync and market)

For a first try, follow the direction on the same wiki page (write the image to a 4Go+ USB flash drive)

My goal is to understand how it works, so let make it the hard way !

First problem, this image is a 4Go+ disk image, including 3 partitions.
These 3 partitions are

  1. Android : FAT16 partition which handle the boot and system
  2. data : EXT2 partition which handle the data (userdata.img on some other devices)
  3. sdcard: FAT16 partition which simulate the SD Card

I have 8Go so I decided to create the sdcard partition myself.
It's (a lot) easier to write the 4Go+ image to your USB drive then use gparted or fdisk to expand the last partition but I found it interesting to start from partition images.
To do this, I first had to extract them from the disk image, using their offsets.

Several tools exists (kpartx!!) but I want to do it with standard Linux tools : fdisk, dd (and mount)

fdisk -lu image.img
'l' list the partition
'u' ask to print sector info

      Device Boot      Start         End      Blocks   Id  System
  image.img1              63     1159167      579552+   b  W95 FAT32
  Partition 1 does not end on cylinder boundary.
  image.img2         1159168     3201023     1020928   83  Linux
  Partition 2 does not end on cylinder boundary.
  image3             3201024     7307263     2053120    b  W95 FAT32
  Partition 3 does not end on cylinder boundary.

if you have sfdisk, use
sfdisk -l -uS image.img

With the info we found, we can now extract partitions with:

dd if=image.img of=partition1.img skip=63 count=$[1159167-63+1]
dd if=image.img of=partition2.img skip=1159168 count=$[3201023-1159168+1]
dd if=image.img of=partition3.img skip=3201024 count=$[7307263-3201024+1]

You could skip the last one if you want to start from zero, but since it contains a lot of apk to use...

Let's mount them to check everything is alright

mkdir /mnt/android_part1
mkdir /mnt/android_part2
mkdir /mnt/android_part3

mount partition1.img /mnt/android_part1 -o loop

mount partition2.img /mnt/android_part2 -o loop

mount partition3.img /mnt/android_part3 -o loop

The important part is -o loop

I browse these mounts without problems, looking for every interesting bit.
Note 'Apps pack' on the SD card partition which contains a lot of apk tested working on Joggler.
Be free to add / remove some.

If you plan to make perfect copy of the partition, get the images' size for fdisk using ls -lh partition*.img

-rwxrwxrwx 1 root root 566M Mar 29 09:17 partition1.img
-rwxrwxrwx 1 root root 997M Mar 29 09:17 partition2.img
-rwxrwxrwx 1 root root 2.0G Mar 29 09:17 partition3.img

So, now I connect a 8Go USB drive on my laptop.
To find its device handle, I use dmesg | tail

[12239.238397] sd 6:0:0:0: Attached scsi generic sg3 type 0
[12239.246154] sd 6:0:0:0: [sdc] 15695871 512-byte logical blocks: (8.03 GB/7.48 GiB)
[12239.250002] sd 6:0:0:0: [sdc] Write Protect is off
[12239.250006] sd 6:0:0:0: [sdc] Mode Sense: 45 00 00 08
[12239.250008] sd 6:0:0:0: [sdc] Assuming drive cache: write through
[12239.269992] sd 6:0:0:0: [sdc] Assuming drive cache: write through
[12239.270000]  sdc: sdc1
[12239.288169] sd 6:0:0:0: [sdc] Assuming drive cache: write through
[12239.288175] sd 6:0:0:0: [sdc] Attached SCSI removable disk

My USB drive is on sdc.
To write partitions, I need to remove the existing one so BE SURE of your drive handle !

fdisk /dev/sdc launches fdisk in interactive mode

press p to print the device table (I have 1 partition)
press d to delete a partition
press 1 to delete partition 1 (only if you have more than 1 partition)
press p to check the partition is delete
press w to write the table and so REALLY delete the partition

USB drive is now a raw device.

press n to create the first partition (system)
press p to make it primary
press 1 to tell it's the first one
press enter for default start cylinder
press +566M to define partition 1 size (or whatever you want, like +128M)
press t to ask for type change
press L to see the existing type (optional)
press b to ask for FAT32 change
press p to check if partition is created
press n to create the second partition (userdata)
press p to make it primary
press 2 to tell it's the second one
press enter for default start cylinder
press +997M to define partition 2 size (or whatever you want, like +1G)
press p to check if partition is created
press n to create the third partition (sdcard)
press p to make it primary
press 3 to tell it's the second one
press enter for default start cylinder
press enter for default end cylinder (full size)
press t to ask for type change
press b to ask for FAT32 change
press p to check if partition is created
press w to write partitions and quit

partprobe will sync the partition info with the kernel

Method 1, if you create partition with exact size of image, you could load the partitions with dd

dd if=partition1.img of=/dev/sdc1
dd if=partition2.img of=/dev/sdc2 (optional)

Linux replace the newly created partitions in fdisk (with correct cylinder info)

Methode 2, If you create your own partitions, format, mount and copy

mkdosfs -n system /dev/sdc1
mkdir /mnt/android_system
mount /dev/sdc1 /mnt/android_system
cp -a /mnt/android_part1/* /mnt/android_system

mkfs.ext2 -L user /dev/sdc2
mkdir /mnt/android_user
mount /dev/sdc2 /mnt/android_user
cp -a /mnt/android_part2/* /mnt/android_user

Now copy the previous SD card data to the new one

mkdosfs -n sdcard /dev/sdc3
mkdir /mnt/android_sd
mount /dev/sdc3 /mnt/android_sd
cp -a /mnt/android_part3/* /mnt/android_sd

Et voilà! My USB drive is ready to be plug on Joggler with a ready-to go SD card

Note, in a second try, I simply create 3 partitions and copy the system partition only : a clean boot.
It took several minutes to boot, creating the userdata and basic sd card data.
After a first reboot, everything runs smoother.


Step 2: Setup Android.

I had to disable WIFI and localisation, prior to active Ethernet.
I then setup the Clock Sync.

And apk installation followed...

It's Android so it's only a matter of personal choice, mine was

- cifsManager to handle shared folder on network

- ES File explorer to handle file handling

- Alarm clock plus for music alarm, weather and night desk clock

- Fancy widgets for the HTC Sense like clock, but not working weather (still waiting for an alternative)

- Photo slides to make Joggler a photo frame, using photos from my NAS

- Screen filter to dim the screen when not it use (Joggler is on the bedroom!!)

- Upnplay to play music from my NAS upnp server and control my daughter sound system


Step 3: Analyse port

The Android port was made by Mijuu from mporting and updated by various forum's members.
He was able to

  1. make the Joggler boot on USB
  2. configure a working bootloader for Joggler

Step 3a: Make the Joggler boot on USB

To make the Joggler boot on USB isn't that hard when you know how it works.

Joggler uses a EFI firmware, it so looks on USB for a recovery device if needed.
If it find a EFI Shell script called boot.nsh, it will call it.

Note that I first thought (like a lot of people it seems) than startup.nsh was the script file needed.
I was logical since it's what you'll find on the official EFI document and some various others documents.
But, trying to follow the full boot process, I couln't understand what the fs1:boot2 command meant.
I could make sense to find fs1:boot (call boot.nsh on fs1, the USB device) but not fs1:boot2 !
Thanks to Torn Wuff for making it clear : startup.nsh isn't called on USB device. Easy to test, rename/delete it and you'll still be able to boot on Android !
So, let's go deeper, where goe this bad use of startup.nsh come from ?
Like I said earlier, the first answer is on the EFI official document :
' EFI, a file called "startup.nsh" automatically runs every time a shell environment is opened ...'

But it doesn't explain the fs1:boot2...
To find the answer, let's look at the original Joggler firmware image (based on Miles' instructions)

I downloaded O2 latest firmware at
Then I untared it (tar xvf) and, of course, looked inside : it's more easy-to-hack firmware update I saw !
Basically, this tgz contains a bunch of files (like the raw framebuffer screen to show while updating) and the script (run) to launch the update...
You should now see where Miles' instructions come from ;)

Extracting payload/image.myg will give you a bzipped partimage file.
I so installed partimage (apt-get install partimage on Debian) since fdisk doesn't like it...

partimage -z2 infoimage image.myg

.... segmentation fault ... WTF ?!

in fact, it seems something change on partimage or openpeak used their own...
Hopefully, it is on tools\bin folder so use this one

First we create a fake partition image using

dd if=/dev/zero of=myimage bs=1000 count=0 seek=500000
ps: i love the way he did it : write 0 bytes at position 500000*1000 (about 500M..while we only need 200M)

and mount it using mount...well..not exactly.... since myimage is a raw partition mount can't mount it
you need to format it first...but how if we can't mount the image... using the command behind the -o loop option : losetup

losetup /dev/loop0 myimage
ps : I didn't know this one so sorry if the description isn't perfect, it's how I understand it

mounted as /dev/loop0, a partition like could be /dev/sdc1, we can format it

mkfs.ext2 /dev/loop0

and so restore the partition

./partimage -z2 restore /dev/loop0 image.myg

So.. partimage restore image.myg on /dev/loop0 which is in fact myimage
myimage is now a restored partition, like usual.
Release it

losetup -d /dev/loop0

and mount it

mkdir /mnt/jogglerfs
mount myimage /mnt/jogglerfs -o loop

browse /mnt/jogglerfs and learn a lot !

If you browe bin/, you'll notice joggler use in fact busybox 1.17.1.
Useful if you need to call a command in shell.

If you browse boot/ you'll notice joggler use a 2.6.24 kernel

If you browse cfg/etc/Wireless, you'll notice joggler should be able to use a driver for WIFI for Ralink chipset.

if you browse dev/, you'll notice joggler use only one virtual console. Confirmed by etc/inittab.

if you browse etc/, you'll find some useful stuff like etc/fstab which explain that efi/ and media/ are in fact mount points
etc/X11/xorg.conf will tell you joggler use an Sharp LQ070Y3LG4A at 800x480 24bits with an Intel IEGDriver
etc/client.tag was a mistery before I looked in etc/init.d/boot.d scripts : it seems firmware was also used by swisscom, telio, telefonica and openenergy.
Did OpenPeak make a device for Brazil, Norway, US and UK ?!

if you browse openpeak/, you'll find all the apps (SWF file) for the stock O2 Joggler and the programs behind them

var/images seems to be the data for the geolocalisation

but wait...nothing about boot process !
In fact, like said before, look at etc/fstab : the boot script SEEMS to be in /dev/mmcblk0p1

So we need to dump /dev/mmcblk0p1


Hopefully, someone already did it !
If you browse , you'll find a dump of mmcblk0
I if you don't want to use mount, dd again, the EFI 8686 S3 dump is also waiting you !

apt-get install kpartx
modprobe dm-mod
kpartx -l mmcblk0.img
losetup /dev/loop1 mmcblk0.img
kpartx -av /dev/loop1
dd if=/dev/mapper/loop1p1 of=mmc_1.img
dd if=/dev/mapper/loop1p2 of=mmc_2.img
dd if=/dev/mapper/loop1p3 of=mmc_3.img
dd if=/dev/mapper/loop1p4 of=mmc_4.img
mkdir /mnt/mmc_1
mkdir /mnt/mmc_2
mkdir /mnt/mmc_3
mkdir /mnt/mmc_4
mount /dev/mapper/loop1p1 /mnt/mmc_1
mount /dev/mapper/loop1p2 /mnt/mmc_2
mount /dev/mapper/loop1p3 /mnt/mmc_3
mount /dev/mapper/loop1p4 /mnt/mmc_4
....<do stuff on /mnt/mmc_1>
umount /mnt/mmc_1
umount /mnt/mmc_2
umount /mnt/mmc_3
umount /mnt/mmc_4
losetup -d /dev/loop1
kpartx -d /dev/loop1

If you look inside, you'll find the original EFI bootloader (boot.efi) and the infamous startup.nsh


Yes, the stock firmware tries to launch a boot(.nsh/.efi?) from USB device before to launch its own boot(.efi) from eMMC

Wow! all this work to confirm something already known ?
Yes, but in the same time, I learnt a way to hack throught a closed device like the Joggler.

Step 3b: Configure a working bootloader for Joggler

So a boot.nsh on USB should contains


in the case of the joggler, they almost all use a modified version of GRUB2.
But things change....Torne Wuff did it again : the official GRUB2 now support Joggler without modification.

But what is GRUB ? What it is needed for ?
GRUB loads in fact an Operating System (Linux, Dos, Windows...)
Based on a grub.cfg, GRUB will launch Android (or Linux) with parameters

set timeout = 0

since there is one and only choice (ie not multiboot), don't wait for user choice...difficult without keyboard

menuentry "Android"

define a boot entry called Android. If you could see the GRUB GUI, you'll have to select the "Android" entry

set root=(hd0,1)

any command following are from disk 0, 1st partition.
...disk 0 ? Why ? since we are on USB, we are on disk 1 (fs1) ...
I'm still looking for the meaning of this....

linux /android/kernel root=/dev/ram0 ro video=efifb:off processor.max_cstate=3 LANG=zh SRC=android DATA=/dev/sda2 SDCARD=/dev/block/sda3 DPI=160 ETH_MAC=00:11:22:33:44:55

boots a linux kernel, located at (hd0,1)/android/kernel
others commands following are in fact parameters sent to kernel

initrd /android/initrd.img

load initial RAM disk (on ram0 ????)

initrd.img doesn't contain a initrc nor an init so I don't know what it is used for...
Perhaps referencing the initial devices ?