串口开着,上电后字是一行一行出来的。今天顺着启动链路走:卡在哪一行,对应哪一张分区,不要先改驱动。

屏停在 logo 上,你改 RenderService、改 launcher、改设备树,二十分钟一轮,现象不变。串口其实早就把死亡地点写出来了:有的停在 write training result,有的停在 Cannot find partition 'boot_linux',有的 16 秒 wait for file ... dwmmc,有的 22 秒桌面起来了又自己关屏。这些不是同一种「起不来」。启动是一条严格串行的管子,每一节读一张不同的分区。管子在哪一节断,改后面的分区没有用。

产品名 rk3568_evb。内核 Linux 5.10 aarch64,用户态 32 位 musl。hardware 名 rk30board

上电
 → MiniLoaderAll.bin     DDR 训练、把 U-Boot 搬进内存
 → uboot.img             读 GPT(parameter.txt 写进的那张表)
 → resource 分区         logo.bmp + rk-kernel.dtb
 → boot_linux 分区       ext2:Image + extlinux.conf + ramdisk
 → 内核 + ramdisk        一阶段 init,读 fstab.required
 → 挂 /usr /vendor       二阶段 init,读 fstab.rk30board
 → system + 一堆 SA      foundation、render_service、launcher
 → 桌面                  然后可能被 SuspendController 关屏

官方启动流程偏通用:启动子系统。下面按这块 RK3568 板上实际读的分区写。


1. 用死亡时间认管子断在哪

大约时间 串口关键字 断在哪 该动哪张镜像
0~1 s,反复训练 `write training result` 之后没 `out` MiniLoader / DDR MiniLoaderAll.bin,整包
1~2 s `Cannot find partition 'boot_linux'` U-Boot 找分区,常去 eMMC 先 USB 刷 eMMC 的 GPT + p5
2 s 有 logo,无内核 `FATAL error: cannot load boot_linux` p5 空或不是 ext2 boot_linux.img
内核起,~16 s panic `wait for file .../fe2b0000.dwmmc/by-name/system` ramdisk 的 fstab.required 和介质错配 ramdisk / 整包
~16 s `Failed to exec "/bin/init"`,然后 `FreeRootDir` 没加载 ramdisk,或 fstab.required 缺 boot_linux 里的 extlinux.conf
~58 s `/data` 挂不上,`ExecReboot` fstab.rk30board 错,或 vendor 没在一阶段挂上 vendor.img
动画播完,再过十几秒屏黑 `KeventFbNotifierFn:blank=4` SuspendController timeout system 里的 power_suspend.json
卡 logo,串口能敲命令 无 render_service,或它退了 图形栈 / SystemUI vendor GPU 库、system

启动不会「同时」暴露两个错。16 秒那关过了,才会让你看见 58 秒那关。所以修启动问题按时间往下走,不要看见黑屏就改 dts。


2. MiniLoader:DDR 版本比容量口号重要

上电之后还没有 U-Boot。芯片 BootROM 从介质开头取出 MiniLoaderAll.bin,里面嵌着 DDR 训练固件。训练过了,才把 uboot.img 搬进内存。

串口这一段大致是:

DDR V1.16 6f71c736ce 1056MHz
0x0
...
SRX
U-Boot 2017.09 ...

4 GB 核心板,公版 MiniLoader 经常是 DDR V1.10 @ 1560 MHz。写训练打完就停:

write training result

没有 out,没有 U-Boot,没有 Linux。看起来像内存坏了。换一块 2 GB 板可能能起,于是有人下结论「开源鸿蒙标准系统必须 4 GB / 1 GB 跑不动桌面」。后半句被证伪过:2 GB 板 MemAvailable 足够出桌面。真因是 loader 频率和这份颗粒不对付。

刷之前看镜像里的二进制:

strings out/rk3568_evb/packages/phone/images/MiniLoaderAll.bin | grep -E 'DDR|V1\.' | head

期望 V1.16。合成用 rkbin 的 boot_merger,不是改内核 sdram_rk3568.c——那份是空 stub,RK3568 容量由预编译 bin 探测。

