1. 为什么要在VMware里跑VxWorks 6.9
1.1 这套组合到底能干什么
先说结论:在VMware里跑VxWorks 6.9,最大的价值是你手里可以没有一块真实的x86开发板,就能把VxWorks的编译、烧写、启动、网络通信、任务调试这一整条开发链路全部打通。
VxWorks 6.9是风河公司非常经典的一套实时操作系统版本,一直到今天,还有大量工业控制、电力、轨道交通、医疗设备、航空航天相关的旧项目跑在它上面。这些项目往往维护周期特别长,几个人的小团队要同时维护好几个老产品,而老型号的x86目标板早就停产了。这时候VMware就派上用场了。
我的实际感受是,VMware把虚拟化做得足够“透明”:它模拟出来的x86处理器、中断控制器、串口、网卡等硬件,对VxWorks来说就是一块标准PC主板。VxWorks的x86 BSP本来就支持这些通用设备,所以只要配置得当,VxWorks 6.9完全可以在虚拟机里正常启动,并且稳定跑任务。
这套组合适合三类人:一是刚入门VxWorks、想找个便宜环境练手的嵌入式初学者;二是老项目维护工程师,需要复现客户现场问题但手边没有目标机;三是在做持续集成或者自动化测试的团队,想用虚拟机批量跑VxWorks镜像做回归验证。
1.2 虚拟机方案和真实开发板的差异
很多刚从Linux或单片机转过来的朋友,容易把虚拟机里跑RTOS想得过于轻松,一上来就想“把镜像拖进去就能开机”。实际上VxWorks不像Windows那样有完整的BIOS引导链和文件系统,它对目标板硬件依赖非常强,尤其是网卡驱动、串口地址、中断号这些细节。
在真实开发板上,BSP厂商已经把硬件配置固化好了;而在VMware里,你要主动去“将就”虚拟机的硬件。换句话说,虚拟机的好处是硬件可调整、可复现,坏处是硬件参数得自己去对齐VxWorks的BSP配置。
还有一个容易踩坑的点:VxWorks没有“驱动自动识别”的概念。它不像Linux那样启动时会枚举PCI设备并自动加载对应驱动。VxWorks用的是静态配置的驱动表——你必须在编译镜像时就把需要的网卡驱动、串口驱动选进去,并且告诉bootrom“启动设备叫fei还是el还是其他名字”。这块搞不定,虚拟机里的VxWorks基本就是“能启动但等于废了”。而一旦你把网络和串口打通了,后面用Workbench连接Target Server做调试,比真机还要舒服,因为不怕断电、不怕接线松动、随时可以快照回滚。
1.3 开始之前要具备的底子
我不是劝退,但建议你先确认下面几项基础,否则看后面的内容会有点吃力:
- C语言和基本编译流程要熟,VxWorks工程里组件配置、链接脚本这些概念和裸机开发不一样。
- 对x86架构的启动过程、内存分布有个大概概念。比如引导行里要写内存基址,你得知道它对应的是什么含义。
- 至少用过一次VMware Workstation,能自己创建普通虚拟机。
- 能理解“目标机”和“宿主机”的关系:VxWorks跑在目标机(虚拟机),开发环境Workbench跑在宿主机。
下面我按我实际做过一遍的流程来写,尽量把容易卡住的地方都点出来。
2. 环境搭建:先让宿主机这边准备好
2.1 VMware版本和虚拟机创建要点
先说宿主机平台。Windows和Linux都可以,但我建议新手用Windows加VMware Workstation Pro,教程和排错经验最多。Workstation Pro现在已经对个人用户免费了,不用在密钥上动太多心思,官方下载安装即可。如果手头还是老版本,Workstation 15/16也都能用,后面我会讲版本兼容问题。
创建虚拟机时,几个容易忽视的选项我单独说一下:
- “客户机操作系统”不要选Windows或Linux。在Workstation里一般找不到VxWorks选项,可以直接选“其他”或“其他 64 位”(取决于你的VxWorks镜像是32位还是64位,多数6.9工程是32位,选“其他”即可)。这个选项不影响开机,只是为了给VMware一个参考。
- 内存建议给512MB到1GB。VxWorks本身很小,十几MB的镜像就能跑,但如果你要在目标机上跑比较重的测试任务,给1GB比较稳。这里提醒一句:VxWorks镜像里通常会配置内存池大小,虚拟机的物理内存只是“物理内存上限”,VxWorks实际用的是你自己在启动行或内核配置里指定的内存范围。
- 硬盘可以给,也可以不给。如果用FTP从网络下载镜像启动,虚拟硬盘不是必须的。但Workstation在创建向导里会强制让你选“创建虚拟磁盘”,这个没关系,创建好之后如果不需要可以移除。
网络适配器的选择很关键,这一步直接决定VxWorks里能不能看到网卡。VxWorks 6.9常见的x86 BSP网络驱动,很多对应的是Intel PRO/100(设备名fei)或者老式3Com网卡(设备名el),也有BSP里带了Intel PRO/1000或AMD PCNet的驱动。所以在虚拟机的网络适配器设置里,建议优先试“e1000”或传统“PCnet”类型,不同版本的Workstation叫法略有不同。实际测试中,我见过有些BSP在e1000上能起来,有些反而PCnet更稳。这个没有统一答案,按你手上的BSP覆盖的驱动来选即可。
2.2 虚拟串口设置:调试的核心通道
在VxWorks开发里,串口控制台的优先级非常高,甚至比网络调试还高。原因很简单:网络驱动出问题时,你还能看到bootrom打印的串口日志;反过来如果你只依赖网络,一旦启动阶段网络没起来,你连目标机发生了什么都不知道。
VMware给虚拟机加串口的方法并不复杂,在虚拟机设置里选择“添加设备”->“串行端口”,然后选择“使用命名管道”。Windows下命名管道一般写成\\.\pipe\com_1这样的形式。
关键配置有两处:
- 连接模式选择“另一端是应用程序”。这样VMware会把虚拟串口暴露成一个管道,宿主机上的串口终端软件可以通过这个管道读写数据。
- 勾选“接通电源时连接”。否则每次启动虚拟机都要手动去勾选,容易忘。
宿主机侧我用的是PuTTY。新建连接时选择“Serial”,在Serial line框里填\\.\pipe\com_1,Speed填115200,数据位8、停止位1、无校验,打开连接。这样虚拟机的VxWorks串口输出就会实时出现在PuTTY窗口里,同时你在PuTTY里输入命令也能进VxWorks shell。这套串口通道是整个调试过程里最可靠的观察窗口。
2.3 Workbench 3.x安装和许可处理
VxWorks 6.9对应的开发环境是Wind River Workbench 3.2或3.3,基于Eclipse做的IDE。安装过程本身不复杂,但有两个常见问题。
一是Workbench的许可(License)服务。它一般依赖Wind River License Manager,可能是本地License文件也可能是网络许可服务器。安装完成后记得检查环境变量WIND_LICENSE_FILE是否正确指向许可文件或服务器地址。否则Workbench可以打开,但一编译就报license错误。
二是Workbench版本和主机操作系统兼容性。Workbench 3.x年代比较早,在较新的Windows 10/11上偶尔会有界面显示错乱或启动卡住的情况。一个比较有效的办法是用兼容性模式运行,或者直接在虚拟机里再套一层Windows 7/10来装Workbench。虽然套两层虚拟机听起来很绕,但好处是环境隔离,Workbench不会被宿主机各种环境变量干扰。
Workbench安装完成后,还有两个“辅助角色”需要准备:FTP/TFTP服务器和串口终端。FTP服务器后面专门讲,串口终端就是上面说的PuTTY。等这些都就绪,宿主机侧的工作就算做完了。
3. 构建VxWorks 6.9镜像:BSP、组件和启动行
3.1 新建工程时BSP怎么选
打开Workbench之后,新建项目,你会看到VxWorks Image Project、VxWorks Boot Loader Project、Downloadable Kernel Module Project等选项。这块我直接说结论:
- VxWorks Boot Loader Project:用来生成bootrom,也就是引导程序。它负责在目标机上电后做基础初始化,然后通过网络从宿主机下载真正的VxWorks镜像。
- VxWorks Image Project:用来生成vxWorks镜像本身,也就是操作系统主体。
- Downloadable Kernel Module Project:生成可动态加载的模块(.o文件),类似应用代码,编译后通过Target Shell或Target Server加载到运行中的VxWorks里。
开发时通常先建Boot Loader工程,再建Image工程,或者直接用一个配置了“Boot ROM”选项的Image工程同时输出两部分。为了少绕弯子,我建议分开建。
选BSP的时候,在工程向导里会列出许多BSP模板。VMware环境首选带x86字样的通用BSP。这相当于是VxWorks对“标准PC”的适配包。如果找不到明确的x86类别,就看它支持的网卡驱动和串口配置是否有Intel 8259中断控制器、8254定时器、16550串口这些典型PC设备。这些都是VMware模拟出的基础硬件。
3.2 需要显式勾选的组件
VxWorks 6.9的镜像裁剪非常细,组件没选对,后面调试会很难受。我列一个最小集合,这些都是你在Image Project里要重点检查的:
- 网络协议栈组件。VxWorks 6.9里通常是“INET”或“IPNET”组件,二选一。一般BSP会根据目标板自动带一个,你不必纠结,但如果镜像里连
ifconfig命令都没有,大概率是这层组件没选全。 - FTP Client组件。bootrom下载镜像要走FTP协议,Image里如果你想在运行时也用FTP传输文件,同样需要勾上。
- WDB Agent组件。这是Workbench远程调试的核心,必须选上,并且要配置成网络模式或串口模式。网络模式下要记住目标机端口号,默认一般是1534。
- Target Shell组件。也就是目标机上的命令行解释器,启动后你能通过串口或网络敲命令,全靠它。
- Host Shell组件。在宿主机Workbench侧使用的shell,通过Target Server和目标机交互。
组件配置面板里会有依赖关系提示,勾选缺依赖时会有警告。刚开始不用怕多勾,镜像大点无所谓的,等跑通了再回头裁剪。
3.3 bootline启动行逐项解析
VxWorks启动行是最容易把人搞晕的地方,我尽量把它讲透。bootline是一串用空格分隔的参数,告诉bootrom从哪里下载镜像、自己的IP是多少、宿主机IP是多少、用什么协议下载。常见格式类似下面这样:
fei(0,0)host:vxWorks h=192.168.1.100 e=192.168.1.99:ffffff00 u=target pw=target f=0x0各段含义如下:
fei(0,0):启动设备名。unit是0,参数是0。这里的fei是你BSP里网卡驱动的名字,不同BSP差别很大,也可能是el(0,0)、e1000(0,0)、pcnet(0,0)。host:vxWorks:要下载的文件路径。这里是FTP服务器上的相对路径,vxWorks表示根目录下的vxWorks文件。h=192.168.1.100:宿主机IP,即FTP服务器地址。e=192.168.1.99:ffffff00:目标机(虚拟机)IP和子网掩码,掩码要写成十六进制。u=target pw=target:FTP登录账号密码。VxWorks默认的FTP下载账号经常是target/target。f=0x0:启动标志,0表示正常启动,具体位数可查BSP文档。
配置启动行的位置有两种。一种是在Boot Loader工程里打开bootrom配置,把启动行编译进bootrom;另一种是在bootrom启动时手动输入,它会提示你boot device、host name、file name等,逐项输入后确认即可。手工输入的好处是不用反复编译,改IP很方便,但每次重启目标机都要重新敲一遍。调试阶段我建议用手工输入,正式固化时再编译进去。
3.4 三种常见输出文件的区别
工程构建完成后,你会在输出目录里看到多个文件,常见的有vxWorks、vxWorks_rom、bootrom等。初学者容易搞混,我简单区分:
vxWorks:ELF格式的VxWorks内核镜像,不能直接裸机启动,通常由bootrom下载到内存后运行,或者由Workbench下载运行。bootrom:引导程序镜像,启动后初始化硬件,然后根据bootline下载vxWorks并跳转执行。vxWorks_rom:自带启动代码的VxWorks镜像,可以直接从ROM/Flash执行,一般烧到板子的Flash里用。
在VMware环境中最常用的路线是:bootrom做一个可引导软盘镜像,vxWorks放在宿主机FTP服务器上,目标机从虚拟软盘启动bootrom,bootrom再从FTP拉取vxWorks到内存运行。
关于内存的位置有一点要提醒:bootrom下载镜像时会有默认加载地址,比如0x100000或0x300000,这个地址必须和VxWorks镜像编译时的链接地址一致。如果你改了链接脚本,记得同步检查。默认情况下,直接用BSP自带的配置,一般不大会错。
4. 让目标机跑起来:FTP下载与串口观察
4.1 在宿主机上搭FTP服务器
VxWorks 6.9年代的bootrom,用的是比较老的FTP客户端逻辑,所以服务器选型要保守一点。我用过FileZilla Server,也用过一些绿色小型FTP工具,只要满足三点就行:
- 支持普通FTP协议,不要强制加密或TLS。
- 能自定义账号密码。就按启动行里的
u=target pw=target建一个用户。 - 能设置被动/主动模式。VxWorks老客户端有些在主动模式工作更正常,如果下载卡住,优先切一下FTP服务器的主动被动模式试。
然后把构建出来的vxWorks文件放到FTP服务器的根目录,确保能用Windows资源管理器以target账号登录并看到这个文件。
防火墙方面,Workstation的虚拟网卡走的是宿主机的真实网络,所以Windows防火墙要放行FTP相关端口(主要是21和20)。这一步不做好,表现就是bootrom里“Loading …”之后一直转圈,最后报超时。
4.2 制作带bootrom的可引导介质
这一步我做成功的是“把bootrom写进虚拟软盘镜像”的方案。主要流程是:
- 在Workbench的Boot Loader工程里,先确认生成了
bootrom文件。 - 在宿主机上准备一个1.44MB的软盘镜像文件(flp或img都可以)。Windows下可以直接用WinImage创建并写入,或者如果你手边有Linux,用
dd写也方便。 - 把bootrom写到软盘镜像的引导扇区起始位置。
- 回到Workstation,在虚拟机设置里给目标机添加“软盘驱动器”,指向这个软盘镜像,并勾选“启动时连接”。
- 调整虚拟机的BIOS启动顺序,确保软驱优先于其他设备。
这里我多提两句:为什么不是直接用CD-ROM引导?因为VxWorks bootrom的格式跟普通光盘引导格式不兼容,做成ISO大概率起不来。软盘镜像是最贴近老式嵌入式开发习惯的方式,很多老工程师当年就是这么调目标板的。如果你的Workbench或BSP工具里提供了专门的软盘镜像制作脚本,那就更方便,直接生成镜像挂到虚拟软驱即可。
启动目标机后,PuTTY串口窗口里应该能看到bootrom打印信息,例如内存自检、网络协商等,然后出现启动行输入提示。确认启动行里的h、e、文件路径正确,bootrom就会开始从FTP下载。
4.3 看到VxWorks启动日志就相当于成功了一半
当bootrom完成FTP下载后,它会跳到VxWorks镜像的入口地址。串口上会打印出类似Attaching network interface ... done、ADDING 2588 SYMBOL TABLE、Starting at 0x...之类的信息,最后进入Target Shell,出现->提示符。
到了这一步,说明VxWorks的内核已经在虚拟机的CPU上跑起来了。你可以在->后面敲help、i、taskShow等命令验证。i显示所有任务的状态,taskShow看更详细的任务信息。这些命令正常工作,说明内核的调度器、内存管理、定时器都起来了。
一个常见误区是:看到“Starting at ...”就以为系统完全启动成功了,结果Shell不响应。这种情况多半是控制台串口参数不对,比如波特率不匹配,或者bootline里指定的console设备不是当前虚拟串口。VxWorks默认控制台波特率常见的就9600和115200两种,如果PuTTY里全是乱码,先切一下波特率试试,别急着怀疑镜像坏了。
5. Workbench远程调试:Target Server和Shell连接
5.1 创建Target Server连接
目标机起来之后,接下来就是把Workbench连上去了。Workbench连接目标机的桥梁叫Target Server,它通过WDB协议和目标机上的WDB Agent通信。
在Workbench里打开Target Server配置界面,新建连接时关键参数有:
- 连接方式:网络或串口。网络方式最常见,选“Network”。
- 目标机IP地址:填虚拟机里VxWorks的IP,也就是bootline里
e=后面的地址。 - 目标机端口:默认是1534。这个端口是WDB Agent监听用的,如果连接不上,优先确认目标机上WDB Agent组件是否真的在运行。
- 字节序:x86平台是Little Endian,默认就是,不用改。
配置完成后点击连接。如果连接成功,Workbench底部的“Target Console”窗口会打开,你可以在宿主机上直接操作目标机的Shell。同时,Workbench的调试视图里会列出目标机上的任务列表,双击任务就能看它的栈和寄存器信息。
5.2 用串口帮你排查网络连接问题
第一次做连接时,网络连接失败是常有的事。我的排查顺序是:
- 先在PuTTY串口里确认目标机IP是否真的起来了。执行
ifconfig查看网卡状态,如果网卡没起来,Target Server连不上是很正常的。 - 然后在宿主机上ping目标机IP,能ping通说明二层三层都通。
- 如果宿主机ping不通目标机,去检查VMware的网络适配器模式。建议用桥接模式或仅主机模式,这两种模式宿主和目标机之间最直接。使用NAT模式时,目标机虽然能出网,但宿主机访问目标机的1534端口偶尔会有别扭。
- 再检查Workbench侧的防火墙,尤其是Windows宿主机自带的Defender防火墙,很可能把Workbench的WDB连接拦掉。
这里想特别强调一下串口窗口的价值:不论网络怎么折腾,串口那一头永远能看到VxWorks的实际状态。我遇到过很多次网络配置看起来都对,但目标机就是没起来,最后串口一看,原来bootline里网卡设备名写错了,VxWorks根本就没绑定网络设备。串口日志是定位这种问题的钥匙。
5.3 用好Target Shell和内存窗口
等Target Server稳定连接后,调试效率会比纯串口高很多。你可以在Workbench的Target Shell里直接调用C函数、查看全局变量,甚至可以动态下载应用模块。
举个例子,你编译了一个可下载的内核模块,比如一个操作GPIO或串口收发的小驱动,Workbench的连接建立之后,可以通过Target Shell或Launch配置把这个模块加载到目标机内存里,马上就能调用它的函数。这比反复把整个镜像重新下载一遍要快得多。
内存窗口也很实用。开发老项目时经常要核对寄存器值、检查内存缓冲区,在Workbench里直接打开Memory视图,输入地址,就能实时看到内存内容。这是真机调试很难做到那么直观的。
6. 常见问题与避坑实录
6.1 FTP下载失败或下载后重启
这是环境搭建阶段遇到最多的问题。典型症状是bootrom串口打印出Loading ...之后长时间不动,最终超时失败。排查时按优先级看三件事:
- FTP账号密码和启动行
u=、pw=是否一致。 h=宿主机IP是否真能访问到FTP服务。- 防火墙是否放行20和21端口。
还有一种情况是下载成功了,但bootrom跳转执行后立刻重启,像个死循环。这通常不是镜像坏了,而是下载到的vxWorks镜像和bootrom的链接地址或内存布局不匹配。你可以先用同一个BSP工程分别构建bootrom和vxWorks,保证两者来源一致,一般能解决。
6.2 启动后网络接口没起来
串口上能看到ifconfig命令,但执行后显示设备不存在。这个问题几乎都是网卡驱动没选对。
前面说过,VMware虚拟网卡类型和VxWorks BSP的驱动要匹配。如果你的启动行里写的是fei(0,0),但BSP实际支持的网卡驱动不叫这个名字,那么bootrom阶段可能还能勉强跑,但Image阶段没有对应驱动,网络就断了。解决办法是回到BSP配置里查看网卡驱动列表,然后到VMware设置里换成对应的虚拟网卡型号。
我在实际测试中用过的组合:某款x86 BSP搭配VMware的e1000虚拟网卡,启动行为e1000(0,0)。但请注意,换一个BSP组合就完全可能不一样,所以先查BSP文档再改VMware配置。
6.3 VMware版本和硬件兼容性玄学
VxWorks 6.9是十几年前的产品,新版VMware Workstation的虚拟硬件更新了很多,有个别版本在古老的BSP上会出现中断异常、定时器不准、串口丢字符等奇怪问题。
我的经验是:当出现“看起来都配对了但就是不稳定”的情况,可以尝试把虚拟机的硬件兼容性调低。在VMware里,虚拟机的“兼容性”设置可以选Workstation 8、10、12等更老的版本。我遇到过一次串口输出断断续续的情况,把兼容性从Workstation 17往下调到Workstation 12后就好了。这个操作不复杂,就在虚拟机设置的高级选项里。
6.4 Workbench连接不上目标机
Target Server一直显示连接超时,但目标机串口Shell是好的,网络也能ping通。这时候要检查目标机上的WDB Agent到底有没有绑定到网络。
VxWorks 6.9的WDB Agent也是组件化配置的,如果只勾选了串口WDB,那目标机根本不会监听1534端口。处理办法是回到Image工程里,同时打开网络WDB组件,并配置WDB的监听端口。配置完成后重新构建镜像,再走一遍bootrom下载流程就行。
另外,如果目标机开启了防火墙组件(VxWorks里也有防火墙基础组件),也要确保1534端口被放行。不做这一步,网络通但连接不了的情况会一直出现。
7. 折腾完这一圈,我的几点体感
这套VxWorks 6.9加VMware的环境,我前前后后帮人搭过不少次。最耗时的从来不是编译,而是“硬件识别”这个环节。VxWorks这种静态配置风格的RTOS,和现在习惯“即插即用”的开发思维差异很大。你把启动行当成是给目标机写的自我介绍,把BSP当成是硬件驱动的一张静态清单,思路就顺了。
如果你第一次跑通,我建议别急着继续往下做业务开发,先把几件小事练熟:用串口执行Shell命令、用Workbench加载一个模块、通过Target Shell调用函数、学会看内存窗口。这几个动作每样五分钟,但熟练之后,后面写应用代码时效率会高很多。
最后分享一个我在虚拟机环境里特别喜欢的操作:给目标机做快照。在VxWorks启动并完成FTP下载后,如果系统状态正常,给虚拟机做一个快照。后面开发过程中把目标机搞挂了,直接从快照恢复,十秒钟回到稳定状态,比在真机上反复重新烧写痛快太多了。希望这份流程能让你少走点弯路。