启动链路与分区—【万物智能之开源鸿蒙OpenHarmony系统实战开发系列教程】
串口开着,上电后字是一行一行出来的。今天顺着启动链路走:卡在哪一行,对应哪一张分区,不要先改驱动。


屏停在 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。
约束:
- 分区名
boot_linux不能改。 U-Bootbootrkp硬编码找它。改成boot/kernel,失败可以很安静。 boot_linux:bootable的:bootable要留。 它参与distro_bootpart这类逻辑。userdata:grow的:grow要去掉。 否则 GPT 分区名变成字面量userdata:grow,内核找不到userdata。- userdata 偏移不能超出介质。 公版
0x01308000大约对应 9.77 GB,8 GB eMMC 上这个分区不存在,报Could not find userdata part。往前收到紧挨上一个分区的位置。 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
更多推荐

所有评论(0)