# 在 rkbin 目录,示例。ini 文件名按你的包
cd /path/to/rkbin
# RKBOOT/RK3568MINIALL.ini 里两处 FlashData / CODE471
# rk3568_ddr_1560MHz_v1.16.bin  →  rk3568_ddr_1056MHz_v1.16.bin
./tools/boot_merger RKBOOT/RK3568MINIALL.ini
# 产出 MiniLoaderAll.bin
strings MiniLoaderAll.bin | grep DDR
cp MiniLoaderAll.bin \
  /path/to/OpenHarmony/device/board/rk/rk3568_evb/loader/MiniLoaderAll.bin
cp MiniLoaderAll.bin \
  /path/to/OpenHarmony/out/rk3568_evb/packages/phone/images/MiniLoaderAll.bin

还挂,再降到 780 MHz 那档固件。SDDiskTool 从磁盘 0 扇区写,会覆盖卡上旧 loader。卡以前能起 4 GB,刷一份带 V1.10 的包之后就不能起,是这个覆盖,不是颗粒突然坏了。

Maskrom 进不去、完全没字,先确认 3.3 V / 5 V 到了 SoC。MiniLoader 是芯片行为,没电就不会枚举 ROCKUSB,也不会打 DDR 日志。


3. U-Boot 和 parameter.txt:分区名是契约

MiniLoader 把控制权交给 uboot.img。U-Boot 读 GPT。GPT 是打包时按 parameter.txt 写进去的。CMDLINE 里那串 mtdparts= 看起来像 NAND,在 eMMC/SD 上同样当分区表用。

一份能用的骨架(扇区数按你板的容量改,userdata 起始必须落在真实容量内):

FIRMWARE_VER: 1.0.0
MACHINE_MODEL: RK3568
MACHINE_ID: 007
MANUFACTURER: RK3568
MAGIC: 0x5041524B
ATAG: 0x00200800
MACHINE: 0xffffffff
CHECK_MASK: 0x80
PWR_HLD: 0,0,A,0,1
TYPE: GPT
CMDLINE: mtdparts=rk29xxnand:0x00002000@0x00004000(uboot),0x00002000@0x00006000(misc),0x00003000@0x00008000(resource),0x00030000@0x0000B000(boot_linux:bootable),0x00002000@0x0003B000(backup),0x00002000@0x0003D000(bootctrl),0x00300000@0x0003F000(system),0x00080000@0x0033F000(vendor),0x00020000@0x003BF000(sys_prod),0x00020000@0x003DF000(chip_prod),0x00020000@0x003FF000(updater),0x00002000@0x0041F000(chip_ckm),0x00020000@0x00421000(eng_system),0x00002000@0x00441000(eng_chipset),0x006BE000@0x00443000(userdata)
uuid:rootfs=614e0000-0000-4b53-8000-1d28000054a9

数字是示例。你树上那份才是权威。要盯的是名字和几个 flag,不是把示例扇区抄进 8 GB 的 eMMC。

约束:

  1. 分区名 boot_linux 不能改。 U-Boot bootrkp 硬编码找它。改成 boot / kernel,失败可以很安静。
  2. boot_linux:bootable 的 :bootable 要留。 它参与 distro_bootpart 这类逻辑。
  3. userdata:grow 的 :grow 要去掉。 否则 GPT 分区名变成字面量 userdata:grow,内核找不到 userdata
  4. userdata 偏移不能超出介质。 公版 0x01308000 大约对应 9.77 GB,8 GB eMMC 上这个分区不存在,报 Could not find userdata part。往前收到紧挨上一个分区的位置。
  5. package-file 第一列必须和括号里的名字一致。 一边写 rootfs 一边写 system,对应镜像不会被写进整包。

U-Boot 停下来可以手探:

=> mmc list
=> mmc dev 0
=> part list mmc 0
=> mmc dev 1
=> part list mmc 1

