20090821

Android ARMv4T Donut Patch

On my most recent flight from Canada to Germany, and in spite of having a great conversation with a single-serving friend, I got a bit bored and decided to try and build Donut for ARMv4T, which is quite unstable at the moment. The single-serving friend, whose name I never learned, was in a very similar boat as me - he said he was in the middle of an MSc in biomedical engineering in Lyon, and was originally from Kentucky. It's nice to actually have a decent conversation on an overseas flight for a change.

Anyway - back to the topic at hand.

The reason I'm working on the Donut branch of Android, and patching it for ARMv4T, is that I would eventually like to use it on my OpenMoko FreeRunner, which currently uses Android-Cupcake from KoolU / Michael Trimarchi. Although the generic Donut branch now builds successfully with my patch, I still need to migrate all of the hardware-specific FreeRunner changes that KoolU (any many others) made.

If you feel interested in starting from the upstream end and working downstream, as opposed to starting from KoolU git and working upstream, then check out my patch (update: see bottom of post for updated patches) and give me some feedback. I'm not inclined to submit it upstream yet, without having tested out an an actual device, so it's in very early stages right now, but it definitely builds.

You'll need to create a buildspecs.mk file, like the one below, and put it in the base of your android build directory:

TARGET_SIMULATOR := false
TARGET_BUILD_TYPE := release
TARGET_ARCH_VERSION := armv4t

Happy hacking!

update-20090824: android-donut-armv4t-20090824.patch
update-20090825: android-donut-armv4t-20090825.patch
  • While working on the above patch, I discovered that a lot of upstream work has been done on Android under the hood to support ARMv4T. That includes v4T assembly optimization for opencore, dalvik, etc. Bottom line - this is good for the FreeRunner! However, there are still a few places which need improvement though, and equivalent v4 asm. I filled in some of the gaps (external/opencore/codecs_v2/video/m4v_h263/enc/src/fastquant_inline.h) last night, but the rest are mainly all of the files that think CLZ is an V4 ARM instruction (sheesh!). They were easy enough to convert to C-equivalent code.
  • Recently Michael Trimarchi also announced some work was underway to integrate the libGlamo code into Android's GL. Not too shabby! Perhaps we might see an accelerated Android on the OpenMoko FreeRunner in the near future!
  • I recently put some thought to the Glamo's limited 511x511 buffer and limit of 7Mb/s to memory. Sure, it sucks, that we can't do everything at 640x480 (as advertised), but aren't there other ways to get around it? Such as performing acceleration on one quadrant of the FB at a time? Or switching to/from a lower or higher resolution when playing video / games ? We essentially have to beg for, borrow, cheat & steal those accelerated pixels if acceleration is to work.
update-20091017: android-donut-armv4t-20090825-1.patch
update-20091214: Please see my newer post for a continuation of the effort.

21 comments:

Serdar said...

Hi Christopher,

I've tried your patch on koolu-donut and official android git.

koolu-donut failed.
make: *** No rule to make target `out/host/linux-x86/framework/commons-compress-1.0.jar', needed by `out/host/common/obj/JAVA_LIBRARIES/sdklib_intermediates/javalib.jar'. Stop.
make: *** Waiting for unfinished jobs....

git-android compiled but the system.img I got isn't jffs2 or yaffs2
system.img: VMS Alpha executable

Greetings Serdar

michael said...

Hi,

I'm michael trimarchi,
Can you help us in the new
open freerunner project?

Christopher Friedt said...

Serdar:

I would suggest that you forget about building the SDK or the simulator targets.

I had the same experience with 'file' on the .img files as well - I just assumed that 'file' did not know how to identify a yaffs image. Regardless, you can always just create a tarball by putting the contents of root/ and system/ together.

Michael:

which project are you talking about exactly? The only ones I'm really interested in are the kernel and android ... and perhaps some Gentoo stuff, but mainly for testing out new kernel features.

androjes said...

Christopher:
I've tried your patch on official android git (latest version) but I get some errors:
>Hunk #1 FAILED at 46.
>1 out of 1 hunk FAILED -- saving rejects >to file core/combo/linux-arm.mk.rej
which version are you using?
Thanks

androjes said...

Hi,
I am using now the android donut. Your patch (the latest) works but during the compilation I've got this error:

