原文章出处:http://blog.sina.com.cn/s/blog_455851af0100d2za.html
原作者:phosphor88
WINCE是一个保护模式的操作系统,程序的访问只能使用虚拟内存。WINCE对整个系统实现了线性的32位(4GB)的虚拟地址空间,由CE操作系统启动时创建,由MMU进行管理。因此,在内核初始化和启动MMU之前,不能使用虚拟地址,这意味着bootloader和OAL中部分内存访问不能使用虚拟内存,而必须使用物理内存。
WINCE提供的4GB虚拟地址空间被分为两个2GB的区域,上面的2GB为内核空间,下面的2GB为用户空间,内核空间只能由且有KMODE优先权的线程访问,用户空间是为运行用户应用程序而准备的,可以由除了进程空间保护限制的所有线程访问。用户空间被分为64个32MB的Slot,Slot1~Slot32保留给要加载的每一个进程,WINCE最多同时可以运行32个进行,每个进程战胜一个Slot,而Slot0是一个特殊的Slot,当前正在运行的进程总是被映射到Slot0。
对于ARM架构的CPU,在WINCE内核的启动过程中,内核会将系统所有的物理内存地址全部映射到0X80000000以上的虚拟地址空间中以供内核以后使用,这种物理地址到虚拟地址的映射是由OEM在OAL中通过OEMAddressTable来定义的。
在动态虚拟地址的映射过程中,需要用到以下三个函数:
VirtualAlloc;
VirtualCopy;
VirtualFree.
函数VirtualAlloc用于在用户的进程空间中为要映射的物理地址保存需要大小的一块虚拟地址空间;紧接着VirtualCopy用于将实际的物理地址对应给VirtualAlloc刚才保留的虚拟地址空间,以完成物理地址与虚拟地址空间的绑定;而VirtualFree用于当不再需要访问这段内存时解除上面物理与虚拟地址空间的绑定,并释放保留的虚拟地址空间。
以下为VirtualAlloc,VirtualFree的使用例程:
PRIVATE BOOL
SER_VirtualAlloc(VOID)
{
BOOL r = FALSE;
RETAILMSG(DEBUGMODE,(TEXT("::: SER_VirtualAlloc()\r\n")));
do
{
v_pIOPregs =(volatile IOPreg *)SER_RegAlloc((PVOID)IOP_BASE,sizeof(IOPreg));
if (v_pIOPregs ==NULL)
{
ERRORMSG(1,(TEXT("ForIOPreg: VirtualAlloc failed!\r\n")));
break;
}
v_pUART0regs =(volatile UART0reg *)SER_RegAlloc((PVOID)UART0_BASE,sizeof(UART0reg));
if (v_pUART0regs== NULL)
{
ERRORMSG(1,(TEXT("For UART0reg:VirtualAlloc failed!\r\n")));
break;
}
v_pUART1regs =(volatile UART1reg *)SER_RegAlloc((PVOID)UART1_BASE,sizeof(UART1reg));
if (v_pUART1regs== NULL)
{
ERRORMSG(1,(TEXT("For UART1reg:VirtualAlloc failed!\r\n")));
break;
}
v_pUART2regs =(volatile UART2reg *)SER_RegAlloc((PVOID)UART2_BASE,sizeof(UART2reg));
if (v_pUART2regs== NULL)
{
ERRORMSG(1,(TEXT("For UART2reg:VirtualAlloc failed!\r\n")));
break;
}
v_pINTregs =(volatile INTreg *)SER_RegAlloc((PVOID)INT_BASE,sizeof(INTreg));
if (v_pINTregs ==NULL)
{
ERRORMSG(1,(TEXT("For INTregs:VirtualAlloc failed!\r\n")));
break;
}
v_pPWMregs =(volatile PWMreg *)SER_RegAlloc((PVOID)PWM_BASE,sizeof(PWMreg));
if (v_pPWMregs ==NULL)
{
ERRORMSG(1,(TEXT("For PWMregs:VirtualAlloc failed!\r\n")));
break;
}
r = TRUE;
} while (0);
if (!r)
{
SER_VirtualFree();
RETAILMSG(DEBUGMODE,(TEXT(":::SER_VirtualAlloc() - Fail\r\n")));
}
else
{
RETAILMSG(DEBUGMODE,(TEXT(":::SER_VirtualAlloc() - Success\r\n")));
}
return r;
}
PRIVATE void
SER_VirtualFree(VOID)
{
RETAILMSG(DEBUGMODE,(TEXT("::: SER_VirtualFree()\r\n")));
if (v_pIOPregs)
{
VirtualFree((PVOID)v_pIOPregs, sizeof(IOPreg), MEM_RELEASE);
v_pIOPregs = NULL;
}
if (v_pUART0regs)
{
VirtualFree((PVOID)v_pUART0regs, sizeof(UART0reg),MEM_RELEASE);
v_pUART0regs = NULL;
}
if (v_pUART1regs)
{
VirtualFree((PVOID)v_pUART1regs, sizeof(UART1reg),MEM_RELEASE);
v_pUART1regs = NULL;
}
if (v_pUART2regs)
{
VirtualFree((PVOID)v_pUART2regs, sizeof(UART2reg),MEM_RELEASE);
v_pUART2regs = NULL;
}
if (v_pINTregs)
{
VirtualFree((PVOID)v_pINTregs, sizeof(INTreg), MEM_RELEASE);
v_pINTregs = NULL;
}
if (v_pPWMregs)
{
VirtualFree((PVOID)v_pPWMregs, sizeof(INTreg), MEM_RELEASE);
v_pPWMregs = NULL;
}
}
PRIVATE PVOID
SER_RegAlloc(PVOID addr, INT sz)
{
PVOID reg;
reg = (PVOID)VirtualAlloc(0, sz,MEM_RESERVE, PAGE_NOACCESS);
if (reg)
{
if(!VirtualCopy(reg, addr, sz, PAGE_READWRITE | PAGE_NOCACHE ))
{
VirtualFree(reg,sz, MEM_RELEASE);
reg= NULL;
}
}
return reg;
}