windows内核原理分析之DPC函数的执行(2)

来源:互联网 发布:生刷枪软件下载 编辑:程序博客网 时间:2024/05/20 13:04

windows内核原理分析之DPC函数的执行(2)

需要执行DPC函数时,就通过KeInsertQueueDpc()提出DPC请求,就是把具体的KDPC结构挂入PRCB中的DPC请求队列,这常常是由中断服务程序完成的。

BOOLEAN NTAPI  KeInsertQueueDpc(IN PKDPC Dpc,                   IN PVOID SystemArgument1, IN PVOID SystemArgument2)  {      ......      ASSERT_DPC(Dpc);      /* Check IRQL and Raise it to HIGH_LEVEL */      KeRaiseIrql(HIGH_LEVEL, &OldIrql);      CurrentPrcb = KeGetCurrentPrcb();    //获取当前所在CPU的PRCB      /* Check if the DPC has more then the maximum number of CPUs */      if (Dpc->Number >= MAXIMUM_PROCESSORS)      {          /* Then substract the maximum and get that PRCB. */          Cpu = Dpc->Number - MAXIMUM_PROCESSORS;          Prcb = KiProcessorBlock[Cpu];      }      else      {          /* Use the current one */          Prcb = CurrentPrcb;          Cpu = Prcb->Number;      }      /* ROS Sanity Check */      ASSERT(Prcb == CurrentPrcb);      /* Check if this is a threaded DPC and threaded DPCs are enabled */      if ((Dpc->Type == ThreadedDpcObject) && (Prcb->ThreadDpcEnable))      {          /* Then use the threaded data */          DpcData = &Prcb->DpcData[DPC_THREADED];      }      else      {          /* Otherwise, use the regular data */          DpcData = &Prcb->DpcData[DPC_NORMAL];      }      /* Acquire the DPC lock */      KiAcquireSpinLock(&DpcData->DpcLock);      /* Get the DPC Data */      if (!InterlockedCompareExchangePointer(&Dpc->DpcData, DpcData, NULL))      {          /* Now we can play with the DPC safely */          Dpc->SystemArgument1SystemArgument1 = SystemArgument1;          Dpc->SystemArgument2SystemArgument2 = SystemArgument2;          DpcData->DpcQueueDepth++;          DpcData->DpcCount++;          DpcConfigured = TRUE;          /* Check if this is a high importance DPC */          if (Dpc->Importance == HighImportance)          {              /* Pre-empty other DPCs */              InsertHeadList(&DpcData->DpcListHead, &Dpc->DpcListEntry);          }          else          {              /* Add it at the end */              InsertTailList(&DpcData->DpcListHead, &Dpc->DpcListEntry);          }          /* Check if this is the DPC on the threaded list */          if (&Prcb->DpcData[DPC_THREADED] == DpcData)          {              /* Make sure a threaded DPC isn't already active */              if (!(Prcb->DpcThreadActive) && !(Prcb->DpcThreadRequested))              {                  /* FIXME: Setup Threaded DPC */                  DPRINT1("Threaded DPC not supported\n");                  while (TRUE);              }          }  //end if (&Prcb->DpcData[DPC_THREADED] == DpcData)          else          {              /* Make sure a DPC isn't executing already */              if (!(Prcb->DpcRoutineActive) && !(Prcb->                 DpcInterruptRequested))              {                  /* Check if this is the same CPU */                  if (Prcb != CurrentPrcb)                  {                      /* Check if the DPC is of high importance or above the                       * maximum depth. If it is, then make sure that the CPU                       * isn't idle, or that it's sleeping. */                      if (((Dpc->Importance == HighImportance) ||                          (DpcData->DpcQueueDepth >=                           Prcb->MaximumDpcQueueDepth))                           && (!(AFFINITY_MASK(Cpu) & KiIdleSummary)                          || (Prcb->Sleeping)))                      {                          /* Set interrupt requested */                          Prcb->DpcInterruptRequested = TRUE;                          /* Set DPC inserted */                          DpcInserted = TRUE;                      }                  }  //end if (Prcb != CurrentPrcb)                  else                  {                      /* Check if the DPC is of anything but                       low importance */                      if ((Dpc->Importance != LowImportance) ||                          (DpcData->DpcQueueDepth >=                          Prcb->MaximumDpcQueueDepth)                          || (Prcb->DpcRequestRate                             < Prcb->MinimumDpcRate))                      {                          /* Set interrupt requested */                          Prcb->DpcInterruptRequested = TRUE;                          /* Set DPC inserted */                          DpcInserted = TRUE;                      }                  }              }  //end if (!(Prcb->DpcRoutineActive) && !(Prcb->DpcInterrupt Requested))          }  //end if (&Prcb->DpcData[DPC_THREADED] == DpcData) else       }  //end if (!InterlockedCompareExchangePointer(&Dpc->DpcData, DpcData, NULL))      /* Release the lock */      KiReleaseSpinLock(&DpcData->DpcLock);      /* Check if the DPC was inserted */      if (DpcInserted)      {          /* Check if this was SMP */          if (Prcb != CurrentPrcb)          {              /* It was, request and IPI */              KiIpiSendRequest(AFFINITY_MASK(Cpu), IPI_DPC);          }          else          {              /* It wasn't, request an interrupt from HAL              */  //要求扫描DPC请求队列              HalRequestSoftwareInterrupt(DISPATCH_LEVEL);  //调用HalRequestSoftwareInterrupt函数        }      }      /* Lower IRQL */      KeLowerIrql(OldIrql);  //降低到原来的Irql    return DpcConfigured;  } 

这段代码是支持SMP多处理器结构的,所以不同的CPU有不同的PRCB数据结构,但是单CPU的系统只有一个PRCB。

如果将DPC请求挂入了队列,就通过HalRequestSoftwareInterrupt()将PCR中的相应标志位设置成TRUE,表示要求扫描DPC请求队列:

[KeInsertQueueDpc() > HalRequestSoftwareInterrupt()]  VOID FASTCALL HalRequestSoftwareInterrupt(IN KIRQL Request)  {    switch (Request)    {      case APC_LEVEL:        ((PKIPCR)KeGetPcr())->HalReserved[HAL_APC_REQUEST] = TRUE;        break;      case DISPATCH_LEVEL:        ((PKIPCR)KeGetPcr())->HalReserved[HAL_DPC_REQUEST] = TRUE;        break;      default:        KEBUGCHECK(0);    }  } 
0 0