1 关键字

ramdisk; fstab.required; kernel崩溃

2 问题描述

2.1 运行环境

  • 软件环境:

    • OH版本:3.1release

    • kernel版本:firefly-4.19

  • 硬件环境:

    • firefly 3568-pc

2.2 问题现象:

在OpenHarmony 3.1-Release当中,默认使用了ramdisk启动引导,但使用第三方内核+OH应用启动时,会出现内核崩溃的问题,崩溃日志日志如下:

……
run-init: /etc/init: Permission denied
[    4.389343] [pid=1][INIT][INFO] [init.c:225)] DISABLE_INIT_TWO_STAGES not defined
[    4.389498] [pid=1][INIT][ERROR] [init.c:175)] Failed get fstab.required
[    4.389569] Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000004
[    4.389569] 
[    4.391468] CPU: 3 PID: 1 Comm: init Not tainted 4.19.219 #5
[    4.391965] Hardware name: Firefly RK3568-ROC-PC HDMI (Linux) (DT)
[    4.392508] Call trace:
[    4.392739]  dump_backtrace+0x0/0x188
[    4.393067]  show_stack+0x24/0x30
[    4.393373]  dump_stack+0x8c/0xb4
[    4.393677]  panic+0x138/0x2b0
[    4.393958]  do_exit+0x1a4/0x868
[    4.394250]  __arm64_sys_exit_group+0x0/0x24
[    4.394634]  get_signal+0x694/0x698
[    4.394949]  do_signal+0x9c/0x238
[    4.395252]  do_notify_resume+0xc8/0x110
[    4.395601]  work_pending+0x8/0x10
[    4.395907] SMP: stopping secondary CPUs
[    4.396304] PMU CRU:
……

2.3 测试步骤

  • 1、生成firefly 4.19 未修改过的源码内核文件。boot.img,MiniLoaderAll.bin,misc.img,parameter.txt,recovery.img,uboot.img

  • 2、生成OpenHarmony 3.1-Release 编译后提供的system.img,userdata.img,vector.img

  • 3、使用1提供的分区表文件parameter.txt,把img下载到硬件。

  • 4、启动后直接发现内核崩溃.

3 问题原因

3.1 正常机制

  • 在正常情况下,uboot->kernel->initrd(设置root=/dev/ram0)->init->mount file system->init->启动OpenHarmony

3.2 异常机制

  • kernel执行init过程中,找不到fstab.required文件,导致kernel直接崩溃。

4 解决方案

fstab.required 文件只存在于OpenHarmony生成的ramdisk.img中,解决方案分两种情况:

1、kernel不支持ramdisk方式。

在OpenHarmony中关闭ramdisk(rk3568 修改路径:productdefine\common\device\rk3568.json)。 相应配置修改成:"enable_ramdisk": false。

2、kernel支持ramdisk方式。以firefly rk3568为例:

把OpenHarmony生成的ramdisk.img覆盖firefly kernel使用的ramdisk.img。重新编译,下载。这样就可以找到fstab.required。并挂载文件系统,启动OpenHarmony相关服务。这种方法要确保OpenHarmony与Kernel的编译工具链的一致性。

5 定位过程

1、从崩溃日志可以看到如下打印:

[    2.168829] Run /init as init process
…………
[    4.552748] fusb302 0-0022: PD disabled
[    4.603896] [pid=1][INIT][INFO] [init.c:225)] DISABLE_INIT_TWO_STAGES not defined
[    4.604088] [pid=1][INIT][ERROR] [init.c:175)] Failed get fstab.required
[    4.604173] Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000004
[    4.604173] 
[    4.606027] CPU: 1 PID: 1 Comm: init Not tainted 4.19.219 #5
[    4.606527] Hardware name: Firefly RK3568-ROC-PC HDMI (Linux) (DT)
[    4.607073] Call trace:
……………
​

在启动init时,有两个关键的打印:

  • DISABLE_INIT_TWO_STAGES not defined

  • Failed get fstab.required

从DISABLE_INIT_TWO_STAGES 打印可以看出,与ramdisk有关

