Firefly开源社区

12
发表新贴

Firefly-RK3288 双系统启动的设计和实现

152

积分

0

威望

6

贡献

技术小白

积分
152
发表于 2014-10-22 10:57:33     
本帖最后由 busybee 于 2014-10-23 15:31 编辑

前言

如何在安卓系统里加入 Linux 系统,实现双系统的共存和切换呢?

安卓有所谓的急救(recovery)模式,急救模式所用到的映像是独立的内核和初始内存根文件系统(initramfs),放在 recovery 分区里。这个 recovery 分区就是最好的放置 Linux 的地方。


分区

我们先来看看纯安卓的存储分区情况。分区信息在 parameter 文件里的 CMDLINE 行:
  1. FIRMWARE_VER:4.4.2
  2. MACHINE_MODEL:rk30sdk
  3. MACHINE_ID:007
  4. MANUFACTURER:RK30SDK
  5. MAGIC: 0x5041524B
  6. ATAG: 0x60000800
  7. MACHINE: 3066
  8. CHECK_MASK: 0x80
  9. PWR_HLD: 0,0,A,0,1
  10. #KERNEL_IMG: 0x62008000
  11. #FDT_NAME: rk-kernel.dtb
  12. #RECOVER_KEY: 1,1,0,20,0
  13. CMDLINE:console=ttyFIQ0 androidboot.hardware=rk30board androidboot.console=ttyFIQ0 board.ap_has_alsa=0 init=/init initrd=0x62000000,0x00800000 mtdparts=rk29xxnand:0x00002000@0x00002000(uboot),0x00002000@0x00004000(misc),0x00008000@0x00006000(resource),0x00008000@0x0000e000(kernel),0x00010000@0x00016000(boot),0x00010000@0x00026000(recovery),0x0001a000@0x00036000(backup),0x00040000@0x00050000(cache),0x00002000@0x00090000(kpanic),0x00180000@0x00092000(system),0x00002000@0x00212000(metadata),0x00200000@0x00214000(userdata),0x00020000@0x00414000(radical_update),-@0x00434000(user)
复制代码

CMDLINE 是传递到内核的命令行,参数 mtdparts 就含有分区信息,其格式是:
  1. 0x00002000@0x00002000(uboot)
  2.   大小         偏移     分区名称

  3. 单位是 512 字节(即传统磁盘的扇区大小)。
复制代码

