WINCE5.0和WINCE6.0的内存与系统架构
http://topic.csdn.net/u/20090410/14/75bba2cb-cefc-4ca5-b4f5-4165bbf16006.html
http://wenku.baidu.com/view/b7adad4bcf84b9d528ea7ab0.html
http://msdn.microsoft.com/en-us/library/bb331824.aspx
http://www.msdnwebcast.com/
1.WINCE5.0
1.1 WINCE5.0的内存架构
因为WINCE是32位的嵌入式操作系统,所以WINCE的虚拟寻址能力可达4GB(为什呢,2^32=4GB),但是WINCE5.0和XP操作系统的每个进程独享4GB虚拟地址空间不同,WINCE5.0中所有的进程共享一个4GB的虚拟地址空间。这4GB的虚拟地址空间被分为两个2GB的区域,其中低地址的那2GB区域(0x00000000 ~ 0x7FFFFFFF)是用户虚拟空间,这块虚拟空间由应用程序的共用,也就是说应用程序申请的内存都会从低2GB虚拟内存空间分配的;而高2GB区域(0x80000000 ~ 0xFFFFFFFF)是操作系统的内核虚拟空间,供WINCE操作系统本身使用。
我们知道WINCE5.0的进程数量最多只能达到32个,而且每个进程只能独享32MB的虚拟空间(这个32MB的空间也叫一个slot),这33个进程(32+1,这个1就是指slot0,因为slot0用于映射当前在处理器上执行的线程所在的进程)占用的虚拟空间0x00000000~0x41FFFFFF(slot0~slot32),slot33~slot63对应的虚拟地址空间是0x42000000~0x7FFFFFFF,这块虚拟地址空间是由所有的进程共享的,如果每个进程独享的32MB虚拟地址空间不够用,那么进程可以在这个范围申请虚拟地址空间,这个范围包括对象存储和内存映射文件(.map文件,每个进程都有自己的map文件)。此范围的最后一个slot(slot63)从0x7E000000~0x7FFFFFFF用来存放纯资源DLL。如果某个DLL里面只有资源信息(比如图标、位图、对话框及字符串表灯),这个DLL就会被加载到这个空间内。
从0x80000000开始是WINCE内核使用的虚拟内存空间,其中0x80000000~0x9FFFFFFF(512MB)这段用来静态所有的物理地址,也就是说WINCE会把所有的物理内存1:1地址映射到这段虚拟内存上,这也就是WINCE最大支持的物理内存是512MB的由来。0xA0000000~0xBFFFFFFF(512MB)这段虚拟地址会重复映射所有的物理地址,这段对物理内存的映射与0x80000000这段最大的不同是从0x80000000开始的一段虚拟内存(何宗键老师这里写得是物理内存)是有缓冲的,而从0xA0000000开始的一段是没有缓冲的。通常,缓冲可以提高系统的I/O效率(why,有待进一步理解),但是对于一些OAL或者bootloader或者驱动来说,使用缓冲有可能会造成灾难性的后果,因为缓冲有可能会更改我们对设备的写操作顺序,因此在驱动程序中如果直接访问设备的I/O或寄存器,那么通常使用0xA0000000这段内存地址。
物理内存被映射到内核空间之后,WINCE内核如果要访问某个物理内存地址,就只需要把该物理地址加上0x80000000或者0xC0000000就可以了,这样简便的方式只能由WINCE内核使用,通常的应用程序是无法享受这种便利的。
0xC2000000~0xC3FFFFFF是slot97,此slot97是WINCE5.0的核心进程
NK.EXE,可见实现WINCE5.0操作系统的一些主要功能的NK.EXE本身的地址空间还是在和心态中的,0xE0000000~0xFFFFFFFF这段最高的地址是内核使用的地址空间,对于不同的处理器体系结构,这里保存着不同的内容,通常会放置一些供虚拟内存用的页表和中断向量表等内核使用的数据结构。
从上图我们就slot0来看看一个进程中虚拟地址空间的使用情况。一个进程的32MB虚拟地址空间中,最低的64KB地址(0x000000~0x00010000)是用来捕获野指针的,通常是空指针NULL的,如果某个指针访问了低于64KB的内存区域,那么WINCE就可以捕捉到这个错误,但是这样并不能捕获代码中所有的野指针。
64KB之上是进程的代码、数据以及堆和栈,进程申请虚拟内存是从低地址向高地址增长的。从每个32MB虚拟地址空间最高地址开始,存放的是进程加载的ROM DLL的读写数据以及RAM DLL的数据(ROM DLL的代码对所有的进程来说可以共享一个拷贝,放在slot1中,但对于DLL的数据,就不得不为每个进程设立单独的拷贝),DLL代码和数据的增长是从高地址向低地址增长的,如果这两个高低增长相遇,那么就表示进程已经耗尽了它的虚拟地址空间,就算此时有能还有多余的物理内存,但是无法使用它了,因为进程的虚拟地址空间已经用完了。
我们知道虚拟内存的申请是以64KB为边界的,这对进程加载DLL有非常重要的影响,这也就意味着每个DLL的都要至少占用64KB虚拟地址空间,从理论上来说每个进程只能加载512个DLL。要记住所有的ROM XIP DLL都会被映射到进程的虚拟地址空间中,因为进程有可能访问任何一个XIP DLL。通常一个没有图形界面的WINCE操作系统就会包含有100个左右这样的DLL,一个含有图形界面的正常WINCE包含的这种DLL更多,因此这个问题应该引起重视。可以采取一些方法避免虚拟内存耗尽,例如把几个不到64KB的小DLL合并成为一个大的DLL。
1.2 WINCE5.0的系统架构
2.WINCE6.0
2.1 WINCE6.0的内存架构
⑴WINCE6.0支持最大32000个进程。
⑵每个进程独自占用2G虚拟地址空间。
⑶统一/一元化的内核(unified kernel),把关键性的OS部分移到内核空间。
***和WINCE5.0类似,2G的用户空间被分为两部分。
***最低64KB,被系统用来捕获野指针。
***低1GB的地址空间用来加载进程的代码、数据、堆、栈等
***0x40000000~0x5FFFFFFF(512MB),这段虚拟内存空间用于加载所有的用户进行的DLL代码和数据。
***0x60000000~0x6FFFFFFF(256MB)这段内存分配给内存映射文件MMF(memory mapped files)。
***0x70000000~0x7FEFFFFF这段内存是内核程序和用户进程间的共享堆,实现内核程序和用户进程间通信(无需通过API),此区域用户程序可读,但OS可写。
***0x7FF00000~0x7FFFFFFF这段内存不可访问,作为用户和核心间的缓存。
***低1GB是静态虚拟地址。
***0xC0000000~0xC7FFFFFF(128MB)用于内核加载的XIP DLLs。
***0xC8000000~0xCFFFFFFFF(128MB)是文件系统的对象存储区。
***0xD000000~0xDFFFFFF(512MB)是内核模式的程序执行区。
***0xF000000~0xFFFFFFFF用于捕获系统调用,包含核心数据页。
WINCE6.0系统被划分为user mode(用户模式)和kernel mode(内核模式)两个“层”,CoreDLL同时出现在两个层中,驱动程序也移到了内核中,以前的.exe基本上都变成了.dll
3. WINCE5.0和WINCE6.0的OAL design