Cannot find partition 'boot_linux' 时,先 part list 看当前 mmc dev 是 0 还是 1。很多底板的 U-Boot 默认去 mmc 0(eMMC) 找,即便拨码拨在 SD。eMMC 空,这里就死。先 USB 整包刷 eMMC,再谈 SD 启动。

misc 分区非零,U-Boot 可能进 recovery。打包用全零 misc.img。怀疑时:

=> mmc read $loadaddr <misc起始扇区> 0x80
=> md.b $loadaddr 0x100

全零才正常。单分区日常不要 dd misc,除非你知道自己在清它。


4. resource:logo 和真正生效的 dtb

U-Boot 从 resource 分区(p4) 取出:

rk-kernel.dtb
logo.bmp
logo_kernel.bmp

logo 是 U-Boot 画的,不是内核画的。所以:

  • 换开机画面,刷 p4,不必动 Image
  • 改 dts,真正被内核用的是这份 rk-kernel.dtb,不是 boot_linux 里那份 toybrick.dtb

resource.img 是 RSCE 包,用 resource_tool 打:

resource_tool --pack --image=resource.img \
   rk-kernel.dtb logo.bmp logo_kernel.bmp

build_kernel.sh / make-ohos.sh 会做这一步,并把 resource.img 拷到 out/rk3568_evb/packages/phone/images/。换 logo 后若没删旧 resource.img,脚本可能复用缓存,打包目录里 bmp 是新的、产物仍是旧的。强制:

rm -f out/kernel/src_tmp/linux-5.10/resource.img \
     out/rk3568_evb/packages/phone/images/resource.img

U-Boot 常从 eMMC 取 resource。SD 启动改 dts,mmcblk0p4 和 mmcblk1p4 都写。刷机那篇把命令写死了。

解包验证:

mkdir -p /tmp/res && cd /tmp/res
resource_tool --unpack --image=/path/to/resource.img
dtc -I dtb -O dts rk-kernel.dtb 2>/dev/null | grep -A4 'serial@fdd50000'

板上 /proc/device-tree 对不上这次 dts,先问 p4 刷了没有,再问 U-Boot 取的是哪块盘的 p4。


5. boot_linux:ext2 里的 Image 和 ramdisk

p5 是一张 ext2。U-Boot bootrkp 认这个格式。典型布局:

/Image                      aarch64 内核
/extlinux/extlinux.conf
/extlinux/ramdisk.img       一阶段 initramfs
/extlinux/toybrick.dtb      常有,开机主 dtb 仍是 resource 那份
/logo.bmp                   常有,开机不读

extlinux.conf 必须有 initrd:

label OpenHarmony
   kernel /Image
   initrd /extlinux/ramdisk.img
   append  ... console=ttyS2,1500000n8 androidboot.hardware=rk30board ...

缺 initrd 这一行,U-Boot 不把 ramdisk 交给内核。内核用 root=PARTUUID=... 直接把 system 分区当根。一阶段 init 调 SwitchRoot("/usr"),system 根上没有 /usr 这个挂载点目录的预期结构,stat("/usr") 失败,于是 FreeRootDir 把 system 分区上的文件删光,再 exec("/bin/init") 得到 ENOENT,panic。

这是启动链里最贵的错:每次开机破坏 system,只能重刷。编完先验:

debugfs -R 'cat /extlinux/extlinux.conf' \
   out/rk3568_evb/packages/phone/images/boot_linux.img

看不到 initrd,不要交付。

khdf 的 HCS 烤进内核 Image,不在这张 ext2 的某个 conf 里。改 khdf = 重编 Image = 重打 boot_linux。改 dts 仍要同时刷 resource。

只改 dts、Image 没变时,可以只重编 dtb、重打 ext2(最小重建那篇),但 p4 还是要刷,否则 U-Boot 交出去的还是旧 dtb。


6. ramdisk 和 fstab.required:一阶段

内核解开 ramdisk 当根,跑里面的 /bin/init(32 位 musl)。它读 etc/fstab.required,把标了 required 的分区挂到新根。典型四条:

