如何制作支持VMWare的Windows CE BSP

不知道有没有人试过在VMWare中跑过Windows CE。可能有人会问:在VMWare中跑Windows CE有什么意义?Windows CE不是有基于Vritual PC的emulator吗?要做干吗不做一个基于Microsoft自己的Virtual PC的?

简单的答案是,VMWare支持一些Virtual PC(包括Windows CE emulator)不支持的硬件。对我来说,最吸引我的是VMWare支持USB设备。另外根据我的经验VMWare的性能比Virtual PC强。

本文介绍如何针对VMWare支持的硬件,做一个相应的Windows CE BSP。根据VMWare虚拟机的spec,我打算支持的硬件列表如下(SCSI设备、软驱这些用的比较少就算了):

Graphics

•VGAandSVGAsupport

IDEDrives

•IDEvirtualdisksupto
950GB

•Serial
(COM)Ports

•Uptofourserial
(COM)ports

USBports

•Two-portUSB
1.1UHCIcontroller

Keyboard

104-keyWindows95/98enhanced

MouseandDrawingTablets

•PS
/2mouse

EthernetCard

•AMDPCnet-PCIIIcompatible

Sound

•EmulatesCreativeLabsSoundBlasterAudioPCI
(MIDIinput,gamecontrollersandjoysticksarenotsupported,exceptforUSBdevices)

其实从根本上来说,给VMWare用的Windows CE跟普通PC或者Virtual PC的并无多大区别。因此基本做法和一些概念都可以看MSDN里对CEPC的相关介绍。这里只重点介绍一些针对VMWare的不同地方。

给Windows CE用的VMWare虚拟机可以用DOS的。BSP可以直接copy一份Platform Builder带的CEPC BSP做为起始的BSP,然后在此基础上修改。从IDE硬盘、声卡、显卡、键盘鼠标的支持比较简单,用Platform Builder中现成的driver就行了。

如何制作支持VMWare的Windows CE BSP

比较麻烦的是网卡和USB host controller。

VMWare虚拟的网卡兼容AMD PCnet-PCI II,具体型号是AMD AM79C970A,这个在Windows CE下可实在不好找,自己写一个就太麻烦了。不过在google大法的强力帮助下,我花了很长时间终于找到一个编译好的driver-还是for Windows CE 2.0的(现在想不起来在哪儿找到的了,想要的直接找我吧)。相关注册表设置见附录。

比较头疼的是USB host driver。VMWare中支持的USB host controller是USB 1.1 UHCI controller。Windows CE下有现成的driver,但是直接拿来用的话你会发现不能工作。一番研究后发现问题出在LEGACY SUPPORT REGISTER (LEGSUP)的设置上-VMWare在初始化UHCI controller的时候enable了SMI generation,而且没有把USB中断route到PIRQD上。简单说来就是VMWare对UHCI controller的初始化和Windows CE自带driver要求的不一样(其实是和UHCI spec定义的不一致,UHCI spec定义LEGSUP寄存器默认值是2000h(见5.2.1节),VMWare中是3Bh)。为了能让UHCI controller工作,需要修改UHCI driver的初始化例程,重新编译一个版本。具体修改见附录。

这样,一个支持声卡、网卡、USB设备的VMWare BSP就基本搞定了。

附上两张运行时的截图:

如何制作支持VMWare的Windows CE BSP

如何制作支持VMWare的Windows CE BSP

附1,网卡的注册表设置,放在platform.reg里:

[HKEY_LOCAL_MACHINECommPCNTN4M]
"DisplayName"="PCNTN4MCompatibleEthernetDriver"
"Group"="NDIS"
"ImagePath"="pcntn4m.dll"

[HKEY_LOCAL_MACHINE
CommPCNTN4MLinkage]
"Route"=multi_sz:"PCNTN4M1"

[HKEY_LOCAL_MACHINE
CommPCNTN4M1]
"DisplayName"="PCNTN4MCompatibleEthernetDriver"
"Group"="NDIS"
"ImagePath"="pcntn4m.dll"


[HKEY_LOCAL_MACHINE
CommPCNTN4M1Parms]
;"BusNumber"=dword:0
;"BusType"=dword:05
;"Interrupt"=dword:05
;"IOAddress"=dword:0300


