zoukankan      html  css  js  c++  java
  • IRQL Ring0实现

    一,IRQL的定义
    Interrupt ReQuest Level
         DDK对IRQL的定义是:中断请求级(IRQL)标示中断的优先级。处理器在一个IRQL上执行线程代码,IRQL是帮助决定线程如何被中断的。每个处理器都有自己的中断IRQL。 在同一处理器上,线程只能被更高级别IRQL的线程能中断。也就是说,较高IRQL的中断能够中断其它的任务或具有较低IRQL的中断,所有拥有与当前IRQL相同或更低的IRQL的中断将被屏蔽,直到它在较高IRQL中断服务程序结束后,得到再次执行的机会。

    二,常见的IRQL
         Windows大部分时间都运行在软件中断级别中,即0-2级别。当有设备中断来临时,windows会将IRQL提升至硬件中断级别(DIRQL, DEVICE INTERRUPT REQUEST LEVEL),并且运行相应的硬件中断处理函数。当硬件中断结束后,恢复到原来的IRQL。
        
         我们经常遇见的有四种IRQL级别。“Passive”, “APC”, “Dispatch” and “DIRQL”。“DriverEntry”将会在PASSIVE_LEVEL被调用。
         #define PASSIVE_LEVEL 0
         #define APC_LEVEL 1
         #define DISPATCH_LEVEL 2
         #define PROFILE_LEVEL 27
         #define CLOCK1_LEVEL 28
         #define CLOCK2_LEVEL 28
         #define IPI_LEVEL 29
         #define POWER_LEVEL 30
         #define HIGH_LEVEL 31
         
         PASSIVE_LEVEL
         IRQL最低级别,没有被屏蔽的中断,在这个级别上,线程执行用户模式,可以访问分页内存。
         用户模式的代码是运行在最低级别的PASSIVE_LEVEL中,驱动程序的DriverEntry函数,派遣函数,AddDevice函数一般运行在PASSIVE_LEVEL中(驱动程序的StartIO和DPC函数运行在DISPATCH_LEVEL中),它们在必要的时候可以申请进入DISPATCH_LEVEL级别,使用内核函数KeGetCurrentIrql()可以知道系统的当前IRQL。

         APC_LEVEL
         在这个级别上,只有APC级别的中断被屏蔽,可以访问分页内存。当有APC发生时,处理器提升到APC级别,这样,就屏蔽掉其它APC,为了和APC执行 一些同步,驱动程序可以手动提升到这个级别。APC级别仅仅比PASSIVE_LEVEL高,这也是在一个线程中插入一个APC可以打断该线程(如果该线程运行在PASSIVE_LEVEL上)运行的原因。

         DISPATCH_LEVEL
         DISPATCH_LEVEL是一个重要的区分点,他代表了线程调度器正在运行。一个处理器运行在此IRQL上,代表他可能正在做两件事之一:正在进行线程调度;正在处理一个硬件中断的后半部(不那么重要的部分),这被称为DPC(Deferred Procedure Call:延迟调用)。
         这个级别,DPC(延迟过程) 和更低的中断被屏蔽,不能访问分页内存,所有的被访问的内存不能分页。因为只能处理分页内存,所以在这个级别,能够访问的Api大大减少。
         Windows负责线程调度的组件运行在DISPATCH_LEVEL级别,当前线程运行完时间片后,操作系统自动从PASSIVE_LEVEL提升至DISPATCH_LEVEL级别,从而可以使得线程调度组件可以调度其他的线程。当线程切换完成后,操作系统又从DISPATCH_LEVEL级别恢复到PASSIVE_LEVEL级别。

         DIRQL (Device IRQL)
         通常处于高层次的驱动程序不会使用这个IRQL等级,在这个等级上所有的中断都会被忽略。这是IRQL的最高等级。通常使用这个来判断设备的优先级。
    一般的,更高级的驱动在这个级别上不处理IRQL,但是几乎所有的中断被屏蔽,这实际上是IRQL的一个范围,这是一个决定某个驱动有更高的优先级的方法。

    三,IRQL与线程优先级
         线程优先级的概念不同于IRQL,只有应用程序在PASSIVE_LEVEL运行的时候才有意义。程序员可以设定线程优先级(可以使用API SetThreadPriority)。优先级高代表可以有更多机会在CPU上运行。当线程调度内核组件运行于DISPATCH_LEVEL的时候,所有应用程序的线程都停止,等着被调度。
         一个运行中的线程,它的优先级可能有以下两种类型,每种类型有16个层次:
         1,可变的优先级
         可变的优先级类的数值范围是0到15,大多数的线程都属于这种类型。属于可变优先级的线程总是可抢先的,也就是说,他们共同在相同的IRQL层和其它的线程一起被系统调度,并构成一个循环。
         通常情况下,内核是这样处理一个可变优先级线程的,当线程是一个与用户交互的线程时,它的优先级最高,其它线程
    的优先级随着运行时间片的增长而下降,直到到达最初程序设计者定义的基本优先级层次。
         2,实时优先级
         实时优先级类别的范围数值是16到31。这种类型的线程通常用于临界区线程,只能由一个拥有较高优先级的线程产生可抢先的线程。
         
         要注意的是,无论线程的优先级属性是多少,都会被一个软件或硬件中断所抢先。线程的优先级只影响系统线程调度程序的决策。调度程序运行于DISPATCH_LEVEL级,它将基于线程的优先级来决定一个线程何时该运行及这个线程将会获得多少时间片,同时确定其它所有线程的状态。

    四,IRQL与内存分页
         在使用内存分页时,可能会导致页故障。因为分页内存随时可能从物理内存交换到磁盘文件,读取不在物理内存中的分页内存时,会引发一个页故障,从而执行这个异常的处理函数。异常处理函数会将磁盘文件的内容重新交换到物理内存中。     
         页故障允许出现在PASSIVE_LEVEL级别的程序中,但如果在DISPATCH_LEVEL或更高的IRQL的程序中会带来系统崩溃。     
         因此,对于等于或高于DISPATCH_LEVEL级别的程序不能使用分页内存。
    当程序的中断请求在DISPATCH_LEVEL以上,包括DISPATCH_LEVEL,程序只能使用非分页内存,否则将导致蓝屏死机

    #define PAGED_CODE() PAGED_ASSERT(KeGetCurrentIrql() <= APC_LEVEL);

    PAGED_CODE() 是DDk提供的宏,在check版本中生效。他会检查这个函数是否低于DISPATCH_LEVEL的终端请求,如果等于或高于这个中断请求级,将会产生这个断言

     简单实现代码

      1 #include "IRQL.h"
      2 
      3 //bp IRQL!DriverEntry
      4 void Sub_1();
      5 
      6 NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegisterPath)
      7 {
      8     NTSTATUS Status = STATUS_SUCCESS;
      9     PDEVICE_OBJECT  DeviceObject = NULL;
     10     
     11     //KIRQL Irql;
     12     KIRQL NewIrql;
     13     KIRQL OldIrql;
     14 
     15     int* v1 = NULL;
     16     int* v2 = NULL;
     17 
     18     DriverObject->DriverUnload = DriverUnload;
     19     
     20 
     21     Sub_1();
     22     
     23     NewIrql = APC_LEVEL;
     24 
     25     KeRaiseIrql(NewIrql, &OldIrql);
     26     
     27     Sub_1();
     28 
     29     v1 = ExAllocatePool(NonPagedPool, sizeof(int));
     30     v2 = ExAllocatePool(PagedPool, sizeof(int));//DispatchLevel不能用分页内存
     31 
     32     //APC_LEVEL下的申请内存可以是分页也可以是不分页,
     33     
     34     /*
     35     页故障允许出现在PASSIVE_LEVEL级别的程序中,但如果在DISPATCH_LEVEL或更高的        IRQL的程序中会带来系统崩溃。   
     36    */
     37 
     38     ExFreePool(v1);
     39     ExFreePool(v2);
     40 
     41     /*
     42     KeGetCurrentIrql
     43     KeRaiseIrql
     44     KeLowerIrql
     45     */
     46     KeLowerIrql(OldIrql);
     47     Sub_1();
     48     
     49 
     50 
     51 
     52     /*
     53     PASSIVE_LEVEL
     54     APC_LEVEL
     55     DISPATCH_LEVEL
     56 
     57 
     58 
     59 // Interrupt Request Level definitions
     60 //
     61 
     62 #define PASSIVE_LEVEL 0             // Passive release level
     63 #define LOW_LEVEL 0                 // Lowest interrupt level
     64 #define APC_LEVEL 1                 // APC interrupt level
     65 #define DISPATCH_LEVEL 2            // Dispatcher level
     66 #define CMCI_LEVEL 5                // CMCI handler level
     67 
     68 #define PROFILE_LEVEL 27            // timer used for profiling.
     69 #define CLOCK1_LEVEL 28             // Interval clock 1 level - Not used on x86
     70 #define CLOCK2_LEVEL 28             // Interval clock 2 level
     71 #define IPI_LEVEL 29                // Interprocessor interrupt level
     72 #define POWER_LEVEL 30              // Power failure level
     73 #define HIGH_LEVEL 31               // Highest interrupt level
     74 
     75 #define CLOCK_LEVEL                 (CLOCK2_LEVEL)
     76 
     77 
     78     
     79     */
     80 
     81 
     82 
     83     return Status;
     84 }
     85 
     86 void Sub_1()
     87 {
     88     KIRQL Irql;
     89     Irql = KeGetCurrentIrql();//passive_level
     90     switch (Irql)
     91     {
     92     case PASSIVE_LEVEL:
     93     {
     94         DbgPrint("PASSIVE_LEVEL
    ");
     95         break;
     96 
     97     }
     98     case APC_LEVEL:
     99     {
    100         DbgPrint("APC_LEVEL
    ");
    101 
    102         break;
    103     }
    104     case DISPATCH_LEVEL:
    105     {
    106         DbgPrint("DISPATCH_LEVEL
    ");
    107 
    108         break;
    109     }
    110 
    111     }
    112 
    113 
    114 }
    115 
    116 
    117 VOID DriverUnload(PDRIVER_OBJECT DriverObject)
    118 {
    119     DbgPrint("DriverUnload()
    ");
    120 }

    >=DISPATCH_LEVEL,程序只能使用非分页内存,这里用PAGED_CODE产生断言

      1 #include "IRQL_ApcLevel_Dispatch_Level.h"
      2 
      3 //bp IRQL_ApcLevel_Dispatch_Level!DriverEntry
      4 
      5 
      6 
      7 KIRQL __NewIrql;
      8 KIRQL __OldIrql;
      9 
     10 
     11 void ShowIrql();
     12 void ApcLevel();
     13 void DispatchLevel();
     14 
     15 NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegisterPath)
     16 {
     17     NTSTATUS Status = STATUS_SUCCESS;
     18     PDEVICE_OBJECT  DeviceObject = NULL;
     19     
     20     
     21     DriverObject->DriverUnload = DriverUnload;
     22     
     23     
     24     ApcLevel();
     25 
     26 
     27 
     28 
     29     __NewIrql = DISPATCH_LEVEL;
     30 
     31     KeRaiseIrql(__NewIrql, &__OldIrql);
     32     DispatchLevel();
     33 
     34 
     35     /*
     36     PASSIVE_LEVEL
     37     APC_LEVEL
     38     DISPATCH_LEVEL
     39 
     40 
     41 
     42 // Interrupt Request Level definitions
     43 //
     44 
     45 #define PASSIVE_LEVEL 0             // Passive release level
     46 #define LOW_LEVEL 0                 // Lowest interrupt level
     47 #define APC_LEVEL 1                 // APC interrupt level
     48 #define DISPATCH_LEVEL 2            // Dispatcher level
     49 #define CMCI_LEVEL 5                // CMCI handler level
     50 
     51 #define PROFILE_LEVEL 27            // timer used for profiling.
     52 #define CLOCK1_LEVEL 28             // Interval clock 1 level - Not used on x86
     53 #define CLOCK2_LEVEL 28             // Interval clock 2 level
     54 #define IPI_LEVEL 29                // Interprocessor interrupt level
     55 #define POWER_LEVEL 30              // Power failure level
     56 #define HIGH_LEVEL 31               // Highest interrupt level
     57 
     58 #define CLOCK_LEVEL                 (CLOCK2_LEVEL)
     59 
     60 
     61     
     62     */
     63 
     64 
     65 
     66     return Status;
     67 }
     68 
     69 
     70 void ApcLevel()
     71 {
     72     DbgPrint("In Apc
    ");
     73     int* v1 = NULL;
     74     int* v2 = NULL;
     75 
     76     ShowIrql();
     77 
     78     __NewIrql = APC_LEVEL;
     79 
     80     KeRaiseIrql(__NewIrql, &__OldIrql);
     81     
     82     ShowIrql();
     83 
     84     v1 = ExAllocatePool(NonPagedPool, sizeof(int));
     85     v2 = ExAllocatePool(PagedPool, sizeof(int));//Dispatch不能用分页内存
     86 
     87     //APC_LEVEL下的申请内存可以是分页也可以是不分页
     88 
     89 
     90     ExFreePool(v1);
     91     ExFreePool(v2);
     92 
     93 
     94     KeLowerIrql(__OldIrql);
     95 }
     96 
     97 #pragma PAGEDCODE  //使函数加载到分页内存中
     98 //#pragma LOCKEDCODE //使函数加载到未分页内存中
     99 void DispatchLevel()
    100 {
    101     PAGED_CODE();
    102     //#define PAGED_CODE() PAGED_ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
    103 
    104     //PAGED_CODE() 是DDk提供的宏,在check版本中生效。
    105     //他会检查这个函数是否低于DISPATCH_LEVEL的终端请求,
    106     //如果等于或高于这个中断请求级,将会产生这个断言。
    107 
    108 
    109 
    110 
    111     DbgPrint("In Dispatch
    ");
    112     int* v1 = NULL;
    113     int* v2 = NULL;
    114 
    115     ShowIrql();
    116 
    117     __NewIrql = DISPATCH_LEVEL;
    118 
    119     KeRaiseIrql(__NewIrql, &__OldIrql);
    120     
    121 
    122 
    123 
    124     ShowIrql();
    125 
    126     v1 = ExAllocatePool(NonPagedPool, sizeof(int));
    127     v2 = ExAllocatePool(PagedPool, sizeof(int));//Dispatch不能用分页内存
    128 
    129     //APC_LEVEL下的申请内存可以是分页也可以是不分页
    130 
    131 
    132     ExFreePool(v1);
    133     ExFreePool(v2);
    134 
    135     
    136     KeLowerIrql(__OldIrql);
    137 }
    138 
    139 void ShowIrql()
    140 {
    141     KIRQL Irql;
    142     Irql = KeGetCurrentIrql();//passive_level
    143     switch (Irql)
    144     {
    145     case PASSIVE_LEVEL:
    146     {
    147         DbgPrint("PASSIVE_LEVEL
    ");
    148         break;
    149 
    150     }
    151     case APC_LEVEL:
    152     {
    153         DbgPrint("APC_LEVEL
    ");
    154 
    155         break;
    156     }
    157     case DISPATCH_LEVEL:
    158     {
    159         DbgPrint("DISPATCH_LEVEL
    ");
    160 
    161         break;
    162     }
    163 
    164     }
    165 
    166 
    167 }
    168 
    169 
    170 VOID DriverUnload(PDRIVER_OBJECT DriverObject)
    171 {
    172     DbgPrint("DriverUnload()
    ");
    173 }
  • 相关阅读:
    js作用域
    正则表达式方法
    for-in
    关于this
    由indexOf引发的一系列探究和思考
    Html第一个程序
    转:1.ASP.Net MVC开发基础学习笔记;2.HtmlHelper与扩展方法
    转:单例模式
    转:ORM框架EF(Entity framework)实体框架
    C#lambda表达式
  • 原文地址:https://www.cnblogs.com/1228073191Blog/p/7496342.html
Copyright © 2011-2022 走看看