Sunday, October 6, 2013

Booting to Linux instead of Android (flashing kernel partition) for RK


1) Get the software

You'll first need to fetch the Linux RK flashing tool (ignore the git name, the tool is valid for RK2*, RK30, RK31 devices), and the Linux rkcrc tool (for pre-/post-fixing a kernel image with the right RK values):

git clone https://github.com/Galland/rkflashtool_rk3066 rkflashtool
cd rkflashtool
make
cd..

git clone https://github.com/Galland/rk-tools.git
cd rk-tools
make rkcrc
cd ..

2) Prepare your own kernel


After compiling your kernel, you have to convert/sign the zImage output file with this command:

./rk-tools/rkcrc -k Linux3188/arch/arm/boot/zImage kernel.img

Substitute "Linux3188" with the folder name where your kernel sources are.


3) Getting device into Recovery mode


This is most usually done by keeping pressed a pushbutton while plugging the USB OTG connector to your PC and then releasing it after a >2 seconds. If upon typing Linux command "lsusb" on the PC we see a nameless device (with ID 2207:...), that's our RK device in recovery mode.

Warning: some devices (like the Radxa Rock) have a 2 minutes timeout for the recovery mode after which it will power off, the timeout restarts upon any flash reading/writing.



4) Know your partitions


Before any flashing operation, we must be sure of at what offset and what size does the partition of interest have. To do it, while in recovery mode, issue the following command in your PC:

sudo ./rkflashtool r 0x0 0x1 | head -n 11

That will result in several lines of parameter information from your stick. We are interested in the last text paragraph, from "mtdparts" to the end.

For example, in my MK908 (check yours, since there are several versions), it is:
mtdparts=rk29xxnand:0x00002000@0x00002000(misc),0x00006000@0x00004000(kernel),0x00008000@0x0000A000(boot),0x00010000@0x00012000(recovery),0x00020000@0x00022000(backup),0x00040000@0x00042000(cache),0x00400000@0x00082000(userdata),0x00002000@0x00482000(kpanic),0x00100000@0x00484000(system),-@0x00584000(user)
These are the partitions' parameters, where each partition is described as:
partition_size@partition_offset(partition_name)
So the "kernel" partition in my MK908 is at offset 0x4000 and has a size of 0x6000  (= 24,576 sectors of 512 bytes each = 12,582,912 bytes).

Warning: If your partition of interest has an offset that is not multiple of 4MB, you MUST follow the "misaligned" instructions below, using your device's offsets.


Always remember that the flashing tool requires the numbers in reversed position compared to what appears in the mtdparts above, that is: first the offset, then the size, like:
sudo ./rkflashtool r (offset) (size)



5) Backup stock partitions!


I strongly recommend to read and store in your PC at least the boot, kernel, and recovery stock partitions of your devices, before you start tinkering with it!

This is very easily done with these commands (substitute the offsets and sizes with the ones from your mtdparts):


sudo ./rkflashtool r 0x4000 0x6000 > stock_kernel.img
sudo ./rkflashtool r 0xA000 0x8000 > stock_boot.img

sudo ./rkflashtool r 0x12000 0x10000 > stock_recovery.img


6) Flash your new kernel


Since my kernel partition's offset (0x4000 = 16384 => *512B = 8 MB) is a multiple of 4MB, flashing it becomes as easy as:
sudo ./rkflashtool w 0x4000 0x6000 < kernel.img


NOTE: If for some unknown reason you wanted to flash a kernel into boot partition, you should flash the same one that is used to flash recovery.

In order to ensure flashing is done correctly, always reboot the stick after flashing with the following command:
sudo ./rkflashtool b

Now your device will always boot to your kernel!

If it is a Linux kernel, then RK will directly boot to it, ignoring Android (until you revert these changes, by flashing back the stock kernel image)



Misaligned partitions (offset not at 4 MB boundary)