[HKEY_LOCAL_MACHINE
CommTcpipLinkage]
"Bind"=multi_sz:"ppp","PCNTN4M1"

;Registryvaluesforthepcntn4m1driver
[HKEY_LOCAL_MACHINE
CommPCNTN4M1ParmsTcpIp]
;ThisenabletheDHCP.InWinCE2.1PreviewversionstaticallyallocatedIPaddress
;doesnotwork.SoweusetheDHCPservertoallocatetheIPaddress.
"EnableDHCP"=dword:1
;ThisshouldbeMULTI_SZ
"DefaultGateway"=""
;ThisshouldbeSZ...IfnullitmeansuseLAN,elseWANandInterface.
"LLInterface"=""
;Usezeroforbroadcastaddress?(or255.255.255.255)
"UseZeroBroadcast"=dword:0
;ThusshouldbeMULTI_SZ,theIPaddresslist
"IpAddress"="0.0.0.0"
;ThisshouldbeMULTI_SZ,thesubnetmasksfortheaboveIPaddresses
"Subnetmask"="0.0.0.0"

;
;TemplatethePCIbusdriverusestomatchaAM79C970PC-netcard
;
[HKEY_LOCAL_MACHINE
DriversBuiltInPCITemplatePCNTN4M]
"Dll"="NDIS.dll"
"Class"=dword:02
"SubClass"=dword:00
"ProgIF"=dword:0
"VendorID"=multi_sz:"1022"
"DeviceID"=multi_sz:"2000"
;"Entry"="NdisPCIBusDeviceInit"
"Prefix"="NDS"
"Transceiver"=dword:3
"IsrDll"="giisr.dll"
"IsrHandler"="ISRHandler"
"PortIsIO"=dword:1
"PortOffset"=dword:C;TBD
"PortSize"=dword:2
"PortMask"=dword:5F00;TBD

[HKEY_LOCAL_MACHINE
CommConnectionSharing]
"PrivateInterface"="PCI\PCNTN4M"

附2,UHCI driver需要修改的代码(红色部分,在$(DRIVERS)\USB\HCD\UHC\system.csystem.c中):

如何制作支持VMWare的Windows CE BSP//Inlinefunctions
如何制作支持VMWare的Windows CE BSP
__inlinestaticWORD
如何制作支持VMWare的Windows CE BSPPCIConfig_ReadWord(
如何制作支持VMWare的Windows CE BSPULONGBusNumber,
如何制作支持VMWare的Windows CE BSPULONGDevice,
如何制作支持VMWare的Windows CE BSPULONGFunction,
如何制作支持VMWare的Windows CE BSPULONGOffset
如何制作支持VMWare的Windows CE BSP)
如何制作支持VMWare的Windows CE BSP如何制作支持VMWare的Windows CE BSP
...{
如何制作支持VMWare的Windows CE BSPWORDRetVal=0;
如何制作支持VMWare的Windows CE BSPPCI_SLOT_NUMBERSlotNumber;
如何制作支持VMWare的Windows CE BSP
如何制作支持VMWare的Windows CE BSPSlotNumber.u.AsULONG=0;
如何制作支持VMWare的Windows CE BSPSlotNumber.u.bits.DeviceNumber=Device;
如何制作支持VMWare的Windows CE BSPSlotNumber.u.bits.FunctionNumber=Function;
如何制作支持VMWare的Windows CE BSPHalGetBusDataByOffset(PCIConfiguration,BusNumber,SlotNumber.u.AsULONG,&RetVal,Offset,sizeof(RetVal));
如何制作支持VMWare的Windows CE BSP
如何制作支持VMWare的Windows CE BSPreturnRetVal;
如何制作支持VMWare的Windows CE BSP}