if (!enable_ramdisk) {
      defines += [ "DISABLE_INIT_TWO_STAGES" ]
    }

enable_ramdisk 在以下路径中有定义:productdefine\common\device\rk3568.json

"enable_ramdisk": true,

Failed get fstab.required 打印源码如下:

static void StartInitSecondStage(void)
{
    const char *fstabFile = "/etc/fstab.required";
    Fstab *fstab = NULL;
    if (access(fstabFile, F_OK) != 0) {
        fstabFile = "/system/etc/fstab.required";
    }
    INIT_ERROR_CHECK(access(fstabFile, F_OK) == 0, abort(), "Failed get fstab.required");
    fstab = ReadFstabFromFile(fstabFile, false);
    INIT_ERROR_CHECK(fstab != NULL, abort(), "Read fstab file \" %s \" failed\n", fstabFile);

找不到fstab.required。

搜索out目录:fstab.required存在于./rk3568/packages/phone/ramdisk/etc/fstab.required中。

由此可以看出,找不到fstab.required。是因为ramdisk.img没有加载成功。

我们发现,在打开了ramdisk后,ramdisk.img是打包在了boot_linux.img中的。如下:

root@wuhphis03349:~/ohos/openHarmony/3.1-release/out/rk3568/packages/phone/images/temp# ls
extlinux  logo.bmp  logo_kernel.bmp  lost+found
t@wuhphis03349:~/ohos/openHarmony/3.1-release/out/rk3568/packages/phone/images/temp/extlinux# ls
extlinux.conf  Image  ramdisk.img  toybrick.dtb
root@wuhphis03349:~/ohos/openHarmony/3.1-release/out/rk3568/packages/phone/images/temp/extlinux# cat extlinux.conf
label rockchip-kernel-5.10
    kernel /extlinux/Image
    fdt /extlinux/toybrick.dtb
    initrd /extlinux/ramdisk.img
  append earlycon=uart8250,mmio32,0xfe660000 root=PARTUUID=614e0000-0000-4b53-8000-1d28000054a9 rw rootwait rootfstype=ext4
​

initrd 使用的就是ramdisk.img

那boot_linux.img我们并没有用到,boot使用的是firefly编译出的kernel。

我们的解决办法就是要把ramdisk.img移植到firefly的boot.img中。

ramdisk.img在kernel里面是存在的,直接替换就可以。

然后编译、下载。发现不再崩溃,启动日志如下:

…………
[    1.872984] Run /init as init process
[    1.878187] [pid=1][INIT][INFO] [init.c:225)] DISABLE_INIT_TWO_STAGES not defined
…………
[    2.525787] BEGET[pid=1][INIT][INFO] [fstab_mount.c:331)] Mount /dev/block/platform/fe310000.sdhci/by-name/rootfs to /usr successful
[    2.525821] BEGET[pid=1][INIT][ERROR] [fstab_mount.c:299)] Unsupported file system " none "
[    2.653223] phy phy-fe8a0000.usb2-phy.8: charger = USB_CDP_CHARGER
[    3.033396] EXT4-fs (mmcblk0p6): mounted filesystem without journal. Opts: barrier=1
[    3.033517] BEGET[pid=1][INIT][INFO] [fstab_mount.c:331)] Mount /dev/block/platform/fe310000.sdhci/by-name/oem to /vendor successful
…………

 

6 知识分享

OpenHarmony ramdisk 简要介绍:

ramdisk是在正式文件系统挂载之前,为OS提供一些基础能力。通过设置root=/dev/ram0,把ramdisk挂载成一个根文件系统,在ramdisk里面,可以做一些前期准备工作。在OpenHarmony当中,打开ramdisk后,init会执行二次启动。第一次启动ramdisk中的init,并通过执行/etc/fstab.required,完成对system、vendor、userdata等挂载,然后切换根文件系统,再次执行init,完成OpenHarmony相关服务的启动。目前ramdisk功能有限,后期会不断优化,提升系统的启动效率。

Logo

社区规范:仅讨论OpenHarmony相关问题。

更多推荐