0%

使用全志H6 Android9.0 SDK启动OrangePi 3 LTS

Orange Pi提供了芯片厂商释放的原始H6 Android9.0 SDK,但没有提供Orange Pi3 LTS的适配代码,所以原始SDK编译出来的镜像不能在Orange Pi3 LTS上正常启动。本文来教你如何突破这一限制。

背景

前段时间决定学习Android系统,这就肯定需要一块开发板么,纸上谈兵是不行的。经过一番搜索,要么适配的Android系统版本太低(5或6),要么价格太贵了。经过艰苦的搜索,发现了Orange Pi3 LST这么一款开发板,适配Android9.0,官方店铺价格¥229加8元运费,价格亲民,吃灰也不心疼。马上下单!

Orange Pi官网提供了相关资料的百度云下载地址,在经历几天几夜的挂机下载后,终于将需要的文件都下载下来了。打开用户手册OrangePi_3_LTS_H6_用户手册_v1.8.pdf,通读一遍。在接近结束的时候,发现了下面一段话。真的是吐血的心都有了,只提供芯片原厂释放的原始SDK!!!不提供适配代码!!!

不撞南墙不回头,按照用户手册的指导搭建好编译环境,经过一个下午的漫长等待,终于编译好了原始Android SDK。烧录到TF卡,上电,直接GG,SDRAM初始化失败。想到只有一个编译好的Android img,不能自己编译,万一耽误以后学习咋办,这个问题还是要尝试解决的。

1
2
3
4
5
6
7
8
9
10
11
12
13
[218]HELLO! BOOT0 is starting!
[222]boot0 commit : de6e50bf43bb48975c66a88b58eef6a7460bf0ef

[241]set pll start
[244]set pll end
......
[585]MP_PGSR0 IS = 0040005d
[588]BYTE0 GATE ERRO IS = 00000003
[591]BYTE1 GATE ERRO IS = 00000003
[595]BYTE2 GATE ERRO IS = 00000003
[598]BYTE3 GATE ERRO IS = 00000003
[602]scan dram rank&width fail !
[605]initializing SDRAM Fail.

准备

在解决开机失败问题之前,一定要对开机流程有一个大致的了解。经过简单的百度,发现了一篇博客:全志平台linux启动流程分析。简单总结一下,就是Boot ROM -> Boot0 -> Boot1 -> U-Boot > kernel。从正常的开机log看,基本就是这个流程。所以,原始Android SDK在Boot0就启动失败了,问题点定位到了。

同时,还需要拿到全志H6的芯片资料,这个可以在linux-sunxi.org/H6获取,这里有数据手册、用户手册、原始SDK。

初步分析

Android相关的代码,OrangePi提供了两个压缩包,android.tar.gzlichee.tar.gz,boot0相关的内容应该是在lichee.tar.gz。经过一番搜索,发现了brandy/basic_loader/boot0目录,这里存储了boot0相关的代码。但是,没有H6的boot0!!!H6是A53内核,有make_a50、make_a67,就是没有make_a53。用grep搜索H6的芯片代码sun50iw6p1,也没有找到任何内容。

通过以上分析,可以得出结论,OrangePi没有提供Android系统的boot0源代码,而是使用了预编译文件。

另一边,按照用户手册的指导,为OrangePi3 LTS编译Linux系统,烧录到TF卡之后可以正常启动。也就是说,OrangePi为Linux系统提供了一份可以正常启动的boot0。经过一番搜索,在orangepi-build/u-boot/v2014.07-sun50iw6-linux4.9/sunxi_spl/boot0发现了boot0的源代码和编译好的boot0_sdcard.bin

找出预编译的boot0

前面分析到,Android系统的boot0不是编译出来的,而是使用的预编译文件。关键点要找到这个文件。以下是官方用户手册给出的Android系统编译命令。显然,最后一步的pack命令用来收集所有编译好的文件,打包成img文件。所以要分析pack命令。

1
2
3
4
5
6
test@test:~$ cd android
test@test:~/android$ source build/envsetup.sh
test@test:~/android$ lunch petrel_fvd_p1-eng
test@test:~/android$ extract-bsp
test@test:~/android$ make -j8
test@test:~/android$ pack

pack命令是source build/envsetup.sh注册的一个shell函数,可以用命令type pack看到源码。经过追踪,pack命令最终会调用lichee/tools/pack/pack脚本。经过分析pack脚本,在函数do_finish()中,会调用命令dragon image.cfg sys_partition.fex来打包、生成最终的img文件。image.cfg,看文件名就知道是最终img文件的配置文件。经过find搜索,image.cfg在lichee/tools/pack/out/image.cfg。打开这个文件,发现如下内容,刚好out目录下面有一个boot0_sdcard.fex文件。

1
2
{filename = "boot0_nand.fex",   maintype = ITEM_BOOT,         subtype = "BOOT0_0000000000",},
{filename = "boot0_sdcard.fex", maintype = "12345678", subtype = "1234567890BOOT_0",},

