(说明:这篇文章是我的朋友写的,他在我的博客上首次发表,姑且算为原创吧)
此文档描述了在Windows Qemu虚拟机下建立RTEMS仿真测试环境的过程。
QEMU是一个开源的虚拟机程序,主要应用在Linux系统中,使用命令行方式进行操作。QEMU在Windows下有移植版本,并且技术爱好者为Windows的QEMU提供了免费UI界面,使其更符合Windows用户的软件操作习惯。这个UI程序称为QEMU Manager,平均每年更新一次,目前最新版本号为7.0。用户可以从官网http://www.davereyn.co.uk/获取QEMU Manager的相关信息。
本文构造的RTEMS仿真平台使用到了如下资源:
1. Win7操作系统;
2. QEMU Manager 7.0安装程序;
3. network-demos-4.9.4.tar.bz2(可选,用于平台功能验证)。
在这份文档示例中使用的是当前最新的QEMU Manager 7.0安装版程序,程序来源于http://www.davereyn.co.uk/download.htm。此程序下集成了QEMU 0.11.1与相应的加速器KQemu。
安装过程相对简单,指定好安装路径即可,没有需要特别留意的地方。
图1 QEMU Manager安装界面
图2 初次运行QEMU Manager配置界面
QEMU Manager主界面下选择“Tools->Configure TAP Network Devices”
图3 添加虚拟网卡界面
第一次添加NAT网卡时系统可能会要求安装特定驱动,允许安装即可。
添加成功后Windows系统会生成一个新网卡配置项--“本地连接”,为了方便以后应用,用户可以重新指定这个新网卡名称,文档示例中将此NAT网卡重命名为“qemu_tap”。
QEMU Manager主界面下选择“VM->New Virtual Machine”,在这里需要指定新虚拟机名、虚拟机使用的CPU类型、内存与硬盘容量配置。根据需要,示例中的新虚拟机命名为“rtems_pc386”,CPU类型为“Standard x86”,内存为256M,硬盘为128M。
图4 添加虚拟机界面1
图5 添加虚拟机界面2
图6 添加虚拟机界面3
添加成功一个新虚拟机后会出现如下界面:
图7 虚拟机配置界面
2.3节新创建的虚拟机使用默认工作参数。一般来说,在不使用网络功能的前提下,RTEMS自带pc386 BSP已经可以在默认的虚拟机配置中正常运行。如果需要打开网络功能则还应该对虚拟机参数做适当修改。
示例使用了RTEMS源码包自带的NE2000网卡驱动,所作参数修改如下:修改系统总线类型、选择网卡类型、配置网络参数。
由于RTEMS自带的NE2000驱动无法在PCI总线PC中运行,所以要将“Machine Type”修改为ISA类型。
图8 选择“Machine Type”界面
图9 配置“CPU Type”界面
要确保“Hardware”配置界面中的“Enable Networking”参数为“Yes”,否则配置界面不会显示网卡选择项。
双击“Hardware”配置界面中的“Network Card 1”项,需要选择网卡类型、VLAN类型、网卡MAC地址、指定TAP网络适配器。其中,选择“NE2000 ISA”网卡,VLAN类型为“Tap Networking”, MAC地址可以使用默认值或自己重新指定,TAP适配器选择2.3节中创建的新网卡名,本例使用的是“qemu_tap”。
1.在Windows“网络连接”界面中找到“qemu_tap”网卡。
图11 Windows“网络连接”界面
2.为NAT网卡配置IP。注意,这里设置的NAT网卡IP地址可以与宿主机上的真实物理网卡的地址不在一个段内;而是与虚拟机中NE2000网卡设置的网络地址在一个段内就可以了。
示例使用的物理主机网卡IP为192.168.2网段,配置的NAT网卡IP为192.168.10网段。
经过以上配置之后QEMU虚拟机的环境已经搭建完毕,但想要正常运行RTEMS程序则还需要对相关应用代码做修改。
文档示例使用的netdemo应用程序来源于RTEMS官方提供的程序包network-demos-4.9.4.tar.bz2。解压network-demos-4.9.4.tar.bz2,在解压后的文件夹中有一个名为networkconfig.h的文件,所有的修改都在此文件中完成。
RTEMS 的i386 BSP 默认安装的是DEC21140 网卡,而QEMU 中仿真的
是NE2000 网卡,所以要重新定义相关的宏:
#define RTEMS_BSP_NETWORK_DRIVER_NAME
BSP_NE2000_NETWORK_DRIVER_NAME
#define RTEMS_BSP_NETWORK_DRIVER_ATTACH
BSP_NE2000_NETWORK_DRIVER_ATTACH
这里设置的物理地址一定要与2.4.2节中设置的QEMU NAT网卡MAC值一致。
/*
* Define RTEMS_SET_ETHERNET_ADDRESS if you want to specify the
* Ethernet address here. If RTEMS_SET_ETHERNET_ADDRESS is not
* defined the driver will choose an address.
*/
static char ethernet_address[6] = { 0x52, 0x54, 0x00, 0x38, 0xFE, 0x22 };
在netdriver_config结构体中配置本地IP、网卡IO地址、中断号和所在槽号。其中IP 地址和IP 掩码可以根据自己的需要设置。注意,IP 地址必须与宿主机中TAP 网卡的IP 地址在同一个段内,才能实现虚拟机下RTEMS 与宿主机的网络通信。
关键是最后三个设置参数。这三个参数是在例程的基础上添加上去的。分别设置的是网卡的IO 地址、中断号和所在插槽号。如果在这个定义中省略这三个参数,则RTEMS 采用默认值。而默认NE2000 网卡IO 地址是0x240,中断号是5,与QEMU 虚拟机仿真的网卡不符,所以必须按照上述参数进行设置。
/*
* Default network interface
*/
static struct rtems_bsdnet_ifconfig netdriver_config = {
RTEMS_BSP_NETWORK_DRIVER_NAME, /* name */
RTEMS_BSP_NETWORK_DRIVER_ATTACH, /* attach function */
#ifdef RTEMS_USE_LOOPBACK
&loopback_config, /* link to next interface */
#else
NULL, /* No more interfaces */
#endif
"192.168.10.2", /* IP address(自行配置) */
"255.255.255.0", /* IP net mask */
#endif /* !RTEMS_USE_BOOTP */
ethernet_address, /* Ethernet hardware address */
0, /* ignore broadcast */
0, /* mtu */
0, /* rbuf_count */
0, /* xbuf_count */
0x300, /* port (配置为0x300) */
9, /* irq (配置为9)*/
0, /* bpar (配置为0)*/
NULL /* driver control pointer */
};
在rtems_bsdnet_config结构体中配置网关等参数:
/*
* Network configuration
*/
struct rtems_bsdnet_config rtems_bsdnet_config = {
&netdriver_config,
#if (defined (RTEMS_USE_BOOTP))
rtems_bsdnet_do_bootp,
#else
NULL,
#endif
8, /* Default network task priority */
256 * 1024, /* Default mbuf capacity */
256 * 1024, /* Default mbuf cluster capacity */
"leo", /* Host name */
"leo", /* Domain name */
"192.168.10.1", /* Gateway */
"192.168.10.1", /* Log host */
{"192.168.10.1" }, /* Name server(s) */
{"192.168.10.1" }, /* NTP server(s) */
0, /* efficiency */
0, /* udp TX buffer */
0, /* udp RX buffer */
0, /* tcp TX buffer */
0, /* tcp RX buffer */
};
经过上述设置之后就可以正确编译使用RTEMS 的网络例程了。文档中的Netdemo 例程实现了一个Telnet echo server 功能。也就是说,其它机器(客户端)只要执行telnet 命令与该运行该程序的机器(服务器)的24742 端口建立了连接,则任何在客户端机器键盘上键入的字符,都会被服务器接收并且回传给客户端。这样,在客户端机器键盘上按下a键,其屏幕上就会显示aa两个字符,前一个是对键盘的响应,后一个就是服务器回传字符的显示。
以下为例程使用的networkconfig.h配置文件完整内容,用户可以拷贝此文件内容,稍作修改即可使用。
/*
* Network configuration for MPC8313ERDB in RTEMS Lab
*
************************************************************
* EDIT THIS FILE TO REFLECT YOUR NETWORK CONFIGURATION *
* BEFORE RUNNING ANY RTEMS PROGRAMS WHICH USE THE NETWORK! *
************************************************************
*
* $Id: networkconfig-mpc8313erdb.h,v 1.1 2008/08/21 16:40:37 joel Exp $
*/
#ifndef _RTEMS_NETWORKCONFIG_H_
#define _RTEMS_NETWORKCONFIG_H_
/*
* The following will normally be set by the BSP if it supports
* a single network device driver. In the event, it supports
* multiple network device drivers, then the user's default
* network device driver will have to be selected by a BSP
* specific mechanism.
*/
/* #define RTEMS_USE_BOOTP */
#include
/*
* Define RTEMS_SET_ETHERNET_ADDRESS if you want to specify the
* Ethernet address here. If RTEMS_SET_ETHERNET_ADDRESS is not
* defined the driver will choose an address.
*/
static char ethernet_address[6] = { 0x52, 0x54, 0x00, 0x38, 0xFE, 0x22 };
#ifdef RTEMS_USE_LOOPBACK
/*
* Loopback interface
*/
extern void rtems_bsdnet_loopattach();
static struct rtems_bsdnet_ifconfig loopback_config = {
"lo0", /* name */
rtems_bsdnet_loopattach, /* attach function */
NULL, /* link to next interface */
"127.0.0.1", /* IP address */
"255.0.0.0", /* IP net mask */
};
#endif
#define RTEMS_BSP_NETWORK_DRIVER_NAME BSP_NE2000_NETWORK_DRIVER_NAME
#define RTEMS_BSP_NETWORK_DRIVER_ATTACH BSP_NE2000_NETWORK_DRIVER_ATTACH
/*
* Default network interface
*/
static struct rtems_bsdnet_ifconfig netdriver_config = {
RTEMS_BSP_NETWORK_DRIVER_NAME, /* name */
RTEMS_BSP_NETWORK_DRIVER_ATTACH, /* attach function */
#ifdef RTEMS_USE_LOOPBACK
&loopback_config, /* link to next interface */
#else
NULL, /* No more interfaces */
#endif
#if 0
NULL, /* BOOTP supplies IP address */
NULL, /* BOOTP supplies IP net mask */
#else
"192.168.10.2", /* IP address */
"255.255.255.0", /* IP net mask */
#endif /* !RTEMS_USE_BOOTP */
ethernet_address, /* Ethernet hardware address */
0, /* ignore broadcast */
0, /* mtu */
0, /* rbuf_count */
0, /* xbuf_count */
0x300, /* port */
9, /* irq */
0, /* bpar */
NULL /* driver control pointer */
};
/*
* Network configuration
*/
struct rtems_bsdnet_config rtems_bsdnet_config = {
&netdriver_config,
#if (defined (RTEMS_USE_BOOTP))
rtems_bsdnet_do_bootp,
#else
NULL,
#endif
8, /* Default network task priority */
256 * 1024, /* Default mbuf capacity */
256 * 1024, /* Default mbuf cluster capacity */
"leo", /* Host name */
"leo", /* Domain name */
"192.168.10.1", /* Gateway */
"192.168.10.1", /* Log host */
{"192.168.10.1" }, /* Name server(s) */
{"192.168.10.1" }, /* NTP server(s) */
0, /* efficiency */
0, /* udp TX buffer */
0, /* udp RX buffer */
0, /* tcp TX buffer */
0, /* tcp RX buffer */
};
/*
* For TFTP test application
*/
#if (defined (RTEMS_USE_BOOTP))
#define RTEMS_TFTP_TEST_HOST_NAME "BOOTP_HOST"
#define RTEMS_TFTP_TEST_FILE_NAME "BOOTP_FILE"
#else
#define RTEMS_TFTP_TEST_HOST_NAME "XXX.YYY.ZZZ.XYZ"
#define RTEMS_TFTP_TEST_FILE_NAME "tftptest"
#endif
/*
* For NFS test application
*
* NFS server/path to mount and a directory to ls once mounted
*/
#define RTEMS_NFS_SERVER "192.168.1.210"
#define RTEMS_NFS_SERVER_PATH "/home"
#define RTEMS_NFS_LS_PATH "/mnt/nfstest"
#endif /* _RTEMS_NETWORKCONFIG_H_ */