rk3506 burildroot系统目录地图:从源码树到板子上的分区
- 悦禧新闻
- 2026-10-15
- 5232
顶层有 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)。
上板确认分区确实如参数文件所定义:
$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 芯片,按现在的结构只需要:
- 在 device/rockchip/.chips/ 下新建以芯片命名的目录
- 放入该芯片的板级 *_defconfig、parameter-*.txt、*.its
- ./build.sh chip: <新芯片名> 切换过去 新芯片名>
common/ 下的构建框架与芯片无关,不需要动。这也是这个目录结构最大的价值——加芯片是加目录,不是改代码。
八、小结
- 顶层 7 个符号链接是对外入口,实现在 device/rockchip/ 下
- device/rockchip/common/ 管"怎么构建",.chips/ <芯片> / 管"构建成什么样",.chip 链接指向当前芯片 芯片>
- 所有产物在 output/;rockdev/ 是 output/firmware/ 的别名,里面全是符号链接,保证产物只有一份
- 排构建问题先看 output/sessions/ <时间戳> /,initial.env 能确认配置是否真的生效 时间戳>
- 参数文件用 512 字节扇区,到板子上是字节,换算是 partition-helper 做的