"Assembler messages:
dalvik/vm/arch/arm/CallEABI.S:245: Error: bad instruction `mv pc,lr'
make: *** [out/target/product/generic/obj/SHARED_LIBRARIES/libdvm_intermediates/arch/arm/CallEABI.o] Error 1"


Could you give one solution please? thanks

Janne said...

I assume Micheal means the android-on-freerunner project hosted on google code: http://code.google.com/p/android-on-freerunner/

Christopher Friedt said...

androjes:

my patch applied to some version of android before the official donut release. i can't promise that it will apply cleanly to any random snapshot of the android source.

also, mv pc,lr is an arm instruction that was used (pre ARMv5) to return from a function call. I can't say why it isn't working in your case.

michael:
Janne:

I have been testing out each of the latest images as they are released. At the momentn I'm having a bit of an issue with wifi. I'm doing a bit of hacking on the htc wizard at the moment, but should be done with that soon.

bend said...

this is great.
But I found there is a bug in the patch.
For simulating blx in armv4t, there is something like this in the patch

+#ifndef __ARM_ARCH_4T__
blx ip
+#else
+ mv pc, lr
+ bx ip
+#endif

it should be
mov lr, pc

maybe this is only a typo or something.
what do you think?

Christopher Friedt said...

bend:
androjes:

It is a typo - my mistake.

mv pc, lr => mov lr, pc

Sorry for not fixing it earlier, but I haven't been doing anything with this project for a while.

The patch is updated, and thanks for letting me know ;-)

Tulga said...

Hi,

I'm using s3c2442 armv4t processor. I compiled your patch on my ubuntu box and I tested on emulator. working well. but my hardware using WM6 and I cannot boot from SD card. now I'm using haret to boot from SD card. can you post about generate zImage and initrd?

Thanks

Shantanu said...

nice work chris.. I am getting a mini2440 (which has the same proc as freerunner) so this work will come in handy for me :)
btw, if I may ask, what are you doing on HTC wizard? I happen to own one as well and would be interested to read/learn about anything interesting you are doing with it :)

ran said...

Have done a build, based on repo init -u git://android.git.kernel.org/platform/manifest.git, but no kernel.img . Could you give some idea about?

Christopher Friedt said...

@Shantanu

Nice to hear that the v4T patches are useful for you, although the 2.0 version 'eclair' is out now.

The HTC wizard has a couple of good communities built up around it - wing-linux and linwizard. The wizard is probably the 'best' device I have that runs Android and performs much better than the FR. I was actually quite surprised to see how well the Omap850 handled Android - it's very fast and responsive in spite of being a (relatively) older chip. You can pick them up on eBay for very little - mine was 60€.

Christopher Friedt said...

@Tulga,ran

It's great that you've found my patch useful. Keep in mind though, that the Android code really only concerns itself with the user-space aspect of running Linux on your mobile.

Hacking the Linux kernel to run on a new device is a slightly harder challenge.

In some cases you'll be very lucky to have a Linux kernel 'work' just by using one compiled for the same SoC (from different handset). Often multiple manufacturers will base their handset on the same evaluation board, so the kernel can be portable.

If that doesn't work, my advice would be to buy an identical broken model from someone on eBay, dissassemble that to discover the various chips (bluetooth, wifi, power-management, gps, keypad-controller, etc), and then start creating a new board definition from scratch in the linux kernel (i.e. MACH_TYPE in arch/arm/tools/mach-types, something in arch/arm/mach-X/myboard.c ).

The most important thing you can do at first is get feedback via a console somehow 1) UART (if you can find some unpopulated solder pads) 2) ethernet-gadget, 3) LCD. Then try to get the SD card working. After that, get the various buttons and input devices / touchscreen working, and then worry about bluetooth, wifi, etc.

Good luck!

Shantanu said...

@chris: Wow, I never knew android could run on my wizard as well. Thanks for those tips, I'll try those out.
About eclair, I think the source is not uploaded yet, so currently I'm working with donut code only..

ironox said...

Hi Christopher,

thanks for your patch.and your patch
works.
i am trying to run android on my board,it is based on a s3c2440(arm920t) cpu,but when i run the new compiled img on my board,
i get below log from logcat repeatedly:

# D/AndroidRuntime( 1616): >>>>>>>>>>>>>> AndroidRuntime START <<<<<<<<<<<<<<
# D/AndroidRuntime( 1616): CheckJNI is OFF
# I/DEBUG ( 1464): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
# I/DEBUG ( 1464): Build fingerprint: 'generic/generic/generic/:1.6/Donut/eng.ironox.20091210.133754:eng/test-keys'
# I/DEBUG ( 1464): pid: 1616, tid: 1616 >>> zygote <<<
# I/DEBUG ( 1464): signal 4 (SIGILL), fault addr ad059dc0
# I/DEBUG ( 1464): r0 4104bf1c r1 bee93598 r2 4106cc18 r3 0000bc48
# I/DEBUG ( 1464): r4 417447f2 r5 4104bf2c r6 bee93590 r7 ad00e840
# I/DEBUG ( 1464): r8 00000071 r9 0000bc48 10 4104bf0c fp 00000000
# I/DEBUG ( 1464): ip 00000071 sp bee93550 lr ad01342c pc ad059dc0 cpsr 00000010
# I/DEBUG ( 1464): #00 pc 00059dc0 /system/lib/libdvm.so
# I/DEBUG ( 1464): #01 lr ad01342c /system/lib/libdvm.so
# I/DEBUG ( 1464): stack:
# I/DEBUG ( 1464): bee93510 4000cc70
# I/DEBUG ( 1464): bee93514 4162a1f8
# I/DEBUG ( 1464): bee93518 00000001
# I/DEBUG ( 1464): bee9351c ad06030b /system/lib/libdvm.so
# I/DEBUG ( 1464): bee93520 4000cc70
# I/DEBUG ( 1464): bee93524 ad08ae1c
# I/DEBUG ( 1464): bee93528 00003f3f
# I/DEBUG ( 1464): bee9352c 00015d88 [heap]
# I/DEBUG ( 1464): bee93530 00015d20 [heap]
# I/DEBUG ( 1464): bee93534 0000096f
# I/DEBUG ( 1464): bee93538 00000000
# I/DEBUG ( 1464): bee9353c 41744c48
# I/DEBUG ( 1464): bee93540 4104bf58
# I/DEBUG ( 1464): bee93544 bee93590 [stack]
# I/DEBUG ( 1464): bee93548 e3a07077
# I/DEBUG ( 1464): bee9354c ef900077
# I/DEBUG ( 1464): #00 bee93550 0000bc48 [heap]
# I/DEBUG ( 1464): bee93554 ad08bef0
# I/DEBUG ( 1464): bee93558 bee93590 [stack]
# I/DEBUG ( 1464): bee9355c ad018038 /system/lib/libdvm.so
# I/DEBUG ( 1464): bee93560 00000344
# I/DEBUG ( 1464): bee93564 bee93640 [stack]
# I/DEBUG ( 1464): bee93568 4000cc70
# I/DEBUG ( 1464): bee9356c 4104bf6c
# I/DEBUG ( 1464): bee93570 00000000
# I/DEBUG ( 1464): bee93574 ad018090 /system/lib/libdvm.so
# I/DEBUG ( 1464): bee93578 00010978 [heap]
# I/DEBUG ( 1464): bee9357c 00000001
# I/DEBUG ( 1464): bee93580 0000bc48 [heap]
# I/DEBUG ( 1464): bee93584 ad017a9c /system/lib/libdvm.so
# I/DEBUG ( 1464): bee93588 4000cc70
# I/DEBUG ( 1464): bee9358c afe0ee38 /system/lib/libc.so
# I/DEBUG ( 1464): bee93590 41744c44
# I/DEBUG ( 1464): bee93594 4104bf58
it seems zygote have illegal instruction in it, but i do not know how
fix it,
i also read this page:
http://groups.google.com/group/android-porting/browse_thread/thread/79ce91a0841a4c5b/de53b8177a5cff21?hl=zh-CN&lnk=gst&q=armv4t#de53b8177a5cff21

Greetings

Christopher Friedt said...

@ironox

Thanks for the update.

This patch worked for Donut at some point.

My solution might sound a little brute-force, but its very scriptable.

Go into the out/ directory, to wherever your root/ and system/ directories are, and disassemble all of the binaries (all executables and .so files) using objdump. Then, I would just grep through all of the output to find an ARM instruction that is not part of the ARMv4T instruction set.

Please do share your results with the rest of us, and I'll incorporate any necessary changes.

Thanks!!
===================
bash script outline
===================
#!/bin/sh

# run something like this in your android out/target/product/generic directory

prefix="/some/path/myandroid/prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/arm-eabi-"
dirs="system root"

exes="$(find ${dirs} -type f -executable)"
sos="$(find ${dirs} -type f -name '*.so*')"
all="$(echo "${exes} ${sos}" | sed -e 's/\ /\n/g' | sort -u)"

for i in ${all}; do
${prefix}objdump -d ${OBJDUMPFLAGS} ${i} > ${i}_dump 2>/dev/null
done

for i in $(find ${dirs} -name '*_dump' -and -not '_dump'); do
result="$(grep "${SOME_ILLEGAL_PATTERN}" ${i} 2>/dev/null)"
if [ "${result}" != "" ]; then
echo "${i}: ${result}"
fi
done

ironox said...

Hi Christopher,
I've tried your script ,but it doesn't work,my shell said:
[ironox@localhost generic]$ ./dumpall.sh
find: paths must precede expression: _dump
Usage: find [-H] [-L] [-P] [-Olevel] [-D help|tree|search|stat|rates|opt|exec] [path...] [expression]

sorry ,i know very little about script

dumpall.sh is :

#!/bin/sh

# run something like this in your android out/target/product/generic directory

prefix="/home/ironox/mycupcake/prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/arm-eabi-"
dirs="system root"

exes="$(find ${dirs} -type f -executable)"
sos="$(find ${dirs} -type f -name '*.so*')"
all="$(echo "${exes} ${sos}" | sed -e 's/\ /\n/g' | sort -u)"

for i in ${all}; do
${prefix}objdump -d ${OBJDUMPFLAGS} ${i} > ${i}_dump 2>/dev/null
done

for i in $(find ${dirs} -name '*_dump' -and -not '_dump'); do
result="$(grep "${SOME_ILLEGAL_PATTERN}" ${i} 2>/dev/null)"
if [ "${result}" != "" ]; then
echo "${i}: ${result}"
fi
done

Christopher Friedt said...

Here's a script that will do some of the work.

Does anyone want to fill in the blank for ARMv4T_OPCODES? It should be a regular expression containing all ARMv4T instructions.


#!/bin/sh

OUTPATH=out/target/product/generic
OBJDUMPFLAGS="--no-show-raw-insn"

if [ "${ANDROID_HOME}" = "" ]; then
echo "please export the ANDROID_HOME environment variable"
exit 1
fi

if [ ! -d "${ANDROID_HOME}"/.repo ]; then
echo "${ANDROID_HOME}/.repo: No such file or directory"
exit 2
fi

if [ ! -f "${ANDROID_HOME}"/.repo/manifest.xml ]; then
echo "${ANDROID_HOME}/.repo/manifest.xml: No such file or directory"
exit 3
fi

if [ ! -d "${ANDROID_HOME}"/${OUTPATH}/ ]; then
echo "${ANDROID_HOME}/${OUTPATH}: No such file or directory"
echo "Have you forgotten to run 'make' ?"
exit 4
fi

cd "${ANDROID_HOME}/${OUTPATH}/"

prefix="${ANDROID_HOME}/prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin/arm-eabi-"
dirs="system root"

exes="$(find ${dirs} -type f -executable)"
sos="$(find ${dirs} -type f -name '*.so*')"
all="$(echo "${exes} ${sos}" | sed -e 's/\ /\n/g' | sort -u)"

newall=""
for i in ${all}; do
res="$(file ${i} 2>/dev/null)"
if [[ ${res} =~ .*ARM* ]]; then
echo "${i}"
${prefix}objdump -d $OBJDUMPFLAGS ${i} | grep "^\( \|[0-9]\|[a-f]\)\{8\}:" | awk '{split($0,a,":"); print a[2];}' | sed -e 's/^[\ \t]*//g' | awk '{split($0,a," "); print a[1]; }' | grep -v "^undefined" | sort -u > ${i}_dump
res=$?
if [ $res -ne 0 ]; then
echo "${i}: objdump failed ($res)"
rm "${i}"_dump
else
newall="${newall} ${i}"
fi
fi
done

exit 0

for i in $(find ${dirs} -name '*_dump' -and -not '_dump'); do
result="$(grep -v "${ARMv4T_OPCODES}" ${i} 2>/dev/null)"
if [ "${result}" != "" ]; then
echo "${i}: ${result}"
fi
done

Christopher Friedt said...

@ironox

Hi again, yeah - the script that I posted in the comments section was only for illustrative purposes and I did test it out.

Please see my latest post to download a script that works and has been tested, as well as an update patch.

Christopher Friedt said...

sorry, that should read "I did not test it out", w.r.t. the example script in the comments section.