/dev/block/platform/fe2b0000.dwmmc/by-name/system     /usr       ext4  ro  wait,required
/dev/block/platform/fe2b0000.dwmmc/by-name/vendor     /vendor    ext4  ro  wait,required
/dev/block/platform/fe2b0000.dwmmc/by-name/sys_prod   /sys_prod  ext4  ro  wait,required
/dev/block/platform/fe2b0000.dwmmc/by-name/chip_prod  /chip_prod ext4  ro  wait,required

eMMC 把 fe2b0000.dwmmc 换成 fe310000.sdhci

vendor 必须是 required 只有 wait,一阶段不挂它。SwitchRoot 之后二阶段立刻找 /vendor/etc/fstab.rk30board,找不到,/data 永不挂,后面所有写 /data 的服务失败。

ramdisk 里还要有挂载点目录 /usr /vendor /sys_prod /chip_prod,否则 MountToNewTarget 失败。

fstab 和介质错配,串口大约 16 秒:

wait for file /dev/block/platform/fe2b0000.dwmmc/by-name/system
...
Failed to exec "/bin/init", err=2
Kernel panic - Attempted to kill init!

ueventd 已经按真实控制器建好了 fe310000.sdhci/by-name/...,fstab 却去 dwmmc 下面等。等 5 秒超时,/usr 没挂上,二阶段的 init 路径不存在。

fstab.required 来自 device/board/rk/rk3568_evb/cfg/install_images = ["ramdisk"]。改它不必重编内核,必须重打 ramdisk,并且确认 boot_linux 里那份 ramdisk 也更新了——有的打包把 ramdisk 再拷进 ext2。两处都 grep:

debugfs -R 'cat /etc/fstab.required' \
   out/rk3568_evb/packages/phone/images/ramdisk.img
debugfs -R 'cat /extlinux/ramdisk.img' \
   out/rk3568_evb/packages/phone/images/boot_linux.img > /tmp/rd.img
# ramdisk.img 常是 gzip cpio,具体格式按 file 输出再解
file out/rk3568_evb/packages/phone/images/ramdisk.img

7. vendor 和 fstab.rk30board:二阶段

SwitchRoot 之后,init 读:

import /vendor/etc/init.${ohos.boot.hardware}.cfg
mount_fstab /vendor/etc/fstab.${ohos.boot.hardware}

ohos.boot.hardware=rk30board,所以只认:

/vendor/etc/init.rk30board.cfg
/vendor/etc/fstab.rk30board

fstab.rk3568 是死文件。fstab.rk30board 负责 userdata → /data、misc 等。控制器名必须和一阶段同一介质。只改 required、忘了 rk30board,16 秒那关过了,大约 58 秒:

mount .../fe2b0000.dwmmc/by-name/userdata on /data failed
write_updater ...
ExecReboot panic

/data 没有,所有依赖 data 的 SA 起不来,init 认为关键服务死了,重启。userdata 分区在介质上是存在的(mmcblk0p15 / mmcblk1p15),首挂为空会 fsck/format,这是正常的。找不到的是 fstab 指错了控制器,不是分区没做出来。

init.rk30board.cfg 里放 start console、chmod 节点、自启服务。改它进 vendor.img。

vendor 还装着 uhdf 的 hdf_default.hcb、GPU 和相机 so。config.json 若没把芯片产品配进 VDI/GPU 列表,render_service 会退,串口正常、屏停 logo。那是图形栈,不是启动管子本身,但死亡时间会和「卡 logo」混在一起。先确认 ps | grep render_service


8. system:桌面,以及首启那次关屏

system 分区挂到 /usr 再 switch 成 /。foundation、窗口、SystemUI、launcher、Settings、powermgr 都在这里。用户态 32 位,/system/bin/init 的 interpreter 是 musl-arm。

正常时间线(2/4 GB、屏那路 okay):

0 s     DDR + U-Boot
2 s     logo(resource)
8 s     内核 dmesg
15 s    bootanimation
25 s    动画退,桌面图标
30 s    hdc list targets 有设备号

