以下均为个人见解,如果有错,希望大家指正,谢谢。
最近在学习Windows驱动,没办法,逃避不了对windows内存管理的学习,我向来对此比较感冒,看了好多回始终不得要领,抛砖引玉,希望仁者见仁、智者见智。
1、在直接讲述分页与非分页内存的相关知识前,还需要先了解点中断的知识。
IRQL(中断请求级别):PASSIVE_LEVEL、APC_LEVEL、DISPATCH_LEVEL、DIRQL
PASSIVE_LEVEL:较低层次的IRQL,没有被屏蔽的中断,在此级别上线程执行用户模式,可以访问分页内存。
APC_LEVEL:异步过程调用,只有APC级别的中断被屏蔽,可以访问分页内存。当异步调用过程发生时,处理器将自己的IRQL也提升到这个级别,为了与APC同步,驱动程序也提升到此级别,从而有些异步调用过程被禁止发生,有些API就无法访问。
DISPATCH_LEVEL:延迟过程调用(调度过程调用),这个级别DPC和较低的中断被屏蔽,只能访问非分页内存,能够访问的API也大大减少。在此级别上,之所以不能够访问分页内存,原因如下:调用分页内存可能会产生缺页中断,一旦产生缺页中断,CPU就得等待文件系统将磁盘数据读入内存,CPU空闲,线程调度器强制切换去执行另外一个线程体,但是线程调度和我们此时运行的代码同属一个中断级别,是不能够被中断的,然后当前线程就访问到了非法内存,导致计算机蓝屏。
DIRQL:几乎所有的中断被屏蔽,决定某个驱动具有更高优先级的方法。
2、分页内存和非分页内存
物理内存概念:PC机上有三条总线,以32位的CPU为例,它的最大寻址能力为4GB,也就意味着用户最多可以使用4GB的真是的物理内存,而事实是达不到的。原因很简单,那是因为设备提供了自己的内存,这些设备内存映射到物理内存上,虽然操作这些内存改变的是设备内存而非物理内存,其次还有一些内存存放着内核的东东,用户是不能碰的。
虚拟内存概念:CPU的内存管理单元为使用者提出了虚拟内存的概念,Ring0层和Ring3层的程序都可以操作,最终都会转换成对真实物理内存的操作。CPU中有一个32位的CR0寄存器,它其中的一个PG位用来负责告诉系统是否分页,windows启动前PG为置1,表示允许分页。DDK中PAGE_SIZE一般为4KB大小,4GB的虚拟内存被分割为1M个分页单元。有一部分单元和物理内存对应起来,但这种对应非一一对用,而是多对一的映射。那么也就会有一部分虚拟内存单元被映射成磁盘上的文件,并标记为Dirty,当系统要读取映射到磁盘文件上的虚拟内存时,系统会发出异常,异常处理函数会将磁盘文件读入内存并将标记设置为不脏。还有一部分内存单元什么也没有对应,是空的。内存管理单元之所以如此设计,其优点不言而喻。
用户模式地址和内核模式地址:用户模式地址即为低2GB的虚拟地址,高2GB的虚拟地址即为内核模式地址,用户只能访问低2GB的虚拟地址,而Ring0层的程序可以访问4GB的虚拟内存。windows的核心代码和驱动程序都是加载在高2GB的虚拟地址里,这样就提高了系统的稳健和安全,进程切换的时候只改变用户模式地址的映射。
以上为理解分页内存和非分页内存的基础,以下来看看分页内存和非分页内存:
Windows规定有些虚拟内存页面可以交换到磁盘文件中,这类内存被称为分页内存,相反的为非分页内存。
当程序的中断请求级别在DISPATCH_LEVEL之上时,包括DISPATCH_LEVEL,程序只能使用非分页内存,否则导致蓝屏死机,原因前面已经讲明。
在编译驱动程序的时候,可以指定某个例程和某个变量是否载入分页内存或者非分页内存,至于如何定义看Windows驱动开发技术详解或者网上一大堆,但是要提醒以下,在配置管理器中,不能应用DEBUG和Release模式,DDK提供的宏只在check版本中生效。
今天做的一个驱动就是,当我编译通过的时候,应用DriverMonitor加载的时候指出现:ERROR(2001)指定的驱动程序无效。。。。。。,当我重新生成配置管理器的时候,重新设置项目属性,编译通过在应用DriverMonitor,一切OK,编译环境VS2008+WDDK7600.16385.1版本。