要特别注意page fault,会引起系统崩溃。
中断和IRQL
中断:对应于每个硬件事件。软件也可以生成软件中断(DPC),可以用来处理硬件中断。
windows把中断传给处理器。
windows对已有线程进行中断来处理中断。
IRQL:所有中断都对应着中断级别,越高越优先。
**注意中断优先级和线程优先级的不同
PASSIVE_LEVEL:
最低的IRQL,正常线程的默认运行级别,不能产生中断,可以调用所有windows核心服务。
DISPATCH_LEVEL:
软件中断中的最高级别中断,可以调用有限的windows核心服务。
DIRQL:
驱动级别的中断,device-IRQLs,可以调用一些windows核心服务。
**要选择正确的中断级别,Driver Verifier和SDV可以用来协助解决这些错误。
并行和同步
线程和同步在驱动级别的机制和应用级别不同。
线程:
驱动不会创建线程或者在某一个具体的线程上运行。
驱动例程不会知道具体在哪个进程的哪个线程中运行。
系统只是借用已有的线程来执行驱动例程。
线程的借用:
1.应用程序在线程A中调用DeviceIoControl来向驱动发起请求。
2.I/O manager在线程A中调用dispatch routine
3.驱动处理请求,返回线程的控制权给应用程序
4.设备处理完请求后,产生硬件中断,选择一个arbitrary thread context由ISR处理,具体的线程无法由驱动决定。
5.ISR产生一个DPC进入队列,在一个更低级别的IRQL中选择一个arbitrary thread context处理DPC。
arbitrary thread context的实现:
1.选择不同的例程和不同的线程。
2.例程和线程停止,借给操作系统让更低级别IRQL运行。
同步:
用来防止race conditions
内核模式的同步和用户模式不同。
PASSIVE_LEVEL的同步
1.使用Kernel dispatcher objects
objects-event,semaphore,mutex
2.Fast mutex和resource objects
High-IRQL同步
spin lock:
当一个线程拥有spin lock时,其他要获取spin lock的线程等待。
可以在DISPATCH_LEVEL及below使用spin lock
创建对象时,可以使用spin lock对象保护该对象,并保存spin lock备用。
使用spin lock时IRQL必须升到DISPATCH_LEVEL
interrupt spin lock:
ISR需要对相关的DPC或其他ISRs同步
DIRQL中不能用spin lock,只能用interrupt spin lock
用法和spin lock一样
使用interrupt spin lock时IRQL必须升到DIRQL
Race Conditions和Dead locks
防止的两种方法:同步(使用同步对象)和序列化(序列化请求)
在free build更容易产生race condition
内核区域的内存
用户模式类似:都使用虚拟地址空间
用户模式区别:
所有内核模式驱动共享一个虚拟地址空间
用户模式进程不能访问内核模式空间
内核模式进程可以访问用户模式地址空间
内核进程访问用户空间需要一个安全的访问方法保证有效性:
驱动可以探测和锁定用户模式里的缓存。
内存管理
共同点:都要分配和释放内存,使用栈,处理faults
不同点,page faults 问题:
IRQL>=DISPATCH_LEVEL:page fault会产生bug check(IRQL_NOT_LESS_OR_EQUAL),可以使用PREfast和SDV差错
IRQL<DISPATCH_LEVEL:page fault只会产生延迟,但是会产生deadlock和double-fault crash
内存池:
驱动必须使用的内存池分配内存。
1.Paged pool:可以被paged out,用来存储<DISPATCH_LEVEL相关的数据。
2.Nonpaged pool:不能被paged out,空间有限,用来存储>=DISPATCH_LEVEL相关的数据。
kernel stack
很小而且不会增加,需要小心使用:
1.递归例程最好别使用kernel stack
2.disk I/O path对kernel stack使用很敏感
3.不要把大量数据放入stack,而是指针。
4.怎样不使用kernel stack: http://go.microsoft.com/fwlink/?LinkId=79604
MDLs
内核数据缓冲经常会以MDL方式使用,包括buffer和组成buffer的locked pages的列表
中断和IRQL
中断:对应于每个硬件事件。软件也可以生成软件中断(DPC),可以用来处理硬件中断。
windows把中断传给处理器。
windows对已有线程进行中断来处理中断。
IRQL:所有中断都对应着中断级别,越高越优先。
**注意中断优先级和线程优先级的不同
PASSIVE_LEVEL:
最低的IRQL,正常线程的默认运行级别,不能产生中断,可以调用所有windows核心服务。
DISPATCH_LEVEL:
软件中断中的最高级别中断,可以调用有限的windows核心服务。
DIRQL:
驱动级别的中断,device-IRQLs,可以调用一些windows核心服务。
**要选择正确的中断级别,Driver Verifier和SDV可以用来协助解决这些错误。
并行和同步
线程和同步在驱动级别的机制和应用级别不同。
线程:
驱动不会创建线程或者在某一个具体的线程上运行。
驱动例程不会知道具体在哪个进程的哪个线程中运行。
系统只是借用已有的线程来执行驱动例程。
线程的借用:
1.应用程序在线程A中调用DeviceIoControl来向驱动发起请求。
2.I/O manager在线程A中调用dispatch routine
3.驱动处理请求,返回线程的控制权给应用程序
4.设备处理完请求后,产生硬件中断,选择一个arbitrary thread context由ISR处理,具体的线程无法由驱动决定。
5.ISR产生一个DPC进入队列,在一个更低级别的IRQL中选择一个arbitrary thread context处理DPC。
arbitrary thread context的实现:
1.选择不同的例程和不同的线程。
2.例程和线程停止,借给操作系统让更低级别IRQL运行。
同步:
用来防止race conditions
内核模式的同步和用户模式不同。
PASSIVE_LEVEL的同步
1.使用Kernel dispatcher objects
objects-event,semaphore,mutex
2.Fast mutex和resource objects
High-IRQL同步
spin lock:
当一个线程拥有spin lock时,其他要获取spin lock的线程等待。
可以在DISPATCH_LEVEL及below使用spin lock
创建对象时,可以使用spin lock对象保护该对象,并保存spin lock备用。
使用spin lock时IRQL必须升到DISPATCH_LEVEL
interrupt spin lock:
ISR需要对相关的DPC或其他ISRs同步
DIRQL中不能用spin lock,只能用interrupt spin lock
用法和spin lock一样
使用interrupt spin lock时IRQL必须升到DIRQL
Race Conditions和Dead locks
防止的两种方法:同步(使用同步对象)和序列化(序列化请求)
在free build更容易产生race condition
内核区域的内存
用户模式类似:都使用虚拟地址空间
用户模式区别:
所有内核模式驱动共享一个虚拟地址空间
用户模式进程不能访问内核模式空间
内核模式进程可以访问用户模式地址空间
内核进程访问用户空间需要一个安全的访问方法保证有效性:
驱动可以探测和锁定用户模式里的缓存。
内存管理
共同点:都要分配和释放内存,使用栈,处理faults
不同点,page faults 问题:
IRQL>=DISPATCH_LEVEL:page fault会产生bug check(IRQL_NOT_LESS_OR_EQUAL),可以使用PREfast和SDV差错
IRQL<DISPATCH_LEVEL:page fault只会产生延迟,但是会产生deadlock和double-fault crash
内存池:
驱动必须使用的内存池分配内存。
1.Paged pool:可以被paged out,用来存储<DISPATCH_LEVEL相关的数据。
2.Nonpaged pool:不能被paged out,空间有限,用来存储>=DISPATCH_LEVEL相关的数据。
kernel stack
很小而且不会增加,需要小心使用:
1.递归例程最好别使用kernel stack
2.disk I/O path对kernel stack使用很敏感
3.不要把大量数据放入stack,而是指针。
4.怎样不使用kernel stack: http://go.microsoft.com/fwlink/?LinkId=79604
MDLs
内核数据缓冲经常会以MDL方式使用,包括buffer和组成buffer的locked pages的列表