当前位置:首页 > 悦禧新闻 > rk3506 burildroot系统目录地图:从源码树到板子上的分区

rk3506 burildroot系统目录地图:从源码树到板子上的分区

顶层有 7 个符号链接,它们才是对外暴露的入口;真正的框架代码集中在 device/rockchip/common/。构建产物全部落在 output/,而 rockdev/ 只是它的另一个名字。文末会把参数文件(512 字节扇区)与实际启动参数(字节)的换算核对一遍,确认这条链路没有断点。

拿到一份 Rockchip SDK,第一眼看到的是十几个顶层目录。它们并不都是"源码"——有的是构建框架,有的是配置,有的纯粹是产物中转站。分不清这三类,后面找源码、找配置、找产物都容易走错。

一、顶层全景

先按用途分组,比按字母顺序看要清晰得多:

分组 目录 职责
构建框架 device/rockchip/ 板级配置与构建框架本体
源码 u-boot/ 引导加载器
kernel-6.1/ Linux 内核
buildroot/ 根文件系统构建系统
rtos/、hal/ RT-Thread 与硬件抽象层(AMP 双系统用)
yocto/ 另一条 rootfs 构建线
rootfs/ Ubuntu rootfs 的预置镜像
上层组件 app/ 应用代码(rkadk、lvgl_demo)
external/ 官方与第三方组件(rkscript、recovery、rkwifibt…)
prebuilts/ 预编译的交叉工具链
rkbin/ Rockchip 二进制(DDR 初始化、Loader 等)
tools/ 主机侧工具(linux/mac/windows)
产物 output/ 全部构建产物
文档 docs/ 及各类 *_series/ 说明与教程

一个快速的规模感:u-boot/ 有 65 个一级条目、buildroot/ 35 个、rtos/ 24 个——都是完整的上游项目原样收编,SDK 自己的工作集中在 device/rockchip/。

二、七个符号链接:伪装成文件的入口

顶层看到的 build.sh、Makefile、kernel 这些,没有一个是真实文件,全是符号链接:

build.sh -> device/rockchip/common/scripts/build.shMakefile -> device/rockchip/common/MakefileREADME.md -> device/rockchip/common/README.mdrkflash.sh -> device/rockchip/common/scripts/rkflash.shcommon -> device/rockchip/commonkernel -> kernel-6.1rockdev -> output/firmware

这样安排有两个好处:命令都在顶层敲(./build.sh、make),而实现和配置集中在 device/rockchip/,整个 SDK 是多仓库拼起来的,顶层只保留统一入口。

其中 kernel -> kernel-6.1 这个链接值得注意:内核目录带版本号,链接名不带。以后内核升级到 6.6,只需要改链接指向,build.sh 里的路径不用动。

注意:正因为 build.sh 是符号链接,git status 里看到的修改会出现在 device/rockchip/common/scripts/ 下,而不是顶层。改构建脚本时不要找错位置。

三、device/rockchip/:三层职责

这个目录是 SDK 真正"自己写"的部分,内部又分三层:

device/rockchip/├── common/ # 构建框架:与芯片无关的通用逻辑│ ├── build-hooks/ # 分阶段的构建钩子(00-config ~ 99-all)│ ├── post-hooks/ # 根文件系统后期处理│ ├── scripts/ # build.sh 本体与各 mk-*.sh│ ├── configs/ # Kconfig 定义│ ├── overlays/ # 通用 rootfs overlay│ └── kconfig/ # 配置系统├── .chips/│ └── rk3506/ # 芯片相关:板级 defconfig、parameter、its└── .chip -> .chips/rk3506 # "当前选中的芯片"

common/ 处理"怎么构建",.chips/ <芯片> / 处理"构建成什么样"。 两者的分界线很干净:换一块别的 Rockchip 板子,common/ 基本不动,改的是 .chips/ 下的配置。

.chip 这个链接是"当前芯片"的指针。构建脚本里大量使用 $RK_CHIP_DIR,展开就是 device/rockchip/.chip,也就是当前芯片目录。切芯片本质上是改这个链接。

四、output/:产物都去哪了

所有构建产物都在 output/ 下,一次构建之后的结构:

output/├── .config # SDK 级配置(RK_* 变量)├── defconfig -> ../device/rockchip/.chips/rk3506/
    <板级 defconfig>├── sessions/ # 每次构建的日志与环境快照├── firmware/ # 最终可烧录镜像├── buildroot/ # buildroot 的完整输出├── recovery/ # recovery 镜像├── extra-parts/ # oem / userdata 分区镜像└── update/ # update.img