转换成表格比较直观些:
分区大小(字节)分区名称
4Muboot
4Mmisc
16Mresource
16Mkernel
32Mboot
32Mrecovery
52Mbackup
128Mcache
4Mkpanic
768Msystem
4Mmetadata
1Guserdata
64Mradical_update
总容量-2152Muser


  • uboot :是用来存放第二阶段(stage two) u-boot,开发板用的是 eMMC 分区,其 u-boot 不需要分阶段,所以此处没用上。
  • misc :非常有用的一个分区,下面会介绍到,用来控制启动模式的。
  • resource :存放内核的开机图片和设备树(Device Tree)信息。
  • kernel :存放安卓的内核
  • boot : 存放安卓的正常系统启动的初始内存文件系统(initramfs)。注意,如果在 OTA 方式下, boot 分区跟 recovery 分区一样,含有内核和初始内存文件系统,此时 kernel 分区不作使用。
  • recovery : 存放安卓急救模式所使用到的内核和初始内存文件系统。
  • backup : RK 设计的用来存放备份固件的分区, Firefly-RK3288 没有用到。
  • cache : 安卓的缓存分区
  • kpanic : 安卓的 kernel panic 分区(?)
  • system : 安卓的系统分区(挂载于 /system
  • metadata : RK 的元数据分区,使用情况不详
  • userdata : 安卓的数据分区(挂载于 /data
  • radical_update : RK 的升级分区,使用情况不详
  • user : 安卓的内部存储分区(挂载于 /mnt/sdcard

我们需要增加一个名为 'linuxroot' 的新分区,用来存放 Linux 的根文件系统。为了使分区保持兼容,我们选择了替换 radical_update 分区,容量给够 3G :

1Guserdata
3136Mlinuxroot
总容量-5224Muser


这样,修改后的 parameter 文件,其 CMDLINE 更改为:
  1. CMDLINE:console=ttyFIQ0 androidboot.hardware=rk30board androidboot.console=ttyFIQ0 board.ap_has_alsa=0 root=/dev/block/mtd/by-name/linuxroot rw rootfstype=ext4 init=/sbin/init initrd=0x62000000,0x00800000 mtdparts=rk29xxnand:0x00002000@0x00002000(uboot),0x00002000@0x00004000(misc),0x00008000@0x00006000(resource),0x00008000@0x0000e000(kernel),0x00010000@0x00016000(boot),0x00010000@0x00026000(recovery),0x0001a000@0x00036000(backup),0x00040000@0x00050000(cache),0x00002000@0x00090000(kpanic),0x00180000@0x00092000(system),0x00002000@0x00212000(metadata),0x00200000@0x00214000(userdata),0x00620000@0x00414000(linuxroot),-@0x00a34000(user)
复制代码



如何进入 Linux

接下来的事情是解决如何进入 Linux, 因为我们将 Linux 放在 recovery 分区,因此,问题等价于如何进入安卓的急救模式。以下有几种方式:

  • 拔掉 USB 线,按住开发板的 recovery 键开机(无论是初次上电、重启或按 reset 键开机都可以)。这是临时性的切换,下次开机不按,还是会进入 Linux 。
  • 在安卓系统的设置里选择恢复出厂设置。实际上,恢复出厂设备这个功能已被阉割了,重启后会进入 Linux。
  • Firefly-RK3288 在安卓系统的关机菜单(点底部工具栏的关机按钮进入)增加了一项切换系统的选择,非常人性化。当然,它是检测到 linuxroot 分区才会出现,也就是说单系统是不会出现的。
  • 将 SDK 里的 rkst/Image/misc.img  刷进到 misc 分区。

2~4 项都是通过写 misc 分区,达到切换到 recovery,这里也即是 Linux 的目的。

用 hexdump 命令可以方便地查看 misc.img 的内容:
  1. $ hexdump -C rkst/Image/misc.img
  2. 00000000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
  3. *
  4. 00004000  62 6f 6f 74 2d 72 65 63  6f 76 65 72 79 00 00 00  |boot-recovery...|
  5. 00004010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
  6. *
  7. 00004040  72 65 63 6f 76 65 72 79  0a 2d 2d 77 69 70 65 5f  |recovery.--wipe_|
  8. 00004050  61 6c 6c 00 00 00 00 00  00 00 00 00 00 00 00 00  |all.............|
  9. 00004060  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
  10. *
  11. 0000c000
复制代码

可见,前 16K (0x4000) 字节都是 0,然后是一个 "boot-recovery" 命令,后面又跟着 "recovery", "--wipe_all" 这些动作和参数。

启动加载器(bootloader, 这里是 u-boot),会读出这个分区的内容,如果是 "boot-recovery",则加载 recovery 分区。


第一次启动

虽然说去掉了安卓恢复出厂设置的功能,但初始设置还是不可缺少的。

我们在 Linux 的根文件系统里增加了一个标志文件 /firstboot 。当 Linux 启动,检测到此文件存在,便判断这是第一次启动,需要做以下安卓系统的初始化动作:
  • 使用 resize2fs 扩展根文件系统,修正文件系统的容量信息
  • 格式化 userdata 分区
  • 格式化 cache 分区
  • 格式化 metadata 分区
  • 格式化 user 分区
  • 删除标志文件 /firstboot
  • 重启回安卓系统

实现细节在在 /etc/rc.local 里:
  1. /usr/local/bin/mtd-by-name.sh

  2. if [ -e /firstboot ]; then
  3.     echo "======Expanding the rootfs..."
  4.     resize2fs /dev/block/mtd/by-name/linuxroot
  5.     if [ -e /dev/block/mtd/by-name/userdata ]; then
  6.         echo "=======Formatting userdata(/data)..."
  7.         mkfs.ext4 /dev/block/mtd/by-name/userdata

  8.         echo "=======Formatting metadata(/metadata)..."
  9.         mkfs.ext4 /dev/block/mtd/by-name/metadata

  10.         echo "=======Formatting cache(/cache)..."
  11.         mkfs.ext4 /dev/block/mtd/by-name/cache

  12.         echo "=======Formatting user(/sdcard)..."
  13.         mkfs.vfat /dev/block/mtd/by-name/user

  14.         # reboot to android
  15.         dd if=/dev/zero of=/dev/block/mtd/by-name/misc bs=16k count=3
  16.         rm -f /firstboot
  17.         sync
  18.         reboot
  19.     fi
  20.     rm -f /firstboot
  21. fi
复制代码



如何从 Linux 切换回 Android

很简单,写个脚本将 misc 分区清空,然后重启即可:
  1. sudo dd if=/dev/zero of=/dev/block/mtd/by-name/misc bs=16k count=3
  2. sudo reboot
复制代码

/usr/local/bin/b2android.sh 脚本正是干这事的。
已有 1评分贡献 +6 收起 理由
sunlh + 6 赞一个!

查看全部评分

回复

使用道具 举报

3747

积分

17

威望

18

贡献

官方团队

Rank: 9Rank: 9Rank: 9

积分
3747
发表于 2014-10-22 17:06:32     
哇~~~长见识了
回复

使用道具 举报

79

积分

0

威望

0

贡献

技术小白

积分
79
发表于 2014-11-6 12:42:24     
android 下mtd 分区可以直接 dd 写? linux 的 flash 操作貌似都要先 flash_erase, 然后才能写
回复

使用道具 举报

529

积分

0

威望

0

贡献

技术大神

Rank: 3Rank: 3

积分
529
发表于 2015-5-8 16:30:12     
請問如此的 Linux 是使用原先安卓的同一個內核嘛?
回复

使用道具 举报

152

积分

0

威望

6

贡献

技术小白

积分
152
发表于 2015-5-13 09:59:37     
两个系统所使用的内核,源码相同,内核配置有所不同,因此不是用同一个内核。
回复

使用道具 举报

8

积分

0

威望

0

贡献

吃瓜的群众

积分
8
发表于 2015-12-2 21:59:05     
请教版主,双系统中ubuntu的kernel如何才能更新呢?
回复

使用道具 举报

89

积分

0

威望

0

贡献

技术小白

积分
89
发表于 2016-9-14 14:25:21     
见长识了,自己晚上回去尝试下
回复

使用道具 举报

24

积分

0

威望

0

贡献

游客

积分
24
发表于 2016-10-12 23:28:49     
请教版主:
两个系统所使用的内核,源码相同,内核配置有所不同,因此不是用同一个内核。
---》这个如何做
回复

使用道具 举报

29

积分

0

威望

0

贡献

游客

积分
29
发表于 2016-11-2 11:29:02     
菜鸟求助》》 刷linux内核应该刷到哪个分区里面呢? 。。。
  1. mtdparts=rk29xxnand:0x00002000@0x00002000(uboot),0x00002000@0x00004000(misc),0x00008000@0x00006000(resource),0x00008000@0x0000e000(kernel),0x00010000@0x00016000(boot),0x00010000@0x00026000(recovery),0x0001a000@0x00036000(backup),0x00040000@0x00050000(cache),0x00002000@0x00090000(kpanic),0x00300000@0x00092000(system),0x00008000@0x00392000(metadata),0x00002000@0x0039A000(baseparamer),0x00200000@0x0039C000(userdata),0x00620000@0x0059C000(linuxroot),-@0x00BBC000(user)
复制代码
回复

使用道具 举报

152

积分

0

威望

6

贡献

技术小白

积分
152
发表于 2016-11-2 15:29:33     
安卓有所谓的急救(recovery)模式,急救模式所用到的映像是独立的内核和初始内存根文件系统(initramfs),放在 recovery 分区里。这个 recovery 分区就是最好的放置 Linux 的地方。


(linux kernel + initrd)  --合成--> linux-boot.img --烧写--> recovery 分区
回复

使用道具 举报

返回列表
12
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

友情链接 : 爱板网 电子发烧友论坛 云汉电子社区 粤ICP备14022046号-2
快速回复 返回顶部 返回列表