瑞芯微Rockchip开发者社区
登录
直播中
爱吃果冻
13年用户
884经验值
私信
关注
[问答]
RK3188 从上电开始到启动内核为止的过程是怎样去完成的
开启该帖子的消息推送
RK3188
上电
内核
如何获取RK3066的BootRom呢?有哪些步骤?
RK3188从上电开始到启动内核为止的过程是怎样去完成的?
回帖
(1)
张清华
2022-2-18 13:41:08
上一篇我们已经弄明白了整个MiniPC的软件组成,但是并不是很清楚系统启动的细节,所以这一篇就仔细说明一下rk3188 从上电开始到启动内核为止的过程。
再说明一点,这篇有一部分是翻译的内容,但针对翻译的内容,我亲自做了一些实际的实验,所以我还是自己坦白,这篇算是“伪原创”吧。
这个是国外的一个大神做的工作,真是很佩服啊。
那么,有人会问,我们为什么这么费劲的去解析启动部分的内容,第一,我们没有RK3188的datasheet,第二,没有bootloader的源码。而我们的目的是能够自由的开发或移植bootloader到rk3188上,能够启动我们定制的操作系统。如果谁有RK3188的详细datasheet或者bootloader的源码,一定要给我一份啊!
首先,先翻译一下原创的内容吧。绿色的部分是原文没有提及,我自己根据自己的实验猜测的。其中的代码就不拷贝过来了。
如何获取RK3066的BootRom
以下是我的步骤。
首先,我在我的设备的升级包(update.img)中发现了一个
RK30xxLoader(L)_V1.18.bin的文件。我用rk29Kitchen把它解包出来。
使用
strings
命令(linux下)去查看其中的参考字符串,并没有发现有用的地方,所以我觉得这个文件是经过加密混淆过的。
下一个步骤是使用IDA pro来反汇编RKAndroidTool.exe ---rockchip公司提供的用于烧写升级包的工具。在分解过程中,我发现了loader文件使用了RC4的加密方法。这个文件被分隔成512字节的多个块,每个块都被加密。
所以,我用perl写了unpack_loader.pl
脚本,这样我得到了4个输出文件。
1 14a 321c 30_LPDDR2_300MHz_DD
2 3366 c914 rk30u***plug
4 fc7a 3400 FlashData
4 1307a 1ac00 FlashBoot
幸运的是,这些文件名都是有意义的名字。
30_LPDDR2_300MHz_DD
是一个dram 初始化处理过程。
FlashData
是只是
30_LPDDR2_300MHz_DD的拷贝,只不过是512字节对齐(flash的块大小)。
rk30u***plug
是负责MaskRom模式下的处理。
FlashBoot
是从NAND flash启动的第二阶段,里面也包含了DFU模式的处理。
我也反编译了上面所说的4个文件。在FlashBoot中,发现了用于DFU模式下从DDR Ram区域获取数据的指令。所以,我的想法是在FlashBoot中注入代码,把bootrom拷贝到DFU模式下能够访问到的内存地址。但是一个问题是,FlashBoot会覆盖掉从0地址开始的内存 --- 这个地址也是上电时bootrom被加载的地方。所以,我需要做的就是在Flashboot覆盖掉它以前,从0地址拷贝出0x2800个字节(boot rom 的大小)。这个就是我们想要的
bootrom.bin。
然后,我写了一系列的工具:patch_loader.sh 帮助 注入代码;pack_loader.pl重新组包,并且用rkcrc签名。
我所有的命令就是以下几个:
# perl unpack_loader.pl RK30xxLoader(L)_V1.18.bin write
# sh patch_loader.sh FlashBoot.bin
# perl pack_loader.pl dram=30_LPDDR2_300MHz_DD.bin boot=FlashBoot.bin.patched data=FlashData.bin u***plug=rk30u***plug.bin out=patchedLoader.bin
用RKAndroidTool.exe把生成的patchedLoader.bin烧写到flash中,然后用以下的命令获取loader。
# rkflashtool m 0x64000000 0x2800 >bootrom.bin
我上传了 bootrom.hex。执行命令xxd -rp bootrom.hex >bootrom.bin 把bootrom.hex变换成二进制文件boot.bin。
现在,loader的所有部分都被破解并且反编译了,现在我们就可以把uboot移植到这个平台上,启动我们想要的任何操作系统。
RK3066 的启动过程
在上电时,rk30在bootrom的0地址开始启动。
Bootrom把自己拷贝到SRAM,然后到idbrom中搜索dram的初始化句柄。
Bootrom加载dram初始化句柄到内存(SRAM),然后执行它。
Bootrom到idbrom中搜索flashboot,加载到内存(DRAM)。
如果没找到flashboot,bootrom继续搜索u***plug然后加载它。
如果找到,flashboot初始化NAND,搜索parameter文件,加载kernel到DRAM,然后启动kernel。
该翻译的已经翻译完了,不知道大家能不能理解,反正我是明白了一部分。对于作者的逆向工程的功底,我真是自叹不如啊。既熟悉Windows平台的可执行文件破解,又熟悉arm架构的机器码和汇编指令,还能开发工具进行代码注入。
下面就是我的实验阶段了。
我没有利用IDA pro进行反编译调试,这部分工作好长时间不做了,很生疏,费时。总之,把作者写的perl脚本下载下来运行,解我的Rk3188的bootloader,是完全行的通的。这说明rk3066和rk3188在启动过程以及架构上没有很大改变。运行结果如下图:
从中我们也能看到3188_LPDDR2_300MHz_ 和FlashData的大小很接近,FlashData是以512字节对齐的。这符合作者的阐述。
其实,以上的这些信息,我们使用winhex也是可以看到的,但不是很直观的。
比较解压完的4个文件的大小,发现跟上面解包过程中提供的信息是一样的,这也能说明这个过程是正确的。
我没有分析3188_LPDDR2_300MHz_ 和rk30u***plug,因为DDR2的初始化是必需的过程,没有必要改动。rk30u***plug是通往MaskRom模式的(其实我是真不懂MaskRom模式是什么模式,做什么用,谁明白细节的告诉我啊),但是在我测试过程中,从没进入过这个模式,所以略过吧。
那么重点就是仔细分析FlashBoot这个模块了。
第一步,反汇编FlashBoot模块。FlashBoot模式是纯的二进制文件,不是我们通常的elf文件,在这里没有段的概念,没有架构的概念,有的只有二进制的代码和地址。先看看反汇编的指令吧。
#
arm-linux-gnueabi-objdump -b binary -marmv5 -D FlashBoot.bin > flashboot.asm
每个标准的gcc交叉编译工具链,都很提供一个objdump程序,这是帮助我们做一些debug工作的。我用的arm gcc是从linaro社区下载的,版本是4.7。其中的参数是必须的,binary表示我们的输入是一个纯的二进制文件,marmv5是告诉objdump安装哪种架构来将机器码翻译成汇编语言。因为这个arm objdump不支持armv7的架构,所以先用armv5代替了,虽然有些小的差别,但不会错的天翻地覆。大家可以通过 --help来看看自己的objdump支持什么架构。
这样就得到反汇编得到的汇编语言。下面着重分析这个汇编文件。
从上面的分析得出,第一次拷贝时覆盖了0地址,所以需要在第一次拷贝之前进行代码注入。
那么以下,就分析作者的代码注入原理。
首先,先关注两个重要参数。
offset和inject
,分别代表注入代码的静态文件偏移和执行时的注入点。 这两个点的选择是有依据的。offset为A0,在这个位置数据全部为0,没有特殊意义,并且有很大的空间来存储注入代码。inject为224,通过上面的分析知道,这个是在第一次拷贝之前,比较早的执行位置。
再来看
JUMP1
的计算,实际上这里的目标地址是里面的2b0,因为2b0位置是memcpy的代码,从汇编代码看,就是在r0,r1,r2三个寄存器存入合适的数据(传参),然后把0地址的数据拷贝到
0x64000000
去,个数为0x2800,因为从仅有的手册上看bootrom只有10K。
0x64000000是比较高的地址,不会被覆盖掉。
但为什么计算过程这么麻烦呢,是因为流水线的缘故,这个大家自己去了解吧。
在执行我们注入代码的最后,是恢复原始环境的代码,就是把注入之前的环境恢复回来。224位置的代码被我们修改了,我们返回的时候,要把224位置的代码重新补回来,然后再跳转到228。224位置原来的意思是:把2D8中的数据存入r0,我们则在注入代码中直接写入10080000,效果是一样的。返回228之后,程序就正常执行了。
JUMP
的计算,目的是获得offset位置相对PC的偏移,因为我们的跳转都是相对跳转。当执行到224的时候,要跳转到A0,就要计算向前跳转的偏移。
我们明白这些参数的含义之后,就可以用
dd
命令完成 flashboot的重新组装。
重组的过程是分解的逆过程,在此不多说了。
rkflashtool在前几篇的链接中有源码,在linux下编译通过,并且可以成功运行。在windows下,可执行文件rkflashtool.exe没法成功运行,不知道为什么,也没仔细调试,大家成功了的话,通知一下我吧。
到现在,我们就明白了注入过程和原理。根据我对kernel代码和上面地址的分析,以下就是我个人的猜测了。
bootrom是CPU内置的ROM,内容无法被修改,启动时会依据硬件设置来选择启动方式。
bootrom把自身拷贝带内部sram,因为内部sram无需初始化,所以非常适合bootrom操作。
我们所说的bootloader,实际上是被烧写在一块神秘的idbrom上。这个rom的特性应该是类似于Nor flash,可以随机的访问,并且能执行代码。这样bootrom在其中找到句柄时,就可以立刻跳转过去执行,而不用先拷贝后执行。idbrom的flash肯定不是NAND flash。这点从烧写工具上就可以看出:windows上的rkandroidtool,bootloader和paramter文件都在0地址,这是一组矛盾。linux上的rkflashtool ,有i选项和r选项,分别对应idb flash和nand flash。
在bootrom的高字节中,包含了CPU的标识ID,通过判断这些ID,就可以知道是什么CPU。
Flashboot中才是我们通常Bootloader的工作。所以获得flashboot的动作属性,是我们后续启动的关键。
动作属性主要包括:
对parameter的解析
对kernel分区的使用
对kernel启动时cmdline的作用
这篇的内容涉及很多底层的知识,搞明白这些真的非常有益。
下一篇讲述 Flashboot的动作属性。
上一篇我们已经弄明白了整个MiniPC的软件组成,但是并不是很清楚系统启动的细节,所以这一篇就仔细说明一下rk3188 从上电开始到启动内核为止的过程。
再说明一点,这篇有一部分是翻译的内容,但针对翻译的内容,我亲自做了一些实际的实验,所以我还是自己坦白,这篇算是“伪原创”吧。
这个是国外的一个大神做的工作,真是很佩服啊。
那么,有人会问,我们为什么这么费劲的去解析启动部分的内容,第一,我们没有RK3188的datasheet,第二,没有bootloader的源码。而我们的目的是能够自由的开发或移植bootloader到rk3188上,能够启动我们定制的操作系统。如果谁有RK3188的详细datasheet或者bootloader的源码,一定要给我一份啊!
首先,先翻译一下原创的内容吧。绿色的部分是原文没有提及,我自己根据自己的实验猜测的。其中的代码就不拷贝过来了。
如何获取RK3066的BootRom
以下是我的步骤。
首先,我在我的设备的升级包(update.img)中发现了一个
RK30xxLoader(L)_V1.18.bin的文件。我用rk29Kitchen把它解包出来。
使用
strings
命令(linux下)去查看其中的参考字符串,并没有发现有用的地方,所以我觉得这个文件是经过加密混淆过的。
下一个步骤是使用IDA pro来反汇编RKAndroidTool.exe ---rockchip公司提供的用于烧写升级包的工具。在分解过程中,我发现了loader文件使用了RC4的加密方法。这个文件被分隔成512字节的多个块,每个块都被加密。
所以,我用perl写了unpack_loader.pl
脚本,这样我得到了4个输出文件。
1 14a 321c 30_LPDDR2_300MHz_DD
2 3366 c914 rk30u***plug
4 fc7a 3400 FlashData
4 1307a 1ac00 FlashBoot
幸运的是,这些文件名都是有意义的名字。
30_LPDDR2_300MHz_DD
是一个dram 初始化处理过程。
FlashData
是只是
30_LPDDR2_300MHz_DD的拷贝,只不过是512字节对齐(flash的块大小)。
rk30u***plug
是负责MaskRom模式下的处理。
FlashBoot
是从NAND flash启动的第二阶段,里面也包含了DFU模式的处理。
我也反编译了上面所说的4个文件。在FlashBoot中,发现了用于DFU模式下从DDR Ram区域获取数据的指令。所以,我的想法是在FlashBoot中注入代码,把bootrom拷贝到DFU模式下能够访问到的内存地址。但是一个问题是,FlashBoot会覆盖掉从0地址开始的内存 --- 这个地址也是上电时bootrom被加载的地方。所以,我需要做的就是在Flashboot覆盖掉它以前,从0地址拷贝出0x2800个字节(boot rom 的大小)。这个就是我们想要的
bootrom.bin。
然后,我写了一系列的工具:patch_loader.sh 帮助 注入代码;pack_loader.pl重新组包,并且用rkcrc签名。
我所有的命令就是以下几个:
# perl unpack_loader.pl RK30xxLoader(L)_V1.18.bin write
# sh patch_loader.sh FlashBoot.bin
# perl pack_loader.pl dram=30_LPDDR2_300MHz_DD.bin boot=FlashBoot.bin.patched data=FlashData.bin u***plug=rk30u***plug.bin out=patchedLoader.bin
用RKAndroidTool.exe把生成的patchedLoader.bin烧写到flash中,然后用以下的命令获取loader。
# rkflashtool m 0x64000000 0x2800 >bootrom.bin
我上传了 bootrom.hex。执行命令xxd -rp bootrom.hex >bootrom.bin 把bootrom.hex变换成二进制文件boot.bin。
现在,loader的所有部分都被破解并且反编译了,现在我们就可以把uboot移植到这个平台上,启动我们想要的任何操作系统。
RK3066 的启动过程
在上电时,rk30在bootrom的0地址开始启动。
Bootrom把自己拷贝到SRAM,然后到idbrom中搜索dram的初始化句柄。
Bootrom加载dram初始化句柄到内存(SRAM),然后执行它。
Bootrom到idbrom中搜索flashboot,加载到内存(DRAM)。
如果没找到flashboot,bootrom继续搜索u***plug然后加载它。
如果找到,flashboot初始化NAND,搜索parameter文件,加载kernel到DRAM,然后启动kernel。
该翻译的已经翻译完了,不知道大家能不能理解,反正我是明白了一部分。对于作者的逆向工程的功底,我真是自叹不如啊。既熟悉Windows平台的可执行文件破解,又熟悉arm架构的机器码和汇编指令,还能开发工具进行代码注入。
下面就是我的实验阶段了。
我没有利用IDA pro进行反编译调试,这部分工作好长时间不做了,很生疏,费时。总之,把作者写的perl脚本下载下来运行,解我的Rk3188的bootloader,是完全行的通的。这说明rk3066和rk3188在启动过程以及架构上没有很大改变。运行结果如下图:
从中我们也能看到3188_LPDDR2_300MHz_ 和FlashData的大小很接近,FlashData是以512字节对齐的。这符合作者的阐述。
其实,以上的这些信息,我们使用winhex也是可以看到的,但不是很直观的。
比较解压完的4个文件的大小,发现跟上面解包过程中提供的信息是一样的,这也能说明这个过程是正确的。
我没有分析3188_LPDDR2_300MHz_ 和rk30u***plug,因为DDR2的初始化是必需的过程,没有必要改动。rk30u***plug是通往MaskRom模式的(其实我是真不懂MaskRom模式是什么模式,做什么用,谁明白细节的告诉我啊),但是在我测试过程中,从没进入过这个模式,所以略过吧。
那么重点就是仔细分析FlashBoot这个模块了。
第一步,反汇编FlashBoot模块。FlashBoot模式是纯的二进制文件,不是我们通常的elf文件,在这里没有段的概念,没有架构的概念,有的只有二进制的代码和地址。先看看反汇编的指令吧。
#
arm-linux-gnueabi-objdump -b binary -marmv5 -D FlashBoot.bin > flashboot.asm
每个标准的gcc交叉编译工具链,都很提供一个objdump程序,这是帮助我们做一些debug工作的。我用的arm gcc是从linaro社区下载的,版本是4.7。其中的参数是必须的,binary表示我们的输入是一个纯的二进制文件,marmv5是告诉objdump安装哪种架构来将机器码翻译成汇编语言。因为这个arm objdump不支持armv7的架构,所以先用armv5代替了,虽然有些小的差别,但不会错的天翻地覆。大家可以通过 --help来看看自己的objdump支持什么架构。
这样就得到反汇编得到的汇编语言。下面着重分析这个汇编文件。
从上面的分析得出,第一次拷贝时覆盖了0地址,所以需要在第一次拷贝之前进行代码注入。
那么以下,就分析作者的代码注入原理。
首先,先关注两个重要参数。
offset和inject
,分别代表注入代码的静态文件偏移和执行时的注入点。 这两个点的选择是有依据的。offset为A0,在这个位置数据全部为0,没有特殊意义,并且有很大的空间来存储注入代码。inject为224,通过上面的分析知道,这个是在第一次拷贝之前,比较早的执行位置。
再来看
JUMP1
的计算,实际上这里的目标地址是里面的2b0,因为2b0位置是memcpy的代码,从汇编代码看,就是在r0,r1,r2三个寄存器存入合适的数据(传参),然后把0地址的数据拷贝到
0x64000000
去,个数为0x2800,因为从仅有的手册上看bootrom只有10K。
0x64000000是比较高的地址,不会被覆盖掉。
但为什么计算过程这么麻烦呢,是因为流水线的缘故,这个大家自己去了解吧。
在执行我们注入代码的最后,是恢复原始环境的代码,就是把注入之前的环境恢复回来。224位置的代码被我们修改了,我们返回的时候,要把224位置的代码重新补回来,然后再跳转到228。224位置原来的意思是:把2D8中的数据存入r0,我们则在注入代码中直接写入10080000,效果是一样的。返回228之后,程序就正常执行了。
JUMP
的计算,目的是获得offset位置相对PC的偏移,因为我们的跳转都是相对跳转。当执行到224的时候,要跳转到A0,就要计算向前跳转的偏移。
我们明白这些参数的含义之后,就可以用
dd
命令完成 flashboot的重新组装。
重组的过程是分解的逆过程,在此不多说了。
rkflashtool在前几篇的链接中有源码,在linux下编译通过,并且可以成功运行。在windows下,可执行文件rkflashtool.exe没法成功运行,不知道为什么,也没仔细调试,大家成功了的话,通知一下我吧。
到现在,我们就明白了注入过程和原理。根据我对kernel代码和上面地址的分析,以下就是我个人的猜测了。
bootrom是CPU内置的ROM,内容无法被修改,启动时会依据硬件设置来选择启动方式。
bootrom把自身拷贝带内部sram,因为内部sram无需初始化,所以非常适合bootrom操作。
我们所说的bootloader,实际上是被烧写在一块神秘的idbrom上。这个rom的特性应该是类似于Nor flash,可以随机的访问,并且能执行代码。这样bootrom在其中找到句柄时,就可以立刻跳转过去执行,而不用先拷贝后执行。idbrom的flash肯定不是NAND flash。这点从烧写工具上就可以看出:windows上的rkandroidtool,bootloader和paramter文件都在0地址,这是一组矛盾。linux上的rkflashtool ,有i选项和r选项,分别对应idb flash和nand flash。
在bootrom的高字节中,包含了CPU的标识ID,通过判断这些ID,就可以知道是什么CPU。
Flashboot中才是我们通常Bootloader的工作。所以获得flashboot的动作属性,是我们后续启动的关键。
动作属性主要包括:
对parameter的解析
对kernel分区的使用
对kernel启动时cmdline的作用
这篇的内容涉及很多底层的知识,搞明白这些真的非常有益。
下一篇讲述 Flashboot的动作属性。
举报
更多回帖
rotate(-90deg);
回复
相关问答
RK3188
上电
内核
RK3188
是什么?
RK3188
具有哪些特性呢
2022-02-18
2300
怎样
在
RK3188
平台上
怎样
去
设置HDMI和外接喇叭同时出声呢
2022-02-18
1619
初试
RK3188
/
RK
3288的学习记录
2022-02-18
1617
怎样
使用Goodix的GT801对
RK3188
触摸屏进行调试呢
2022-02-21
2144
怎样
去
解决
RK3188
的wifi无法切换4G上网的问题呢
2022-02-18
1138
RK3188
处理器具有哪些特征呢
2022-02-18
1715
RK3188
的基本参数有哪些呢
2022-02-18
1475
RK3188
硬件设计指南
2022-02-18
1592
瑞芯微
RK3188
芯片设计资料分享
2021-01-19
1348
请问一下如何在
RK
3066/
RK3188
电视棒上安装ubuntu系统呢
2022-02-18
2813
发帖
登录/注册
20万+
工程师都在用,
免费
PCB检查工具
无需安装、支持浏览器和手机在线查看、实时共享
查看
点击登录
登录更多精彩功能!
首页
论坛版块
小组
免费开发板试用
ebook
直播
搜索
登录
×
20
完善资料,
赚取积分