
简介面向Cavium CN68XX系列MIPS处理器的VxWorks6.9 BSP资源包专为需要在多核MIPS i64R2架构上快速搭建嵌入式系统的开发者设计。包内提供完整的板级支持包覆盖启动引导、中断处理、内存管理、设备驱动、文件系统及网络协议栈等关键模块可直接作为系统移植和驱动开发的参考基线。资源共28个文件以C源码和汇编文件为核心辅以CDF配置、头文件、Makefile及README说明压缩包仅107KB结构紧凑、便于按需查阅。内容涉及处理器初始化、时钟与RTC驱动、Flash映射等具体实现细节能帮助开发者快速掌握CN68XX平台的硬件抽象层与驱动编写思路。目前已有148人学习下载适合嵌入式BSP开发工程师、VxWorks学习者及基于CN68XX平台的项目团队参考使用。1. 一次存量固件升级把 cav_cn68xx_mipsi64r2sf 从归档变成了刚需设备在现网跑了六七年供应商停产固件停在旧 SDK。要加一个报文过滤逻辑手上只有当年归档的cav_cn68xx_mipsi64r2sf.zip没有源码工程也没有构建脚本。这时候最要紧的不是重写业务而是先确认这个压缩包里的交叉工具链还能不能在 x86 宿主上跑起来能不能编出和现网二进制同款 ABI 的产物。这个包名字里带着处理器型号、指令集修订号和浮点标记拆开看就是一次完整的交叉编译环境交付。这篇就围绕怎么拆、怎么自检、怎么编、怎么验证来展开适合做网络设备维护或 BSP 移植的工程师参考。2. 解析压缩包命名CN68xx 处理器与 MIPS64r2 在交叉编译里的关系拿到cav_cn68xx_mipsi64r2sf.zip先别急着解压。文件名里的信息足够我们判断这套工具链面向什么硬件、什么指令集、什么 ABI 约束这些直接决定后面的 CFLAGS 和链接参数怎么写。2.1 先分清 ISA 修订MIPS64r2 与 r1、r6 的关键差异r2指的是 MIPS64 Release 2这是 MIPS 指令集架构的一个修订版本。相比 Release 1r2 引入了几条关键指令和特性比如rotr/rotrv循环移位指令、ext/ins位段提取插入指令、seh/seb符号扩展指令以及更高效的乘累加指令形式。这些指令在报文头解析、校验和计算这类场景里能省下不少指令周期所以 Cavium Octeon 系列的 SDK 工具链长期默认使用 r2 作为基线。要注意的是r2 和后来推广的 MIPS32r6/MIPS64r6 完全不兼容。r6 把分支延迟槽去掉了很多指令编码重排jalr行为也变了二进制层面的差异比你想象中大得多。如果你的目标设备是 CN68xx板上跑的是基于 Octeon SDK 的旧内核那编译器选了-marchr6编出来的用户态程序会直接触发非法指令异常。常见做法是先把-march锁在octeon或octeon2上不要用纯 ISA 名去编。MIPS64r2 还规定了 64 位通用寄存器、64 位寻址能力和 32 位/64 位两种 ABI 切换。CN68xx 这类网络处理器跑数据面时通常希望程序能用上 64 位地址空间同时又要兼容旧库所以 ABI 一般选 n64而不是 n32 或 o32。n64 ABI 下long是 64 位int还是 32 位结构体对齐规则也和 o32 不同混编时很容易出问题。2.2 i64 与 r2sf 的歧义靠 ELF 头验证而不是猜名字命名里的i64和sf在不同 SDK 里含义不完全统一。i64多数情况下指 internal 64-bit 核心即 Octeon 家族内部整数核而非带有 DSP 扩展的变体但也有包把i理解为 interleaved memory。sf则有两种主流解释soft-float软浮点或 single-float单精度硬浮点。Octeon 早期 SDK 的交叉工具链为了通用性默认启用软浮点所以r2sf更贴近 Release 2 soft-float 的组合。这意味着什么如果你在代码里写了double运算软浮点工具链不会生成硬件浮点指令而是调用__adddf3这类 libgcc 软浮点库函数。性能上虽然慢但兼容性最好因为 1000 系列到 6800 系列不同步进的核心浮点单元实现差异很大软浮点规避了这个问题。但也正因为如此你不能拿一个mips64-octeon-linux-gnu前缀默认去和硬浮点第三方库混链接。想确认工具链默认到底是不是软浮点最好先编一个带double的小程序看汇编里有没有lwc1/swc1指令。端序问题更值得重视。MIPS 架构天生支持双端Octeon 处理器在硬件上也能配置但 Linux 用户态工具链通常固定一端。文件名没写el还是eb那就不能假设解压后直接对编译器产的临时文件跑readelf -h看Data字段是little endian还是big endian。我见过不止一次因为端序假设反了把大端工具链编出的模块塞进小端系统的惨案。提示压缩包文件名只能作为搜索线索最终以 ELF 头的Machine、Data、Flags三个字段为准。后面第 5 章会给具体命令。2.3 CN68xx 在网络处理器产品线里的定位CN68xx 是 Cavium Octeon 家族里偏中高端的成员面向 10G/40G 线速报文处理片内集成多核 MIPS64 处理器、硬件加速单元压缩、加密、正则匹配和丰富的高速 I/O。从软件角度看它和同系列其他型号共享同一套 SDK 框架区别主要在核数、缓存大小和加速引擎的通道数。下表是同一 SDK 下常见型号的大致差异型号方向面向场景工具链选型关注点CN63xx 系列低密度接入、边缘汇聚老内核-marchocteon更稳CN66xx 系列中等密度业务网关兼容octeon2指令子集CN68xx 系列10G 线速处理、深度检测主要用octeon2注意 L2 cache 行为实际开发里CN68xx 的 BSP 通常附带 U-Boot、Linux 内核补丁和用户态库。压缩包里的工具链需要能编出在板卡 Linux 上直接运行的 ELF因此 sysroot 里必须带全套 glibc 和内核头文件而不是像 x86 桌面开发那样依赖宿主系统库。这也是为什么拿到cav_cn68xx_mipsi64r2sf.zip之后首先要看 sysroot 完整不完整。3. 在 x86 宿主机上部署交叉工具链解压、环境变量与自检命令工具链这东西解压到哪个路径、环境变量怎么配、前缀叫什么直接影响后续所有 Makefile。我一般先把它放到/opt/toolchains/下面路径里不带空格和中文避免make里各种隐式规则出幺蛾子。3.1 解压后的目录体检bin、libexec、sysroot 谁管什么解压完先看顶层目录结构。一个可用的交叉工具链包通常包含这几个部分unzip cav_cn68xx_mipsi64r2sf.zip -d /opt/toolchains/ cd /opt/toolchains/ find . -maxdepth 2 -type d | sort运行后你会看到类似这样的布局目录典型内容作用bin/交叉编译器、汇编器、链接器、二进制工具命令行入口需加入 PATHlibexec/cc1、collect2等内部程序编译器驱动内部调用不需要手动执行lib/gcc/...libgcc 各版本库编译器运行时库链接时自动使用sysroot/glibc、内核头文件、libcrypt 等目标系统根文件系统的最小集合share/文档、man 页、GDB 脚本排错辅助如果sysroot缺失后面#include stdio.h都会失败因为编译器找不到目标平台的系统头文件。如果lib下缺少crt1.o那链接阶段会报cannot find crt1.o。先看这两处能避免后期白折腾。提示不要直接把 sysroot 指向你宿主机的/usr那样编译器会把 x86 的头文件和库送给 MIPS 后端结果必然是类型定义错乱。3.2 最小自检脚本识别编译器前缀与架构默认值工具链里编译器前缀是个关键信息。常见的可能是mips64-octeon-linux-gnu-但文件名没有明说所以要自己去bin/下确认。用一行命令列出所有以gcc结尾的可执行文件ls /opt/toolchains/bin/ | grep gcc$拿到前缀后写个极小的自检脚本确认它能编译能链接#!/bin/bash PREFIX/opt/toolchains/bin/mips64-octeon-linux-gnu cat /tmp/test.c EOF #include stdio.h int main(void) { printf(toolchain ok\n); return 0; } EOF ${PREFIX}-gcc -c /tmp/test.c -o /tmp/test.o ${PREFIX}-gcc /tmp/test.o -o /tmp/test.elf file /tmp/test.elf-c只编译不链接先通过这一步隔离语法和头文件问题第二次运行才进入链接阶段确认crt1.o、libc 这些 sysroot 里的基础件都在。file命令的输出会给出 ELF 位数、端序和指令集比如ELF 64-bit MSB还是ELF 64-bit LSB。如果file显示是MSB说明默认大端LSB是小端。这一行输出直接决定后续 Makefile 里要不要额外加-EL或-EB。3.3 验证 sysroot 与运行库用 -print-sysroot 和 -print-libgcc-file-name交叉编译器有几个隐藏路径没法靠which查出来要用自带的-print系列参数去问。下面几个最常用PREFIX/opt/toolchains/bin/mips64-octeon-linux-gnu ${PREFIX}-gcc -print-sysroot ${PREFIX}-gcc -print-libgcc-file-name ${PREFIX}-gcc -print-multi-lib ${PREFIX}-gcc -marchocteon2 -mabi64 -print-multi-directory-print-sysroot输出的是 sysroot 绝对路径-print-libgcc-file-name显示链接时会用到的 libgcc 位置。真正有价值的是-print-multi-lib它会列出编译器内置支持的所有 ABI/浮点组合。比如某行是lib64/octeon2;marchocteon2mabi64说明官方配置里已经为 octeon2 n64 准备好了多目录库。如果-print-sysroot输出为空而刚才的链接测试却通过了别高兴太早。这可能意味着编译器是按无 sysroot 的方式构建的头文件来自自身include-fixed库来自lib/gcc/...。这种工具链往往只能静态链接动态链接时会找不到目标板上的ld.so。尽早确认这点后面省得抓狂。4. 用 C 模块完整走一遍交叉编译CFLAGS、静态链接与 sysroot 协同工具链能跑只是第一步真正要面对的是编译参数怎么组合。交叉编译报错大多不是代码问题而是 CFLAGS、sysroot、链接方式三者没对齐。这一章用一个带实际意义的报文处理模块走完全过程。4.1 准备被测模块从空循环到带 I/O 的报文处理函数先写一个贴近真实场景的小模块。它从 buffer 里读一个伪报文头做简单的长度校验然后返回处理结果。代码故意不用平台库函数方便聚焦编译和链接参数/* pkt_check.c */ #include stdint.h #define PKT_OK 0 #define PKT_SHORT -1 int pkt_check(const uint8_t *pkt, uint32_t len) { if (!pkt || len 8) return PKT_SHORT; uint16_t proto (pkt[0] 8) | pkt[1]; uint32_t payload_len (pkt[4] 24) | (pkt[5] 16) | (pkt[6] 8) | pkt[7]; if (payload_len 8 len) return PKT_SHORT; return (int)proto; }这个函数用了位运算、移位、指针判空和整数回传没有调用任何 libc 函数也没有浮点运算。把它编成目标文件和静态库可以很好地隔离出工具链自身的代码生成能力。再把入口文件main.c调一下pkt_check用来测试最终链接。编译这段代码时函数内部payload_len 8 len的表达式涉及 32 位无符号整数相加MIPS64 后端会优先用 32 位算术指令而不是 64 位但如果 CFLAGS 里-mabi64和默认整型宽度配合不好可能多出多余的符号扩展指令浪费几个周期。这属于优化细节不影响正确性。4.2 推荐 CFLAGS 组合与参数逐项说明基于前面的分析代码用下面这组参数编译PREFIX/opt/toolchains/bin/mips64-octeon-linux-gnu CFLAGS-marchocteon2 -mabi64 -EL -msoft-float -O2 -Wa,-mno-branch-likely ${PREFIX}-gcc ${CFLAGS} -c pkt_check.c -o pkt_check.o ${PREFIX}-gcc ${CFLAGS} -c main.c -o main.o ${PREFIX}-gcc ${CFLAGS} -static pkt_check.o main.o -o pkt_check.elf逐项说明这组参数参数作用不设的后果-marchocteon2限定指令集为 Octeon 二代核心可能编出 CN68xx 硬件不支持的指令-mabi64采用 n64 ABIlong为 64 位默认 n32 时结构体布局全变-EL强制小端端序随工具链构建配置漂移-msoft-float浮点走软浮点库生成硬件浮点指令老芯片触发异常-O2标准优化不优化导致代码体积大、性能差-Wa,-mno-branch-likely汇编器层面禁用分支延迟槽推测指令内核若配置CPU_MIPS_...不支持则非法指令这里面-EL特别值得多说一句。很多交叉工具链在构建时固定了端序命令行不加-EL也能工作但如果 sysroot 里的 crt 文件或者 libgcc 是另一端编的链接时会莫名其妙报ELF class mismatch。显式指定-EL可以让编译器、汇编器、链接器都锁定在同一个端序视图下。-marchocteon2则是代码能在 CN68xx 上跑的基础Octeon 扩展指令里有一批专门针对报文处理的指令比如位提取、哈希辅助这些只有开对了 march 才可能被用到。提示-msoft-float与-mhard-float混用是交叉编译里最常见的 ABI 撕裂来源。一个编成 soft-float 的对象和一个编成 hard-float 的对象链接不会直接报错但运行时会因为浮点参数传递规则不同出现奇诡结果。4.3 链接阶段的选择静态链接还是依靠目标板动态库上一条命令里加-static是刻意的。对于现场维护场景静态链接最省心一个 ELF 拷上去就能跑不依赖目标板上的/lib/libc.so.1版本。CN68xx 板子的 rootfs 往往几年不更新动态库版本跟宿主编译环境的 glibc 版本对不上时cannot find -lc或运行时报No such file or directory就会交替出现。如果你确定目标板上动态库环境可控也可以去掉-static${PREFIX}-gcc ${CFLAGS} pkt_check.o main.o -o pkt_check_dyn.elf ${PREFIX}-readelf -l pkt_check_dyn.elf | grep interpreter第二行命令会看到类似Requesting program interpreter: /lib64/ld.so.1的输出。它就是动态链接器路径。目标板上这个路径必须真实存在且与 sysroot 里的布局一致否则程序一启动就报找不到链接器。另外去掉-static后编译器默认找的是 sysroot 里的.so库如果 sysroot 里只有.a需要加-Wl,-Bstatic或直接保持-static。动态库路径问题在网络设备上特别隐蔽。很多设备的/lib是个 symlink指向/usr/lib64或自定义分区跟 SDK 里 sysroot 的目录结构不完全一致。稳妥的做法是编完动态版后用readelf -d看NEEDED字段列出的依赖库再逐个去目标板上核对。4.4 三个常见报错与处理路径交叉编译阶段最常见的三个报错处理路径都相对固定第一类fatal error: stdio.h: No such file or directory。这说明 sysroot 的头文件路径没找到优先检查-print-sysroot的输出再看 sysroot 目录权限。不要急着加-I硬指宿主机的/usr/include那只会引来更多类型冲突。第二类undefined reference to __udivdi3。这是 64 位除法在 32 位参数环境下被拆成库调用导致的。一般在 MIPS 上少见因为 n64 ABI 下乘除指令足够支撑 64 位运算但如果你在代码里用了long long且工具链配置有缺漏就会冒出这个符号。解决方法是把除法改成移位版本或者确认 libgcc 完整。第三类relocation truncated to fit: R_MIPS_26 against ...。MIPS 跳转指令只有 26 位偏移代码段超过 256MB 时会触发这个错误。CN68xx 的用户态程序一般不常见但如果自己写的链接脚本把多个大段放一起就可能碰到。处理办法是把大函数拆小或者检查代码段 bss 是否需要放进单独 segment。5. 验证产物readelf、addr2line 与软浮点特征检查交叉编译完不算结束验证产物与目标平台的一致性才是避免上线事故的最后一道闸。别只依赖file命令它只是读 ELF 头信息不完整。我一般会连续跑三组检查把架构、浮点、崩溃定位一次看清。5.1 用 readelf -h 确认 Machine、Data 与 Flags先看头/opt/toolchains/bin/mips64-octeon-linux-gnu-readelf -h pkt_check.elf关注三个字段。Machine:应该是MIPS R2或类似描述代表真实指令集基线Data:如果是2s complement, little endian说明小端和你-EL参数一致Flags:这一行最关键n64 ABI 下会看到ABI64软浮点工具链通常额外可见SOFT_FLOAT。如果Flags里没有SOFT_FLOAT而是HARD_FLOAT说明刚才写的-msoft-float没有真正生效可能被工具链编译配置覆盖。这时候用第 4 章的汇编检查再确认一次最保险。5.2 用 addr2line 与 objdump 定位崩溃地址正常流程下设备上程序崩溃会打印类似pc0x12001234 ra0x12001278的异常现场。这时候交叉工具链里的addr2line能直接把地址还原成源码行号/opt/toolchains/bin/mips64-octeon-linux-gnu-addr2line -e pkt_check.elf -f 0x12001234输出会给出函数名和pkt_check.c:19这样的行号。如果显示??说明这个 ELF 编的时候没有带-g调试信息或者地址不在代码段。我一般会在-O2之外额外为现场保留-g编译调试信息dwarf 体积大一点但对定位问题价值极大。反汇编也是常用的互补手段objdump -d --show-raw-insn可以看指令编码当你怀疑工具链生成了不该出现的浮点指令时直接抓lwc1、swc1、mtc1这些助记符即可。5.3 软浮点与 ABI 检查用脚本批量扫描存量二进制还有一个容易漏掉的操作用readelf -A批量扫描目标板已经存在的存量二进制确认它用的浮点 ABI 到底跟新编出来的是否一致。简单的循环脚本就能办到for f in /path/to/rootfs/bin/*; do /opt/toolchains/bin/mips64-octeon-linux-gnu-readelf -A $f 2/dev/null \ | grep -q SOFT_FLOAT echo $f: soft || echo $f: other donereadelf -A里的Tag_GNU_MIPS_ABI_FP字段会明确标出Soft float或Hard float (double precision)。新老模块混跑时只要有一个硬浮点模块被软浮点主程序 dlopen 进来浮点参数传递就可能错位表现是偶发的 NaN 或参数吞掉。扫描这个字段比编译时看警告靠谱得多。最后把新的pkt_check.elf手动拷到设备上跑一遍确认退出码符合预期再看dmesg有没有留下非法指令的痕迹。这一步过去了这套cav_cn68xx_mipsi64r2sf才算是真正闭环。本文还有配套的精品资源点击获取