有一种「进不去桌面」是假的。动画播完,launcher、foundation、render_service 都在,wms.fullscreen.ready 也打了。再过大约十几秒,屏黑。复位又能看到动画,然后又黑。

电源服务的 SuspendController 读 power_suspend.json 里的 "timeout" 源:这么多秒没人点屏,当用户走开,关屏。首启要装一堆预装 hap,CPU 忙,你盯着串口,没人摸触摸,计时器到点必关。重启后你若碰巧点了一下,计时器被清掉,又能亮很久——看起来偶发,首启无人操作时是必然。

日志:

KeventFbNotifierFn:blank=4
receive display off event
DevmgrServicePowerStateChange:suspend state 1
HdfTouchDriverDozeSuspend

临时:摸触摸,或按电源键。永久:删掉 /system 那份 json 里的 timeout 块。

{
 "power_suspend": {
   "sources": [
     { "name": "lid" },
     { "name": "timeout", "value": 15 }
   ]
 }
}

把 timeout 那个对象整段删掉。源码在 base/powermgr/power_manager/services/native/profile/power_suspend.json,装到 /system/etc/power_config/power_suspend.json

丢一份到 /vendor/etc/power_config/ 无效。加载函数 GetOneCfgFile("etc/power_config/power_suspend.json") 只搜 /system:/chipset:/sys_prod:/chip_prod,命中即返回,/vendor 不在列表里。改完重打 system.img。

displayOff=-1 也救不了。运行时 DisplayOffTime 取自 settings 数据库,不是编译默认。首启数据库里是有限值。

这和 16 秒 panic、58 秒 ExecReboot、DDR 训练失败,都不是一类。串口能敲命令、ps 里有 launcher,再考虑关屏。


9. 把整条管子画成「谁读哪张盘」

BootROM        介质 0 扇区附近的 MiniLoader
MiniLoader     uboot 分区
U-Boot         GPT(来自 parameter.txt)
              resource p4   → logo + rk-kernel.dtb
              boot_linux p5 → Image + ramdisk
内核           ramdisk 里的 init + fstab.required
一阶段 init    system p7 → /usr
              vendor p8 → /vendor     (必须 required)
二阶段 init    /vendor/etc/fstab.rk30board
              userdata p15 → /data
              /vendor/etc/init.rk30board.cfg
SA / 桌面      system 上的二进制 + vendor 上的 HAL/so
Suspend        /system/etc/power_config/power_suspend.json

by-name 软链在运行时指向 eMMC 的 pN,不管当前根在哪。一阶段 fstab 写的却是 platform/<控制器>/by-name/...,走的是控制器下面那份 by-name,和 /dev/block/by-name 不是同一组节点。所以 fstab 必须写对控制器;你自己 dd 时不要用 /dev/block/by-name

boot_devices=fe2b0000.dwmmc,fe310000.sdhci 写在 cmdline 里,是候选列表,两个都列正常。真正决定挂哪块盘的是两份 fstab。


10. 一次对照:从串口日志对到分区

把一次失败的串口保存下来,按出现的第一句致命错误对:

# 主机上
grep -nE 'DDR|U-Boot|boot_linux|Starting kernel|wait for file|FreeRootDir|ExecReboot|blank=4|render_service' uart.log | head -40
第一句 动作
停在 DDR,无 U-Boot 换 V1.16 MiniLoader,整包刷,SDDiskTool 也会覆盖 loader
`Cannot find partition 'boot_linux'` 刷 eMMC GPT + p4 + p5
kernel panic 16s dwmmc/sdhci grep 两份 fstab,重打 ramdisk 和 vendor,出完 eMMC 改回 SD
FreeRootDir / exec init ENOENT 查 extlinux.conf 的 initrd、ramdisk 是否进了 boot_linux
58s ExecReboot fstab.rk30board、vendor 是否 required
blank=4 删 system 的 timeout;先摸一下屏确认桌面其实在
无 render_service vendor 的 GPU/VDI、SystemUI 签名,不是 loader

不要在 DDR 失败时改 dts,不要在 16 秒 panic 时改 launcher。管子是串行的。