如何制作支持VMWare的Windows CE BSP
如何制作支持VMWare的Windows CE BSP__inlinestaticvoid
如何制作支持VMWare的Windows CE BSPPCIConfig_Write(
如何制作支持VMWare的Windows CE BSPULONGBusNumber,
如何制作支持VMWare的Windows CE BSPULONGDevice,
如何制作支持VMWare的Windows CE BSPULONGFunction,
如何制作支持VMWare的Windows CE BSPULONGOffset,
如何制作支持VMWare的Windows CE BSPULONGValue,
如何制作支持VMWare的Windows CE BSPULONGSize
如何制作支持VMWare的Windows CE BSP)
如何制作支持VMWare的Windows CE BSP如何制作支持VMWare的Windows CE BSP
...{
如何制作支持VMWare的Windows CE BSPPCI_SLOT_NUMBERSlotNumber;
如何制作支持VMWare的Windows CE BSP
如何制作支持VMWare的Windows CE BSPSlotNumber.u.AsULONG=0;
如何制作支持VMWare的Windows CE BSPSlotNumber.u.bits.DeviceNumber=Device;
如何制作支持VMWare的Windows CE BSPSlotNumber.u.bits.FunctionNumber=Function;
如何制作支持VMWare的Windows CE BSP
如何制作支持VMWare的Windows CE BSPHalSetBusDataByOffset(PCIConfiguration,BusNumber,SlotNumber.u.AsULONG,&Value,Offset,Size);
如何制作支持VMWare的Windows CE BSP}

如何制作支持VMWare的Windows CE BSP
如何制作支持VMWare的Windows CE BSP如何制作支持VMWare的Windows CE BSP
/**//*InitializeUHCI
如何制作支持VMWare的Windows CE BSP*
如何制作支持VMWare的Windows CE BSP*ConfigureandinitializeUHCIcard
如何制作支持VMWare的Windows CE BSP*
如何制作支持VMWare的Windows CE BSP*ReturnValue:
如何制作支持VMWare的Windows CE BSP*ReturnTRUEifcardcouldbelocatedandconfigured,otherwiseFALSE
如何制作支持VMWare的Windows CE BSP
*/

如何制作支持VMWare的Windows CE BSP
staticBOOL
如何制作支持VMWare的Windows CE BSPInitializeUHCI(
如何制作支持VMWare的Windows CE BSPSUhcdPdd
*pPddObject,//IN-PointertoPDDstructure
如何制作支持VMWare的Windows CE BSP
LPCWSTRszDriverRegKey)//IN-Pointertoactiveregistrykeystring
如何制作支持VMWare的Windows CE BSP如何制作支持VMWare的Windows CE BSP
...{
如何制作支持VMWare的Windows CE BSPPUCHARioPortBase
=NULL;
如何制作支持VMWare的Windows CE BSPDWORDdwAddrLen;
如何制作支持VMWare的Windows CE BSPDWORDdwIOSpace;
如何制作支持VMWare的Windows CE BSPBOOLInstallIsr
=FALSE;
如何制作支持VMWare的Windows CE BSPBOOLfResult
=FALSE;
如何制作支持VMWare的Windows CE BSPLPVOIDpobMem
=NULL;
如何制作支持VMWare的Windows CE BSPLPVOIDpobUhcd
=NULL;
如何制作支持VMWare的Windows CE BSPDWORDPhysAddr;
如何制作支持VMWare的Windows CE BSPDWORDdwHPPhysicalMemSize;
如何制作支持VMWare的Windows CE BSPHKEYhKey;
如何制作支持VMWare的Windows CE BSPWORDLegSup;
如何制作支持VMWare的Windows CE BSP
如何制作支持VMWare的Windows CE BSPDDKWINDOWINFOdwi;
如何制作支持VMWare的Windows CE BSPDDKISRINFOdii;
如何制作支持VMWare的Windows CE BSPDDKPCIINFOdpi;
如何制作支持VMWare的Windows CE BSP如何制作支持VMWare的Windows CE BSP
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,szDriverRegKey,0,0,&hKey)!=ERROR_SUCCESS)...{
如何制作支持VMWare的Windows CE BSPDEBUGMSG(ZONE_ERROR,(TEXT(
"InitializeUHCI:GetRegistryConfigRegOpenKeyEx(%s)failed "),
如何制作支持VMWare的Windows CE BSPszDriverRegKey));
如何制作支持VMWare的Windows CE BSP
returnFALSE;
如何制作支持VMWare的Windows CE BSP}