If the partition you want to write/flash starts at an offset not multiple of 4 MB then you will find that the first <4 MB that you write are wrong when/if you read them back.

An example of this can be found in Radxa Rock's boot partition, which starts at offset 0x9000 and has a size of 0x7000. If naively flashing boot with the command:

sudo ./rkflashtool w 0x9000 0x7000 < boot.img
That is: flash boot.img from 0x9000 up to, but not including, 0x10000 (= 0x9000 + 0x7000). If we proceed to read back the just written data, in order to verify it:
sudo ./rkflashtool r 0x9000 0x7000 > boot_readback.img

The result will be:
- Wrong, apparently random, data from 0x9000 up to, but not including, 0xA000 (note this is the first 4 MB boundary within boot partition)
- Good data from 0xA000 up to, but not including, 0x10000, that is: just what we've written, as expected.

This will cause the RK device to ignore the bad boot partition and jump on to recovery partition.

As far as I know, this problem arises when writing images, not when reading. It happens for Linux rkflashtool as well as for Windows RKAndroidTool.exe.



Workaround to flash misaligned partitions


The workaround I've found is to flash the previous partition (kernel) at the same time than boot partition. Why? Because kernel partition's offset is aligned to a 4 MB boundary, so there is no problem flashing it. Hence the operation would be:

//read stock kernel (padded to the full size of the partition)
sudo ./rkflashtool r 0x4000 0x5000 > radxa_stock_kernel.img
//concatenate the kernel partition with your own boot partition
cat radxa_stock_kernel.img my_own_boot_partition.img > kernelboot.img
//flash both partitions at the same time (0x5000+0x7000=0xC000)
sudo ./rkflashtool w 0x4000 0xC000 < kernelboot.img

//optionally read back to verify flashing operation
sudo ./rkflashtool r 0x4000 0xC000 > kernelboot_readback.img
//compare what we wanted to write, to what has been written
cmp -b kernelboot.img kernelboot_readback.img

//always safely reboot the RK device after flashing
sudo ./rkflashtool b



5 comments:

  1. Hi Victor,
    Sorry, you got idea if there are proposals to integrating support to the mainline kernel?

    Simil, http://linux-sunxi.org/Linux_mainlining_effort

    Thanks!.

    ReplyDelete
    Replies
    1. Omegamoon and I are porting RK kernel to its closest cousin: android-3.0 (which is also quite similar, but not exactly the same, to Linux kernel 3.0.x)
      Let's say the RK specific code (from the android-3.0 version it was originally based on) has been very liberal in its intrusions into the kernel's most innersome parts, making it hardly acceptable for any mainlining.
      My hopes go in the direction of finding a subset of RK code that may be cleanly used to patch a pure android-3.0 (and -3.4 if possible) and get something bootable, although that may likely entail dropping support for rk29* since its coding practices are less than ideal.

      I'm just lacking free time for a speedier work on this.

      Delete
  2. Got following error:
    >make rkcrc
    gcc -g -O2 -DUSE_OPENSSL -o rkcrc rkcrc.c -lcrypto
    rkcrc.c: In function ‘main’:
    rkcrc.c:101:8: warning: ignoring return value of ‘write’, declared with attribute warn_unused_result [-Wunused-result]
    write(out, buf, 8);
    ^
    rkcrc.c:107:8: warning: ignoring return value of ‘write’, declared with attribute warn_unused_result [-Wunused-result]
    write(out, buf, nr);
    ^
    rkcrc.c:115:7: warning: ignoring return value of ‘write’, declared with attribute warn_unused_result [-Wunused-result]
    write(out, buf, 4);
    ^
    /usr/bin/ld: cannot find -lcrypto
    collect2: error: ld returned 1 exit status

    ReplyDelete
    Replies
    1. you should install the missing dev crypto libraries in your PC, google it, it's easy

      Delete
    2. Do you mean sudo apt-get install libssl-dev ? Or what should be the name of that ?

      Delete