主机上可以把这份 grep 做成脚本,丢进日志目录随手跑:

#!/usr/bin/env bash
# classify_uart.sh uart.log
set -euo pipefail
log=${1:?usage: $0 uart.log}

hit() { grep -E "$1" "$log" >/dev/null && echo "$2"; }

hit 'write training result'              'DDR: MiniLoader 频率/版本,看 strings MiniLoaderAll.bin'
hit 'Cannot find partition .boot_linux'  'U-Boot: eMMC 无 GPT/p5,USB 整包刷 eMMC'
hit 'wait for file .*dwmmc'              'ramdisk: fstab.required 还是 SD 路径,当前介质是 eMMC'
hit 'wait for file .*sdhci'              'ramdisk: fstab.required 还是 eMMC 路径,当前介质是 SD'
hit 'FreeRootDir|Failed to exec .*/bin/init' 'extlinux 缺 initrd,或 ramdisk 没有 fstab.required'
hit 'ExecReboot|Could not find userdata' 'vendor: fstab.rk30board / userdata 偏移 / vendor 未 required'
hit 'blank=4|display off event'          'system: SuspendController timeout,桌面其实在'
hit 'render_service'                     '查它是否立刻退了:vendor GPU 库、SystemUI'

if ! grep -q 'Starting kernel' "$log"; then
   echo '内核没起来:问题在 MiniLoader / U-Boot / boot_linux,不要改 system'
fi
if grep -q 'Starting kernel' "$log" && ! grep -q 'wms.fullscreen.ready' "$log"; then
   echo '内核起来了但没到窗口就绪:fstab / init / 图形栈'
fi

10.1 console 和 hardware 后缀,写进生效的那份 cfg

二阶段会 import /vendor/etc/init.rk30board.cfg。调试口要能敲命令,boot 段里得有 start console。骨架:

# device/board/rk/rk3568_evb/cfg/init.rk30board.cfg
on boot
   start console
   chmod 0666 /dev/ttyS0 /dev/ttyS3 /dev/ttyS7 /dev/ttyS8
   chmod 0666 /dev/i2c-1 /dev/i2c-2
   restorecon /dev/ttyS0 /dev/ttyS7 /dev/i2c-1

on property:ohos.boot.completed=true
   # 自启服务写这里,服务名还要进高权限进程白名单
   start your_board_daemon

写在 init.rk3568.cfg 里等于没写。验板上:

# ls -l /vendor/etc/init.rk30board.cfg /vendor/etc/fstab.rk30board
# grep 'start console' /vendor/etc/init.rk30board.cfg
# param get ohos.boot.hardware
rk30board

hardware 不是 rk30board,整份 cfg 不会被 import,console、chmod、自启一起消失。先对 cmdline 里的 androidboot.hardware,再改 cfg。


11. 失败判断

4 GB 板刷完没字。 loader 版本。strings MiniLoaderAll.bin | grep DDR

同一张 SD 换一块核心板就不能起。 新板 eMMC 空,U-Boot 去 eMMC 找 boot_linux。先 USB 刷 eMMC。

logo 新、设备树旧。 刷了带新 logo 的 resource,dtb 仍是旧的——打 resource 时用了旧 dtb。或反过来。解包看 rk-kernel.dtb

每次开机 system 里的文件消失。 缺 initrd。立刻停,修 extlinux.conf,重刷 system。继续开机等于反复格式化自己。

16s / 58s 切换着出现。 两个 fstab 改了一份。一次 grep 全改。

首启黑屏,重启后正常。 timeout 关屏。不是「偶发硬件」。

parameter 里 userdata 越界。 小容量 eMMC。算扇区,不要抄 16 GB 板的表。

misc 非零进 recovery。 换全零 misc,或整包。

从 loader 到桌面,中间没有魔法。每一段对应一张分区、一份配置、一种串口口吻。认准口吻,再决定刷哪一张。


系列第 11 篇 · 芯片:瑞芯微 RK3568 · OpenHarmony 4.1(API 11) · Linux 5.10

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