不知道有没有人试过在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
950
GB
•Serial
(
COM
)
Ports
•Uptofourserial
(
COM
)
ports
USBports
•Two-portUSB
1.1
UHCIcontroller
Keyboard
•
104
-keyWindows
95
/
98
enhanced
MouseandDrawingTablets
•PS
/
2
mouse
EthernetCard
•AMDPCnet-PCIIIcompatible
Sound
•EmulatesCreativeLabsSoundBlasterAudioPCI
(
MIDIinput
,
gamecontrollersandjoysticksare
not
supported
,
except
for
USBdevices
)
其实从根本上来说,给VMWare用的Windows CE跟普通PC或者Virtual PC的并无多大区别。因此基本做法和一些概念都可以看MSDN里对CEPC的相关介绍。这里只重点介绍一些针对VMWare的不同地方。
给Windows CE用的VMWare虚拟机可以用DOS的。BSP可以直接copy一份Platform Builder带的CEPC BSP做为起始的BSP,然后在此基础上修改。从IDE硬盘、声卡、显卡、键盘鼠标的支持比较简单,用Platform Builder中现成的driver就行了。
比较麻烦的是网卡和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就基本搞定了。
附上两张运行时的截图:
附1,网卡的注册表设置,放在platform.reg里:
[HKEY_LOCAL_MACHINE
Comm
PCNTN4M]
"
DisplayName
"
=
"
PCNTN4MCompatibleEthernetDriver
"
"
Group
"
=
"
NDIS
"
"
ImagePath
"
=
"
pcntn4m.dll
"
[HKEY_LOCAL_MACHINE
Comm
PCNTN4M
Linkage]
"
Route
"
=
multi_sz:
"
PCNTN4M1
"
[HKEY_LOCAL_MACHINE
Comm
PCNTN4M1]
"
DisplayName
"
=
"
PCNTN4MCompatibleEthernetDriver
"
"
Group
"
=
"
NDIS
"
"
ImagePath
"
=
"
pcntn4m.dll
"
[HKEY_LOCAL_MACHINE
Comm
PCNTN4M1
Parms]
;
"
BusNumber
"
=
dword:
0
;
"
BusType
"
=
dword:
05
;
"
Interrupt
"
=
dword:
05
;
"
IOAddress
"
=
dword:
0300
[HKEY_LOCAL_MACHINE
Comm
Tcpip
Linkage]
"
Bind
"
=
multi_sz:
"
ppp
"
,
"
PCNTN4M1
"
;
Registryvalues
for
thepcntn4m1driver
[HKEY_LOCAL_MACHINE
Comm
PCNTN4M1
Parms
TcpIp]
;
ThisenabletheDHCP
.
InWinCE
2.1
PreviewversionstaticallyallocatedIPaddress
;
does
not
work
.
Sowe
use
theDHCPservertoallocatetheIPaddress
.
"
EnableDHCP
"
=
dword:
1
;
ThisshouldbeMULTI_SZ
"
DefaultGateway
"
=
""
;
ThisshouldbeSZ
...
If
nullitmeans
use
LAN
,
else
WANandInterface
.
"
LLInterface
"
=
""
;
Use
zero
for
broadcastaddress?
(
or
255.255
.
255.255
)
"
UseZeroBroadcast
"
=
dword:
0
;
ThusshouldbeMULTI_SZ
,
theIPaddresslist
"
IpAddress
"
=
"
0.0.0.0
"
;
ThisshouldbeMULTI_SZ
,
thesubnetmasks
for
theaboveIPaddresses
"
Subnetmask
"
=
"
0.0.0.0
"
;
;
TemplatethePCIbusdriverusestomatchaAM79C970PC-
net
card
;
[HKEY_LOCAL_MACHINE
Drivers
BuiltIn
PCI
Template
PCNTN4M]
"
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
Comm
ConnectionSharing]
"
PrivateInterface
"
=
"
PCI\PCNTN4M
"
附2,UHCI driver需要修改的代码(红色部分,在$(DRIVERS)\USB\HCD\UHC\system.csystem.c中):
//Inlinefunctions
__inlinestaticWORD
PCIConfig_ReadWord(
ULONGBusNumber,
ULONGDevice,
ULONGFunction,
ULONGOffset
)
...{
WORDRetVal=0;
PCI_SLOT_NUMBERSlotNumber;
SlotNumber.u.AsULONG=0;
SlotNumber.u.bits.DeviceNumber=Device;
SlotNumber.u.bits.FunctionNumber=Function;
HalGetBusDataByOffset(PCIConfiguration,BusNumber,SlotNumber.u.AsULONG,&RetVal,Offset,sizeof(RetVal));
returnRetVal;
}
__inlinestaticvoid
PCIConfig_Write(
ULONGBusNumber,
ULONGDevice,
ULONGFunction,
ULONGOffset,
ULONGValue,
ULONGSize
)
...{
PCI_SLOT_NUMBERSlotNumber;
SlotNumber.u.AsULONG=0;
SlotNumber.u.bits.DeviceNumber=Device;
SlotNumber.u.bits.FunctionNumber=Function;
HalSetBusDataByOffset(PCIConfiguration,BusNumber,SlotNumber.u.AsULONG,&Value,Offset,Size);
}
/**//*InitializeUHCI
*
*ConfigureandinitializeUHCIcard
*
*ReturnValue:
*ReturnTRUEifcardcouldbelocatedandconfigured,otherwiseFALSE
*/
staticBOOL
InitializeUHCI(
SUhcdPdd*pPddObject,//IN-PointertoPDDstructure
LPCWSTRszDriverRegKey)//IN-Pointertoactiveregistrykeystring
...{
PUCHARioPortBase=NULL;
DWORDdwAddrLen;
DWORDdwIOSpace;
BOOLInstallIsr=FALSE;
BOOLfResult=FALSE;
LPVOIDpobMem=NULL;
LPVOIDpobUhcd=NULL;
DWORDPhysAddr;
DWORDdwHPPhysicalMemSize;
HKEYhKey;
WORDLegSup;
DDKWINDOWINFOdwi;
DDKISRINFOdii;
DDKPCIINFOdpi;
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,szDriverRegKey,0,0,&hKey)!=ERROR_SUCCESS)...{
DEBUGMSG(ZONE_ERROR,(TEXT("InitializeUHCI:GetRegistryConfigRegOpenKeyEx(%s)failed "),
szDriverRegKey));
returnFALSE;
}
dwi.cbSize=sizeof(dwi);
dii.cbSize=sizeof(dii);
dpi.cbSize=sizeof(dpi);
if(DDKReg_GetWindowInfo(hKey,&dwi)!=ERROR_SUCCESS||
DDKReg_GetIsrInfo(hKey,&dii)!=ERROR_SUCCESS||
DDKReg_GetPciInfo(hKey,&dpi)!=ERROR_SUCCESS)...{
DEBUGMSG(ZONE_ERROR,(TEXT("InitializeUHCI:DDKReg_GetWindowInfoorDDKReg_GetWindowInfoorDDKReg_GetPciInfofailed ")));
gotoInitializeUHCI_Error;
}
if(dwi.dwNumMemWindows!=0)...{
PhysAddr=dwi.memWindows[0].dwBase;
dwAddrLen=dwi.memWindows[0].dwLen;
dwIOSpace=0;
}
elseif(dwi.dwNumIoWindows!=0)...{
PhysAddr=dwi.ioWindows[0].dwBase;
dwAddrLen=dwi.ioWindows[0].dwLen;
dwIOSpace=1;
}
else
gotoInitializeUHCI_Error;
DEBUGMSG(ZONE_INIT,(TEXT("UHCD:Readconfigfromregistry:BaseAddress:0x%X,Length:0x%X,I/OPort:%s,SysIntr:0x%X,InterfaceType:%u,BusNumber:%u "),
PhysAddr,dwAddrLen,dwIOSpace?L"YES":L"NO",dii.dwSysintr,dwi.dwInterfaceType,dwi.dwBusNumber));
ioPortBase=(PUCHAR)PhysAddr;
if(!(fResult=ConfigureUHCICard(pPddObject,&ioPortBase,dwAddrLen,dwIOSpace,dwi.dwInterfaceType,dwi.dwBusNumber)))...{
gotoInitializeUHCI_Error;
}
if(dii.szIsrDll[0]!=0&&dii.szIsrHandler[0]!=0&&dii.dwIrq<0xff&&dii.dwIrq>0)...{
//InstallISRhandler
pPddObject->IsrHandle=LoadIntChainHandler(dii.szIsrDll,dii.szIsrHandler,(BYTE)dii.dwIrq);
if(!pPddObject->IsrHandle)...{
DEBUGMSG(ZONE_ERROR,(L"UHCD:Couldn'tinstallISRhandler "));
}else...{
GIISR_INFOInfo;
PHYSICAL_ADDRESSPortAddress=...{PhysAddr,0};
DEBUGMSG(ZONE_INIT,(L"UHCD:InstalledISRhandler,Dll='%s',Handler='%s',Irq=%d ",
dii.szIsrDll,dii.szIsrHandler,dii.dwIrq));
if(!BusTransBusAddrToStatic(pPddObject->hParentBusHandle,dwi.dwInterfaceType,dwi.dwBusNumber,PortAddress,dwAddrLen,&dwIOSpace,&(PVOID)PhysAddr))...{
DEBUGMSG(ZONE_ERROR,(L"UHCD:FailedTransBusAddrToStatic "));
returnFALSE;
}
//SetupISRhandler
Info.SysIntr=dii.dwSysintr;
Info.CheckPort=TRUE;
Info.PortIsIO=(dwIOSpace)?TRUE:FALSE;
Info.UseMaskReg=TRUE;;
Info.PortAddr=PhysAddr+0x2;
Info.PortSize=sizeof(WORD);
Info.MaskAddr=PhysAddr+0x4;
if(!KernelLibIoControl(pPddObject->IsrHandle,IOCTL_GIISR_INFO,&Info,sizeof(Info),NULL,0,NULL))...{
DEBUGMSG(ZONE_ERROR,(L"UHCD:KernelLibIoControlcallfailed. "));
}
}
}
//ThePDDcansupplyabufferofcontiguousphysicalmemoryhere,orcanletthe
//MDDtrytoallocatethememoryfromsystemRAM.WewillusetheHalAllocateCommonBuffer()
//APItoallocatethememoryandbuscontrollerphysicaladdressesandpassthisinformation
//intotheMDD.
if(GetRegistryPhysicalMemSize(szDriverRegKey,&pPddObject->dwPhysicalMemSize))...{
//AquarterforHighpriorityMemory.
dwHPPhysicalMemSize=pPddObject->dwPhysicalMemSize/4;
//Alignwithpagesize.
pPddObject->dwPhysicalMemSize=(pPddObject->dwPhysicalMemSize+PAGE_SIZE-1)&~(PAGE_SIZE-1);
dwHPPhysicalMemSize=((dwHPPhysicalMemSize+PAGE_SIZE-1)color: rgb(0
分享到:
评论