最近好几个做嵌入式移植的朋友跑来问我,VxWorks 6.9能不能在VMware上跑起来?我的回答是:能,而且配合Wind River Workbench做在线调试,比在真实板卡上还顺手。但这里有个前提——你千万别用装Windows、Ubuntu的思路去搞它。VxWorks不是拿来“安装”的,它是一套实时操作系统,正确的玩法是先让一个bootrom把内核拉起来,然后再通过串口或网络跟它交互。这篇教程是我在VMware Workstation 16 Pro上折腾VxWorks 6.9的完整记录,从虚拟机配置、启动镜像制作、串口终端连接、网络与Workbench调试,再到最终能跑起来的过程,全部展开写。准备把VxWorks放到虚拟化环境里做验证、做演示或者做CI构建的朋友,可以照着走一遍。
1. 先理清思路:虚拟机里的VxWorks为什么和普通系统不一样
1.1 VxWorks 6.9到底是什么,以及它适合跑在VMware上吗
VxWorks是风河(Wind River)旗下的实时操作系统,6.9这个版本在工业控制、网络设备、医疗仪器和航空航天里非常常见,至今还有大量存量项目。它的调度延迟低、内核可裁剪,能在极小的内存里运行,这些是Linux给不了的。
正因为它是嵌入式RTOS,很多开发者的惯性思维是“我能不能下个ISO镜像,然后在VMware里一步步安装”?答案是不能。VxWorks没有独立的安装程序,也没有包管理器。它不像Windows那样有“安装到磁盘”的概念,而是一个内核镜像通过引导加载器加载到内存里直接运行。你所谓的“装系统”,实际是把VxWorks镜像做成可引导介质,通过虚拟机的软驱、光驱或者网络启动。
VMware能不能跑VxWorks 6.9,取决于你拿到的BSP(Board Support Package,板级支持包)是否覆盖了x86体系结构。一般VxWorks 6.9安装目录下的target/config里会带x86或者pcPentium4这类BSP,它们的目标硬件就是PC兼容机,VMware虚拟出来的硬件也是PC兼容机,所以完全能跑。有不少人把它跑在QEMU里,但QEMU的默认设备模拟偏精简,某些中断控制器和时钟行为与VxWorks BSP预期差异较大,反而不如VMware省心。
1.2 引导链:bootrom和vxWorks镜像是两件事
在VxWorks的世界里,引导启动通常分两步。
第一步是bootrom。它是一段很精简的引导代码,负责初始化CPU、内存控制器、串口和最基本的网络接口,然后按照预设的bootline参数,从网络、磁盘或者内存中去加载真正的VxWorks内核镜像。bootrom很小,通常几十K到一两百K,当年之所以用软盘引导,就是因为它小到能塞进软盘。
第二步是vxWorks镜像。这就是真正的实时操作系统内核,加上你裁剪出的各种组件、驱动和应用程序。它在bootrom完成初始化之后被加载进内存,然后接管整个系统。
理解了这一步,你才能在VMware里做出正确的配置:虚拟机的BIOS要先从软驱或者光驱引导,加载bootrom;bootrom再从指定位置加载vxWorks镜像。很多人在虚拟机上卡住,是因为压根没有做这一步,他们打开虚拟机直接看到一片黑,以为系统坏了,其实只是没有引导层。
BSP在这里扮演的角色也很关键。它负责把VxWorks的内核抽象层和具体硬件绑定起来,比如串口地址、中断号、网卡驱动的注册、系统时钟的初始化等等。你选什么样的BSP,决定了你在VMware的虚拟机设置里该选什么网卡类型、什么串口参数。别一上来就默认用最新的设备型号,VxWorks 6.9的BSP往往是针对十年前的硬件写的,VMware默认给Linux虚拟机配置的VMXNET3、SATA硬盘这类现代虚拟设备,VxWorks反而可能认不出来。
2. 虚拟机配置的几个关键参数:软驱、串口、网卡缺一不可
2.1 创建虚拟机时先别急着选Linux模板
在VMware Workstation Pro里新建虚拟机时,很多人习惯性选“Ubuntu”或者“Other Linux 64-bit”模板,这会引入很多VxWorks根本用不到的设备。我的推荐是选“Other (64-bit)”或者“Other”,固件选BIOS,不要选UEFI。因为VxWorks 6.9的bootrom对UEFI引导支持本来就弱,你用UEFI去启动,很可能卡在启动阶段连bootrom都看不见。
硬件参数我实测下来这样配置比较稳:
| 配置项 | 推荐值 | 说明 |
|---|---|---|
| 内存 | 512MB ~ 2GB | VxWorks内核本身占用很低,给太多内存反而没有意义 |
| 处理器 | 1~2核 | 单核足够,多核需要配置多核支持组件,徒增复杂度 |
| 硬盘 | IDE 40GB | 不用太大,关键是控制器选IDE,SATA支持在6.9里比较弱 |
| 固件 | BIOS | 不要选UEFI |
| 软驱 | 手动添加 | 用于挂载bootrom镜像,这一步是关键 |
| 串口 | 手动添加命名管道 | 用于观察bootrom和VxWorks控制台输出 |
| 网卡 | e1000e | 兼容性好,VxWorks的Intel网卡驱动通常能识别 |
| 声卡/打印机 | 移除 | 完全用不上 |
在创建虚拟机的最后一步,点“自定义硬件”,里面把不需要的USB控制器、声卡、打印机都删掉,然后手动添加软盘驱动器、串口和网络适配器。VMware默认的新虚拟机可能没有软驱,你必须自己加。
2.2 软驱、串口、网卡的具体配置方式
软驱这一步很多人找不到。你需要在“虚拟机设置”里点击“添加”按钮,然后在硬件类型里找到“软盘驱动器”。添加完成后,在右侧选择“使用软盘映像”,文件名处选择你后面会做好的bootrom.img。注意不是“物理驱动器”,而是“软盘映像”文件。VMware会把一个img文件当作软驱里面的软盘来处理,这样虚拟机一开机,BIOS就能从软驱引导bootrom。
串口设置比较容易被忽视。VxWorks的默认控制台输出走的是COM1,也就是串口1。你在VMware里添加一个串行端口,端口模式选“使用命名管道”,路径填\\.\pipe\vxworks_com1,另一端选“该端是应用程序”,然后断开电源和唤醒事件。这样宿主机上的串口终端软件就能通过这个命名管道跟虚拟机里的VxWorks通信了。
网卡类型建议选择e1000e。VMware的e1000e模拟的是Intel 82574L千兆网卡,VxWorks的x86 BSP里通常有对应的end驱动;VMXNET3虽然性能好,但VxWorks 6.9默认不带VMXNET3的驱动,你强行用它,bootrom起来之后会发现找不到网络设备,后面加载镜像和调试全都抓瞎。
网络连接模式我推荐“仅主机模式(Host-only)”。这个模式会创建一个宿主机和虚拟机之间的私有网络,不依赖外部DHCP和路由器,网络行为更可控。VxWorks目标机和Workbench调试主机之间的IP地址可以自己指定,不会和外部网络冲突。
2.3 虚拟机文件位置和快照规划
还有一个小建议:在配置好虚拟机和系统之后,一旦VxWorks能成功跑起来,立刻做一个快照。比如把“刚启动到VxWorks shell”作为第一个快照,“网络调试正常”作为第二个快照。VxWorks的BSP调试过程中经常会把配置文件改坏,或者在内核里敲错命令导致系统卡死,快照能帮你秒回状态。这是真实板卡给不了的便利。
3. 制作可引导的bootrom与VxWorks镜像
3.1 在Workbench里新建VxWorks Image项目
VxWorks 6.9的IDE叫Workbench,是基于Eclipse的。你在宿主机上装好Workbench,并且确保有有效的Wind River License之后,打开它,新建一个“VxWorks Image Project”。
新建工程时,Workbench会让你选择BSP。这里一定要选x86体系的BSP,对应你的VMware虚拟机。常见名字有pcPentium4、x86,有些发行版本里会提供类似vmware的专用BSP,如果有就直接选它,如果没有就选兼容性最好的x86 BSP。
接下来是组件配置。VxWorks 6.9把内核功能拆成了大量组件,比如网络协议栈、文件系统、shell、目标代理等。你需要在组件图里勾选:
- C++ / C 运行时库,用于跑应用
- Kernel Shell,方便启动后敲命令
- Target Management,用于Workbench在线调试
- 网络组件(INET或INET6),以及对应的网卡驱动end接口
- 串口驱动,确保COM1输出
组件配置不是越多越好,每多一个组件,镜像体积就大一点,启动时间也更长。建议最小化配置,能跑起来再逐步加。
配置完后执行编译,生成的产物里会有两个关键文件:bootrom.bin和vxWorks。bootrom.bin是引导层,vxWorks是内核镜像。如果你打开代码生成目录,可能还会看到bootrom_uncmp.bin、vxWorks.st这些派生文件,我们主要用bootrom.bin和vxWorks。
3.2 把bootrom.bin做成软盘镜像
bootrom.bin本质上是原始二进制镜像,它已经包含了引导扇区。只要把它原样写到虚拟软盘镜像里,虚拟机开机后BIOS就会去执行扇区里的引导代码。因为你是在VMware里用软盘映像文件,所以需要把单个的bin文件包装成一个标准的1.44MB软驱镜像文件。
在Linux下做这个很简单:
# 创建一个1.44MB大小的空白镜像 dd if=/dev/zero of=bootrom.img bs=1474560 count=1 # 把bootrom.bin写入镜像的最开始位置 dd if=bootrom.bin of=bootrom.img conv=notrunc在Windows下,我惯用的工具是WinImage。打开WinImage,新建一个标准1.44MB软盘映像,然后选择“磁盘→从文件导入”,导入bootrom.bin,最后另存为bootrom.img。
这里有个细节需要注意:bootrom.bin的实际大小可能不到1.44MB,这不影响启动,因为BIOS只读取磁盘第一扇区以及bootrom自己读取后续扇区,文件后头全是0也无所谓。但要保证写入的是“物理偏移”的最开始处,不能用普通的拖拽文件方式放进去,那样会生成文件系统结构,而bootrom不是FAT文件系统。用WinImage时必须用“导入磁盘映像/原始扇区”的方式,而不是把文件拖进“浏览模式”。
3.3 在虚拟机中挂载软盘镜像并启动
做好bootrom.img之后,回到VMware虚拟机设置,把软驱映像文件指向它。然后打开虚拟机电源,如果一切正常,你能在串口终端上看到bootrom打印的启动信息。
这里顺便说一下为什么我不推荐直接用ISO镜像引导。VMware可以启动ISO,但VxWorks 6.9的bootrom默认支持从软驱、IDE硬盘、网络启动,对“从光驱启动”这一行为的支持取决于BSP里有没有包含CD-ROM引导驱动。为了少踩坑,软盘镜像是最稳妥的选择,它最贴近VxWorks BSP当年设计的启动路径。
3.4 另一种方式:直接做可引导ISO
如果你的BSP里带了mkisofs相关工具支持,且你确认BSP支持El Torito软盘模拟引导,那么也可以做ISO。做法是把bootrom.img作为“软盘模拟启动镜像”塞进ISO,VMware的光驱去引导这个ISO。这样不需要添加软驱设备。但这种方式对BSP的要求比较高,很多旧版x86 BSP根本不支持,所以新手还是老老实实用软驱。
4. 串口控制台连接:启动后的第一面镜子
4.1 先准备好串口终端工具
VxWorks启动后不会像Windows那样弹出一个可爱的桌面,它的标准输入输出在串口上。所以你必须先在宿主机上打开一个串口终端,连接刚才创建的命名管道\\.\pipe\vxworks_com1。
我用的是MobaXterm,它的串口会话配置比较直观。你也可以用PuTTY的最新版,选择Connection type为Serial,Serial line填\\.\pipe\vxworks_com1,Speed填115200。
串口参数必须设置成和VxWorks一致,通常为:
| 参数 | 值 |
|---|---|
| 波特率 | 115200 |
| 数据位 | 8 |
| 停止位 | 1 |
| 校验 | None |
| 流控 | None |
有些老BSP默认可能是38400或者9600,但6.9的x86 BSP默认基本都是115200。如果连上去看到乱码,优先检查波特率。
4.2 启动bootrom后能看到什么
开虚拟机电源,串口终端里会立刻出现bootrom的打印,类似这样:
VxWorks Boot 6.9 Copyright 1984-2012 Wind River Systems, Inc. CPU: x86 Version: 6.9 BSP version: 1.2 Creation date: ... Press any key to stop auto-boot...如果你手速够快,在那个“Press any key to stop auto-boot”几秒倒计时里敲任意键,就能进入bootrom的交互命令行,提示符是一个->。如果不干预,它会按照默认bootline自动尝试加载vxWorks镜像。默认bootline很可能是网络启动,而此时网络什么都没配,所以通常会加载失败。没关系,这正好说明bootrom是活的。
进入->提示符后,可以敲?查看所有可用的bootrom命令。常用的是:
| 命令 | 作用 |
|---|---|
p | 打印当前bootline参数 |
c | 进入交互式配置模式 |
@ | 使用当前bootline启动 |
b | 启动 |
i | 显示网络接口信息 |
我强烈建议你先敲p看看默认启动行写成什么样,这有助于理解VxWorks的启动参数结构。bootline里包含设备名、目标机IP、宿主机IP、用户名、密码等,是一串用空格和特殊符号分隔的参数。
4.3 通过交互模式配置启动行
在提示符下按c,bootrom会开启一个简单的问答式配置。它会问你启动设备是什么,比如fei、igbe、fd、tffs等,你需要根据你BSP里的网卡驱动名称填。我用的x86 BSP配合e1000e虚拟网卡时,设备名通常是fei或者igbe。如果你不确定,可以在bootrom提示符输入i查看可用网络接口。
配置启动行的时候,有一个典型参数结构可以参考:
fei(0,0)host:vxWorks h=192.168.70.2 e=192.168.70.10 u=target pw=target o=ae这里简单解释一下:
fei(0,0)表示用第一个fei网卡,从0号设备启动host:vxWorks表示从主机加载名为vxWorks的内核镜像文件h=是宿主机IPe=是目标机(VxWorks)的IPu=和pw=是目标机FTP/TFTP登录用的用户名、密码o=是其他启动选项,a表示自动启动,e表示是否打印错误信息
如果你是基于软盘上的bootrom启动,但是要通过网络加载vxWorks内核,那么你需要在bootline里把启动设备指向网络接口。如果想把bootrom和vxWorks都塞到同一个软盘镜像里,理论也可以,不过还是分开更清晰。
配置完之后,输入@启动,bootrom就会按照你的bootline去网络上寻找vxWorks镜像并加载。
4.4 如果连bootrom都看不到怎么办
如果在串口终端上完全没有任何输出,不要先怀疑VxWorks,先检查几件事:
- 虚拟机串口是否设置为命名管道,路径和你终端软件里填的一致;
- 终端软件的串口参数对不对;
- VMware里串口选项“该端是应用程序”是否勾选;
- 有没有先启动终端软件,再开虚拟机电源。
还有一个很容易忽略的点:每次给虚拟机断电再启动,命名管道可能要被终端软件重新连接一次。MobaXterm有时候会断开,需要断开会话重连一下。
5. 网络联通与Workbench在线调试
5.1 给VxWorks目标机配一个固定IP
如果你的bootline里已经配置了e=192.168.70.10,那么VxWorks内核启动后,会把这个IP配到对应的end网络接口上。这时候你就可以在宿主机上ping一下这个地址,验证网络通不通。
但我更常用的方法是在VxWorks的shell里直接配置网络,尤其是当你第一次用本地软盘启动、没有配置网络启动参数的时候。进入shell后,敲ifconfig可以查看当前网络接口状态,再敲ifconfig end0 192.168.70.10 255.255.255.0 up这样风格的命令给接口配上IP。这里end0是网络接口逻辑名,不同BSP可能不一样,有些是fei0、igbe0,打印接口信息看一眼就知道。
建议把宿主机VMnet1(仅主机模式网卡)的IP设置为192.168.70.2,掩码255.255.255.0,VxWorks目标机设置为192.168.70.10。这样两个地址就落在了同一个网段,通信没有任何阻碍。
5.2 在Workbench里添加目标机
打开Workbench,找到“Target Management”或者“Targets”视图,新建一个Target。连接方式选择“Network”,填上VxWorks目标机的IP地址。Workbench会通过目标代理(Target Agent)和运行中的VxWorks建立连接。
这里有个重要前提:VxWorks镜像里必须包含“Target Management”组件,否则Workbench连不上。如果你编译VxWorks Image时没有勾选这个组件,镜像里就没有代理进程,Workbench扫描目标机时会提示“Target Agent not responding”。解决办法是回到组件配置里,把目标代理组件加进去,重新编译vxWorks镜像,再启动一次。
连接成功后,你可以看到目标机的CPU、内存、任务列表等信息。最爽的是可以在Workbench里直接下载内核、下载应用模块,还能进行断点调试。比如你写了一个用户任务,可以编译成.out文件,通过Workbench的“Download”功能下载到目标机上运行,并在此处设置断点单步执行。
5.3 通过TFTP或者串口把vxWorks镜像加载进来
如果你走的是网络加载方式,宿主机上需要跑一个TFTP服务器,把Workbench编译出来的vxWorks文件放在TFTP根目录下。bootrom启动时根据bootline里的host:vxWorks,会去宿主机的TFTP服务器拉取这个镜像。
TFTP服务器工具有很多,Linux下可以用tftpd-hpa,Windows下可以用OpenTFTP或者SolarWinds TFTP Server。注意Windows防火墙要放行UDP 69端口,否则bootrom访问不到。
如果你不想搭TFTP,又不想把镜像固化到软盘里,还有一个笨办法:通过在串口终端前启动的bootrom,用串口传输协议把vxWorks镜像传入内存。但这需要手工计算地址和长度,操作繁琐,我只在应急时候用。
5.4 在线调试时的常用技巧
Workbench连接上目标机后,我习惯先打开“Kernel Shell”视图,这样既能敲命令,又能配合Workbench图形界面的任务管理和内存查看。组合使用比较顺手。
还有一个小技巧:给VxWorks目标机配置NFS或FTP共享根文件系统,这样可以动态加载应用程序而不用反复重烧镜像。VxWorks 6.9支持NFS客户端,你可以在宿主机上开一个NFS共享目录,在VxWorks里mount到这个目录,应用程序直接在共享目录里运行。虚拟化环境里这样做很舒服,因为宿主机和虚拟机之间的网络就是隔离的VMnet,速度和稳定性都有保障。
6. 问题排查清单:我踩过的那些坑
6.1 串口无输出或者全是乱码
先确认串口参数,特别是波特率。如果波特率不对,整个屏幕都是黑白噪音一样的乱码。再确认你终端连接的是不是VMware的命名管道,而不是某个真实的COM口设备。还有一个坑是VMware的命名管道在Windows下需要终端软件用管理员权限打开,否则连接会被拒绝。
6.2 bootrom启动了,但VxWorks内核加载到一半卡死
这种“半路卡死”大多数是网卡驱动不匹配导致的。bootrom启动时可能还会打印设备信息,如果它卡在“Attaching network interface”之类的地方,大概率是网卡型号和BSP驱动不一致。解决方法是把VMware虚拟机的网卡从默认改成e1000e,或者e1000;不要用VMXNET3。如果你的BSP只支持老式e1000,那你就选e1000。
6.3 VxWorks起来之后鼠标键盘没反应
很多人的第一反应是“坏了”。其实不是,VxWorks默认就是串口控制台,键盘鼠标只是它兼容PC硬件的附带功能,不一定加载了相关驱动。你不需要鼠标键盘,所有输入都在串口终端的shell里敲就行了。如果你实在想要一个带图形界面的VxWorks,那需要额外配置图形组件和鼠标驱动,虚拟化环境下性价比很低,不推荐折腾。
6.4 时钟和延时不准,定时器忽快忽慢
这个问题比较隐蔽。VxWorks BSP默认可能使用PC的i8254定时器,而VMware虚拟化平台对某些定时器中断的虚拟化处理会有延迟,导致taskDelay和系统时钟不太准确。处理方式是在BSP配置里强制指定使用某个时钟源,比如改成HPET或者保持PIT模式,并调整系统时钟频率。具体选项要看BSP头文件里的定义,不同版本差异很大。我的建议是先不要浪费太多时间,因为如果只是做功能验证,轻微的时钟偏差不影响;但如果你在对时间敏感的逻辑上调试,就需要花点心思配置时钟源了。
6.5 硬盘识别不到或启动时找不到磁盘文件系统
VxWorks 6.9对SATA控制器的支持不完善,你在VMware里给虚拟机配置硬盘时,一定要把磁盘类型选成IDE。如果已经是IDE但还是识别不到,检查BSP里是否启用了IDE/ATA驱动组件。VxWorks里访问磁盘需要文件系统组件的支持,比如dosFs或rawFs。如果只是做实验,完全可以不挂磁盘,只从网络加载镜像,这样最省事。
6.6 VMware Tools千万不要装
VMware Tools对Windows和Linux虚拟机是神器,但对VxWorks来说没有任何意义。VMware Tools的安装包是给宿主机操作系统做的,VxWorks没有设备驱动框架去装载它,反而会引入未知的中断。
6.7 保存状态之后再恢复可能导致网络假死
VMware的挂起恢复机制在VxWorks这里偶尔会有问题。VxWorks内核运行中,如果你用一个快照去恢复整个虚拟机,可能网络、定时器和串口都恢复正常,但网络连接变成半死状态,ping不通也连不上。遇到这种情况,直接在VxWorks shell里把网卡down掉再up一次,通常就能恢复。如果不行,就重启VxWorks,毕竟它是RTOS,常驻运行很久不是它的设计重点,开发阶段频繁重启也正常。
我在VMware里把VxWorks 6.9跑通之后,最大的感受是:虚拟化环境确实能省掉很多硬件上才有的烦心事,比如串口线供电不稳、网卡接线松动,但前提是你要理解VxWorks的引导流程和BSP机制。你把这个底层的逻辑理顺了,再回来看VMware的设置,每一步都显得非常自然。如果你也在折腾VxWorks 6.9的虚拟化环境,希望这篇教程能帮你少走些弯路。