如何制作支持VMWare的Windows CE BSPdwi.cbSize
=sizeof(dwi);
如何制作支持VMWare的Windows CE BSPdii.cbSize
=sizeof(dii);
如何制作支持VMWare的Windows CE BSPdpi.cbSize
=sizeof(dpi);
如何制作支持VMWare的Windows CE BSPif(DDKReg_GetWindowInfo(hKey,&dwi)!=ERROR_SUCCESS||
如何制作支持VMWare的Windows CE BSPDDKReg_GetIsrInfo(hKey,&dii)!=ERROR_SUCCESS||
如何制作支持VMWare的Windows CE BSP如何制作支持VMWare的Windows CE BSPDDKReg_GetPciInfo(hKey,&dpi)!=ERROR_SUCCESS)
...{
如何制作支持VMWare的Windows CE BSPDEBUGMSG(ZONE_ERROR,(TEXT("InitializeUHCI:DDKReg_GetWindowInfoorDDKReg_GetWindowInfoorDDKReg_GetPciInfofailed "
)));
如何制作支持VMWare的Windows CE BSP
gotoInitializeUHCI_Error;
如何制作支持VMWare的Windows CE BSP}

如何制作支持VMWare的Windows CE BSP如何制作支持VMWare的Windows CE BSP
if(dwi.dwNumMemWindows!=0)...{
如何制作支持VMWare的Windows CE BSPPhysAddr
=dwi.memWindows[0].dwBase;
如何制作支持VMWare的Windows CE BSPdwAddrLen
=dwi.memWindows[0].dwLen;
如何制作支持VMWare的Windows CE BSPdwIOSpace
=0;
如何制作支持VMWare的Windows CE BSP}

如何制作支持VMWare的Windows CE BSP如何制作支持VMWare的Windows CE BSP
elseif(dwi.dwNumIoWindows!=0)...{
如何制作支持VMWare的Windows CE BSPPhysAddr
=dwi.ioWindows[0].dwBase;
如何制作支持VMWare的Windows CE BSPdwAddrLen
=dwi.ioWindows[0].dwLen;
如何制作支持VMWare的Windows CE BSPdwIOSpace
=1;
如何制作支持VMWare的Windows CE BSP}

如何制作支持VMWare的Windows CE BSP
else
如何制作支持VMWare的Windows CE BSP
gotoInitializeUHCI_Error;
如何制作支持VMWare的Windows CE BSPDEBUGMSG(ZONE_INIT,(TEXT(
"UHCD:Readconfigfromregistry:BaseAddress:0x%X,Length:0x%X,I/OPort:%s,SysIntr:0x%X,InterfaceType:%u,BusNumber:%u "),
如何制作支持VMWare的Windows CE BSPPhysAddr,dwAddrLen,dwIOSpace
?L"YES":L"NO",dii.dwSysintr,dwi.dwInterfaceType,dwi.dwBusNumber));
如何制作支持VMWare的Windows CE BSP
如何制作支持VMWare的Windows CE BSPioPortBase
=(PUCHAR)PhysAddr;
如何制作支持VMWare的Windows CE BSP如何制作支持VMWare的Windows CE BSP
if(!(fResult=ConfigureUHCICard(pPddObject,&ioPortBase,dwAddrLen,dwIOSpace,dwi.dwInterfaceType,dwi.dwBusNumber)))...{
如何制作支持VMWare的Windows CE BSP
gotoInitializeUHCI_Error;
如何制作支持VMWare的Windows CE BSP}