lichee目录是lichee.tar.gz解压出来的,这个压缩包里面没有tools/pack/out目录,说明out目录是编译时某个命令产生的。用grep搜索boot0_sdcard.fex,找到如下关键内容。所以关键点还是在pack脚本。

1
2
3
4
pack/pack:171:${RES_DIR}/${LICHEE_BIN_PATH}/boot0_sdcard_${PACK_CHIP}.bin:out/boot0_sdcard.fex
pack/pack:311: mv out/boot0_sdcard-${OTA_TEST_NAME}.fex out/boot0_sdcard.fex
pack/pack:517: programmer_img boot0_sdcard.fex boot_package.fex ${out_img} > /dev/null
pack/pack:710: update_boot0 boot0_sdcard.fex sys_config.bin SDMMC_CARD > /dev/null

进入脚本一顿搜索分析,找到如下关键信息。boot0_sdcard.fex来源于${RES_DIR}/${LICHEE_BIN_PATH}/boot0_sdcard_${PACK_CHIP}.bin,命令update_boot0可能会修改文件boot0_sdcard.fex

1
2
3
4
5
6
7
8
9
10
11
12
13

boot_file_list=(
${RES_DIR}/${LICHEE_BIN_PATH}/boot0_nand_${PACK_CHIP}.bin:out/boot0_nand.fex
${RES_DIR}/${LICHEE_BIN_PATH}/boot0_sdcard_${PACK_CHIP}.bin:out/boot0_sdcard.fex
......
printf "copying boot file\n"
for file in ${boot_file_list[@]} ; do
cp -f $(echo $file | sed -e 's/:/ /g') 2>/dev/null
done
......
# Those files for Nand or Card
update_boot0 boot0_nand.fex sys_config.bin NAND > /dev/null
update_boot0 boot0_sdcard.fex sys_config.bin SDMMC_CARD > /dev/null

使用命令find -name boot0_sdcard_*.bin找到文件./pack/chips/sun50iw6p1/bin/boot0_sdcard_sun50iw6p1.bin(还有很多给其他IC用的,这里忽略了)。二进制对比文件boot0_sdcard_sun50iw6p1.binboot0_sdcard.fex,确实存在一些差异,确认了update_boot0确实会修改文件boot0_sdcard.fex

尝试1:Android使用Linux boot0

前面提到,自己编译的Linux系统可以完美启动。我觉得在boot loader阶段,Android和Linux其实是没有什么区别的。所以尝试使用Linux boot0来启动Android。在boot0的main()函数加了几句log,用来确认是否编译进去。然后重新编译。

前面分析出来,Android系统的boot0存储在lichee/tools/pack/chips/sun50iw6p1/bin/boot0_sdcard_sun50iw6p1.bin。备份Android原始的boot0,复制Linux的boot0并重命名,最后重新执行pack命令生成新的img文件。

烧录新的img,上电启动。系统是起来了,但是boot0加的log没有出来。一番查看,原来是从EMMC启动了,也就是说跳过了TF卡中的系统。看来Linux编译出来的boot0,可能在Android系统无法通过某种校验,然后就从EMMC启动了。

综上,本次尝试失败,两个系统的boot0无法通用。

尝试2:从官方Android img提取boot0文件

OrangePi有提供一个Android镜像文件,可以正常启动。既然img文件是由若干个文件打包而成,那么一定可以解包。但问题就在这,img文件是通过dragon命令打包的,dragon也只提供了编译好的二进制文件,没有提供源代码。所以无法从打包的方向获取img文件的内部结构。

使用file命令查看img文件,返回data,没有更多的信息。看来file命令也无法识别其具体的文件类型。

用二进制查看器打开img文件,发现文件头有一个魔法字符串IMAGEWTY,Google这个字符串,发现了如下两个非常有用的网址。

awutils提供了一个叫做awimage的工具,可以用来解压img文件。clone到本地,编译成可执行文件,尝试解包,成了。解出来的文件如下图所示。但是解包之后这么多文件,哪一个才是boot0_sdcard.fex呢?dragon命令有一个参数是image.cfg,再去碰碰运气。在boot0_sdcard.fex那一行,可以看到maintype="12345678"subtype="1234567890BOOT_0"。好巧,解包之后存在一个名为12345678_1234567890BOOT_0的文件,且文件的大小也可以对应上,就是它了。

之前提到过,pack脚本将boot0_sdcard_sun50iw6p1.bin复制为boot0_sdcard.fex后,还用update_boot0命令修改了boot0_sdcard.fex,最终打包到img文件的是update_boot0修改之后的文件。所以提取出来的文件也是update_boot0修改之后的。故要在dragon命令打包的前一刻,将提取出来的文件替换到boot0_sdcard.fex。所以对pack脚本做了如下修改,打包之前复制12345678_1234567890BOOT_0替换到boot0_sdcard.fex

1
2
cp -f /path/to/OrangePi_3_LTS_Android9_v1.0.img.dump/12345678_1234567890BOOT_0  boot0_sdcard.fex
dragon image.cfg sys_partition.fex

重新执行pack命令打包img文件,烧录,启动成功。虽然启动过程中还有一些error log,但最终还是顺利进入了系统。全志H6原始Android SDK桌面如下。