其中 sessions/ 是排查构建问题时最该先看的地方。每次构建会新建一个以时间戳命名的目录:

output/sessions/2026-09-26_20-22-17/├── 99-all-build_
    <时间戳>
     .
     log 
     # 顶层构建日志
    ├── br-rockchip_rk3506_
    <时间戳>
     .
     log
     # buildroot 的完整日志
    ├── build_
    <时间戳>
     .
     log
    ├── .config # 本次构建用的配置快照├── initial.env / final.env # 构建前后的环境变量快照└── part-table # 本次算出的分区表

initial.env 和 final.env 特别有用——它们记录了本次构建实际生效的所有 RK_* 变量,比看 .config 更直接,能确认某个开关有没有真的传下去。

五、rockdev 与 output/firmware:同一个目录

rockdev -> output/firmware

两个名字指向同一个地方。rockdev/ 是 Rockchip 工具链的历史习惯用法(烧录工具默认从这里取镜像),output/firmware/ 是新的组织方式,用链接保持兼容。

这个目录里的内容有个特点:全是符号链接,没有一个是真实文件。

$ls-l output/firmware/boot.img -> ../../kernel-6.1/zboot.imguboot.img -> ../../u-boot/uboot.imgMiniLoaderAll.bin -> ../../u-boot/rk3506_spl_loader_v1.06.111.binrootfs.img -> ../../buildroot/output/rockchip_rk3506/images/rootfs.ubirecovery.img -> ../recovery/ramboot.imgparameter.txt -> ../../device/rockchip/.chips/rk3506/parameter-flash.txtoem.img -> ../extra-parts/oem.imguserdata.img -> ../extra-parts/userdata.imgupdate.img -> ../update/Image/update.imgmisc.img -> ../misc.img

这样设计的好处是产物只有一份。rootfs.img 永远指向最新构建出来的 rootfs.ubi,不存在"rockdev 里是旧的、buildroot 里是新的"这种同步问题。烧录工具读 rockdev/,拿到的就是最新产物。

六、从构建产物到板子上的分区

把上面的链路接到板子上。参数文件来自:

$ grep RK_PARAMETER output/.configRK_PARAMETER="parameter-flash.txt"

对应 device/rockchip/.chips/rk3506/parameter-flash.txt,里面的分区定义长这样:

CMDLINE:mtdparts=:0x00003000@0x00002000(uboot),0x00000800@0x00005000(misc),...

注意单位——参数文件用 512 字节扇区。而在板上看到的实际启动参数是字节:

$cat /proc/cmdline... mtdparts=spi-nand0:0x600000@0x400000(uboot),0x100000@0xa00000(misc),...

中间的换算由 device/rockchip/common/scripts/partition-helper 完成:

rk_partition_size_sector_to_readable(){SIZE=$(( $1 *512))...

核对一遍(扇区 × 512 = 字节):

分区 参数文件(扇区) 换算后 板上实测
uboot 0x3000 @ 0x2000 0x600000 @ 0x400000 0x600000 @ 0x400000
boot 0x5000 @ 0xEA00 0xa00000 @ 0x1d40000 0xa00000 @ 0x1d40000
rootfs 0x50000 @ 0x13A00 0xa000000 @ 0x2740000 0xa000000 @ 0x2740000
oem 0x8000 @ 0x63A00 0x1000000 @ 0xc740000 0x1000000 @ 0xc740000

最后一行的 userdata 在参数文件里写的是 -@0x0006BA00(userdata:grow)——- 表示"占满剩余空间",所以在板上看到的是一个具体数值(0x2820000)。

wKgZO2rELkqAYDcLAAES-eDkm2I617.png

上板确认分区确实如参数文件所定义:

$cat/proc/mtddev: size erasesize namemtd0: 00600000 00020000"uboot"mtd1: 00100000 00020000"misc"mtd2: 00040000 00020000"vnvm"mtd3: 01200000 00020000"recovery"mtd4: 00a00000 00020000"boot"mtd5: 0a000000 00020000"rootfs"mtd6: 01000000 00020000"oem"mtd7: 02820000 00020000"userdata"

挂载情况也对应得上:

ubi0:rootfs / ubifs rw ← rootfs.img/dev/ubi6_0 /oem ubifs rw ← oem.img/dev/ubi7_0 /userdata ubifs rw ← userdata.img

rootfs、oem、userdata 三个分区都是 UBIFS 挂在 UBI 卷上,其余(uboot、misc、boot、recovery)是裸分区。这一点决定了它们后续的升级方式不同。

三者的挂载方式还不一样。rootfs 由内核直接挂(cmdline 里的 ubi.mtd=5 root=ubi0:rootfs),另外两个是靠 /etc/fstab 里的这两行:

PARTLABEL=oem /oem ubifs defaults 02PARTLABEL=userdata /userdata ubifs defaults 02

这里的 PARTLABEL= 不是普通的设备路径写法,SDK 提供了一套挂载辅助脚本处理它。开机链路是:

/etc/init.d/S00mountall.sh → mount-helper → . disk-helper → ubiattach +mount

其中 disk-helper 负责把 MTD 分区挂成 UBI 设备:

ubiattach /dev/ubi_ctrl -m$PART_NO-d$PART_NO||return1

源码都在 external/rkscript/ 下(S00mountall.sh、mount-helper、disk-helper),板上对应 /etc/init.d/S00mountall.sh 和 /bin/ 下的两个 helper。

注意:PARTLABEL=oem 这种写法依赖 mount-helper 在中间转换。如果自己手写 fstab 挂 UBI 分区,直接用 PARTLABEL= 是不生效的,得走同样的 helper 或者自己 ubiattach。

七、开发者视角:想改什么,去哪个目录

前面讲的是"这个 SDK 长什么样",这一节换成"要动手时该找谁"。按最常见的三类需求整理。

7.1 按需求定位

需求 位置
改板级配置(分区表、内核配置名、rootfs 类型) device/rockchip/.chips/ <芯片> /*_defconfig
改配置项的定义与默认值 device/rockchip/common/configs/Config.in*
改构建的某个阶段做什么 device/rockchip/common/build-hooks/NN-*.sh
往 rootfs 里加文件 chip 级 overlay:device/rockchip/.chip/overlays/rootfs/ <名字> /
加一个应用或组件 app/ 或 external/,再进 bconfig 打开
找可烧录的镜像 output/firmware/(也就是 rockdev/)
查构建日志 output/sessions/ <时间戳> /

7.2 三个最常用的自查命令

不确定当前是"什么状态"时,这三条能快速定位:

# 1. 当前用的是哪块板子的配置readlinkoutput/defconfig &&readlinkdevice/rockchip/.chip
# 2. 本次构建实际生效的全部 RK_* 变量catoutput/sessions/latest/final.env
# 3. 产物的真实来源(反查断链)ls-l output/firmware/

第 2 条特别有用。output/.config 里存的是 Kconfig 表达式(会出现 ${...} 未展开的情况),而 final.env 是构建时 env 的快照,值是展开后的,不会有歧义。

7.3 排查:链接断了说明什么

output/firmware/ 里全是符号链接,所以"某个镜像不存在"有两种表现:链接指过去报了断链,或者链接压根没生成。

$ls-l output/firmware/boot.img -> ../../kernel-6.1/zboot.imgrootfs.img -> ../../buildroot/output/rockchip_rk3506/images/rootfs.ubi...

沿着链接读一次就能定位到具体是哪个部件没产出:

readlink-f output/firmware/rootfs.img

如果返回空或报错,说明 rootfs.ubi 不存在——对应的是 rootfs 构建阶段没跑成功,直接去看 output/sessions/latest/ 里 rootfs 相关的日志。

常见几种:

症状 原因方向
xxx.img 是断链 对应模块没构建成功,去看该模块的日志
output/firmware/ 目录本身为空 还没跑过 ./build.sh firmware,或构建在更早的阶段就失败了
rockdev/ 不存在 它是 output/firmware/ 的链接,cleanall 会删掉它,跑一次构建会重建
镜像时间戳是旧的 那次构建没有重新产出该部件,./build.sh <部件名> 单独重建

7.4 扩展:加一个芯片目录

如果要支持一颗新的 Rockchip 芯片,按现在的结构只需要:

  1. 在 device/rockchip/.chips/ 下新建以芯片命名的目录
  2. 放入该芯片的板级 *_defconfig、parameter-*.txt、*.its
  3. ./build.sh chip: <新芯片名> 切换过去

common/ 下的构建框架与芯片无关,不需要动。这也是这个目录结构最大的价值——加芯片是加目录,不是改代码。

八、小结

  • 顶层 7 个符号链接是对外入口,实现在 device/rockchip/ 下
  • device/rockchip/common/ 管"怎么构建",.chips/ <芯片> / 管"构建成什么样",.chip 链接指向当前芯片
  • 所有产物在 output/;rockdev/ 是 output/firmware/ 的别名,里面全是符号链接,保证产物只有一份
  • 排构建问题先看 output/sessions/ <时间戳> /,initial.env 能确认配置是否真的生效
  • 参数文件用 512 字节扇区,到板子上是字节,换算是 partition-helper 做的