如何制作支持VMWare的Windows CE BSP如何制作支持VMWare的Windows CE BSP
if(dii.szIsrDll[0]!=0&&dii.szIsrHandler[0]!=0&&dii.dwIrq<0xff&&dii.dwIrq>0)...{
如何制作支持VMWare的Windows CE BSP
//InstallISRhandler
如何制作支持VMWare的Windows CE BSP
pPddObject->IsrHandle=LoadIntChainHandler(dii.szIsrDll,dii.szIsrHandler,(BYTE)dii.dwIrq);
如何制作支持VMWare的Windows CE BSP
如何制作支持VMWare的Windows CE BSP如何制作支持VMWare的Windows CE BSP
if(!pPddObject->IsrHandle)...{
如何制作支持VMWare的Windows CE BSPDEBUGMSG(ZONE_ERROR,(L
"UHCD:Couldn'tinstallISRhandler "));
如何制作支持VMWare的Windows CE BSP如何制作支持VMWare的Windows CE BSP}
else...{
如何制作支持VMWare的Windows CE BSPGIISR_INFOInfo;
如何制作支持VMWare的Windows CE BSP如何制作支持VMWare的Windows CE BSPPHYSICAL_ADDRESSPortAddress
=...{PhysAddr,0};
如何制作支持VMWare的Windows CE BSPDEBUGMSG(ZONE_INIT,(L
"UHCD:InstalledISRhandler,Dll='%s',Handler='%s',Irq=%d ",
如何制作支持VMWare的Windows CE BSPdii.szIsrDll,dii.szIsrHandler,dii.dwIrq));
如何制作支持VMWare的Windows CE BSP如何制作支持VMWare的Windows CE BSP
if(!BusTransBusAddrToStatic(pPddObject->hParentBusHandle,dwi.dwInterfaceType,dwi.dwBusNumber,PortAddress,dwAddrLen,&dwIOSpace,&(PVOID)PhysAddr))...{
如何制作支持VMWare的Windows CE BSPDEBUGMSG(ZONE_ERROR,(L
"UHCD:FailedTransBusAddrToStatic "));
如何制作支持VMWare的Windows CE BSP
returnFALSE;
如何制作支持VMWare的Windows CE BSP}

如何制作支持VMWare的Windows CE BSP
//SetupISRhandler
如何制作支持VMWare的Windows CE BSP
Info.SysIntr=dii.dwSysintr;
如何制作支持VMWare的Windows CE BSPInfo.CheckPort
=TRUE;
如何制作支持VMWare的Windows CE BSPInfo.PortIsIO
=(dwIOSpace)?TRUE:FALSE;
如何制作支持VMWare的Windows CE BSPInfo.UseMaskReg
=TRUE;;
如何制作支持VMWare的Windows CE BSPInfo.PortAddr
=PhysAddr+0x2;
如何制作支持VMWare的Windows CE BSPInfo.PortSize
=sizeof(WORD);
如何制作支持VMWare的Windows CE BSPInfo.MaskAddr
=PhysAddr+0x4;
如何制作支持VMWare的Windows CE BSP如何制作支持VMWare的Windows CE BSP
if(!KernelLibIoControl(pPddObject->IsrHandle,IOCTL_GIISR_INFO,&Info,sizeof(Info),NULL,0,NULL))...{
如何制作支持VMWare的Windows CE BSPDEBUGMSG(ZONE_ERROR,(L
"UHCD:KernelLibIoControlcallfailed. "));
如何制作支持VMWare的Windows CE BSP}

如何制作支持VMWare的Windows CE BSP}

如何制作支持VMWare的Windows CE BSP}

如何制作支持VMWare的Windows CE BSP
//ThePDDcansupplyabufferofcontiguousphysicalmemoryhere,orcanletthe
如何制作支持VMWare的Windows CE BSP
//MDDtrytoallocatethememoryfromsystemRAM.WewillusetheHalAllocateCommonBuffer()
如何制作支持VMWare的Windows CE BSP
//APItoallocatethememoryandbuscontrollerphysicaladdressesandpassthisinformation
如何制作支持VMWare的Windows CE BSP
//intotheMDD.
如何制作支持VMWare的Windows CE BSP如何制作支持VMWare的Windows CE BSP
if(GetRegistryPhysicalMemSize(szDriverRegKey,&pPddObject->dwPhysicalMemSize))...{
如何制作支持VMWare的Windows CE BSP
//AquarterforHighpriorityMemory.
如何制作支持VMWare的Windows CE BSP
dwHPPhysicalMemSize=pPddObject->dwPhysicalMemSize/4;
如何制作支持VMWare的Windows CE BSP
//Alignwithpagesize.
如何制作支持VMWare的Windows CE BSP
pPddObject->dwPhysicalMemSize=(pPddObject->dwPhysicalMemSize+PAGE_SIZE-1)&~(PAGE_SIZE-1);
如何制作支持VMWare的Windows CE BSPdwHPPhysicalMemSize
=((dwHPPhysicalMemSize+PAGE_SIZE-1)