从时钟中断到线程调度的分析(一)

 

      首先,时钟中断属于硬件中断,IRQL为28,仅次于蓝屏,电源和IPI,属于很高级别了,所以不知道接下来的调试会不会很顺利,不说了,试试看看

      擦,搜索了下,WRK居然没有时钟中断函数,看来不愧是阉割版,那看看reactos里面有没

VOID NTAPI HalpInitializePICs(IN BOOLEAN EnableInterrupts)
{
    ULONG_PTR EFlags;

    /* Save EFlags and disable interrupts */
    EFlags = __readeflags();
    _disable();  

    /* Initialize and mask the PIC */
    HalpInitializeLegacyPIC();

    /* Initialize the I/O APIC */
    ApicInitializeIOApic();

    /* Manually reserve some vectors */
    HalpVectorToIndex[APIC_CLOCK_VECTOR] = 8;
    HalpVectorToIndex[APC_VECTOR] = 99;
    HalpVectorToIndex[DISPATCH_VECTOR] = 99;

    /* Set interrupt handlers in the IDT */
    KeRegisterInterruptHandler(APIC_CLOCK_VECTOR, HalpClockInterrupt);  // 注册时钟中断函数
#ifndef _M_AMD64
    KeRegisterInterruptHandler(APC_VECTOR, HalpApcInterrupt);           // 注册APC中断函数
    KeRegisterInterruptHandler(DISPATCH_VECTOR, HalpDispatchInterrupt); // 注册DPC中断函数
#endif

    /* Register the vectors for APC and dispatch interrupts */
    HalpRegisterVector(IDT_INTERNAL, 0, APC_VECTOR, APC_LEVEL);
    HalpRegisterVector(IDT_INTERNAL, 0, DISPATCH_VECTOR, DISPATCH_LEVEL);

    /* Restore interrupt state */
    if (EnableInterrupts) EFlags |= EFLAGS_INTERRUPT_MASK;
    __writeeflags(EFlags);
}

 

    阴差阳错,搜索HalpClockInterrupt时居然看到了时钟中断,APC,和DPC的注册过程,注册过程是HalpInitializePICs初始化的,那么这个函数又是被谁调用的呢,继续跟踪发现是在HalInitSystem中被调用的

windows真不要脸,这个函数也没公布,只公布了原型:

     HalInitSystem (IN ULONG Phase,IN PLOADER_PARAMETER_BLOCK LoaderBlock);

看原型,这跟Reactos中定义的一样啊,所以还是看看reactos吧:
BOOLEAN NTAPI INIT_FUNCTION HalInitSystem(IN ULONG BootPhase,IN PLOADER_PARAMETER_BLOCK LoaderBlock) { PKPRCB Prcb
= KeGetCurrentPrcb(); /* Check the boot phase */ if (BootPhase == 0) // 看情况是阶段0初始化的时候,才能注册时钟中断 { /* Phase 0... save bus type */ HalpBusType = LoaderBlock->u.I386.MachineType & 0xFF; /* Get command-line parameters */ HalpGetParameters(LoaderBlock); /* Check for PRCB version mismatch */ if (Prcb->MajorVersion != PRCB_MAJOR_VERSION) { /* No match, bugcheck */ KeBugCheckEx(MISMATCHED_HAL, 1, Prcb->MajorVersion, PRCB_MAJOR_VERSION, 0); } /* Checked/free HAL requires checked/free kernel */ if (Prcb->BuildType != HalpBuildType) { /* No match, bugcheck */ KeBugCheckEx(MISMATCHED_HAL, 2, Prcb->BuildType, HalpBuildType, 0); } /* Initialize ACPI */ HalpSetupAcpiPhase0(LoaderBlock); /* Initialize the PICs */ HalpInitializePICs(TRUE); // 这个函数会调用函数进行时钟中断,APC,DPC的注册 /* Initialize CMOS lock */ KeInitializeSpinLock(&HalpSystemHardwareLock); /* Initialize CMOS */ HalpInitializeCmos(); /* Fill out the dispatch tables */ HalQuerySystemInformation = HaliQuerySystemInformation; HalSetSystemInformation = HaliSetSystemInformation; HalInitPnpDriver = HaliInitPnpDriver; HalGetDmaAdapter = HalpGetDmaAdapter; HalGetInterruptTranslator = NULL; // FIXME: TODO HalResetDisplay = HalpBiosDisplayReset; HalHaltSystem = HaliHaltSystem; /* Setup I/O space */ HalpDefaultIoSpace.Next = HalpAddressUsageList; HalpAddressUsageList = &HalpDefaultIoSpace; /* Setup busy waiting */ HalpCalibrateStallExecution(); /* Initialize the clock */ HalpInitializeClock(); /* * We could be rebooting with a pending profile interrupt, * so clear it here before interrupts are enabled */ HalStopProfileInterrupt(ProfileTime); /* Do some HAL-specific initialization */ HalpInitPhase0(LoaderBlock); } else if (BootPhase == 1) { /* Initialize bus handlers */ HalpInitBusHandlers(); /* Do some HAL-specific initialization */ HalpInitPhase1(); } /* All done, return */ return TRUE; }

       至于HalInitSystem是什么,这个基本搞过内核的都知道,内核初始化的时候会调用这个函数,看了下Reactos是直接设置了入口点,所以回到WRK,看看HalInitSystem是什么时间调用的

VOID ExpInitializeExecutive(IN ULONG Number,IN PLOADER_PARAMETER_BLOCK LoaderBlock) 
{
  ......

    if (HalInitSystem(InitializationPhase, LoaderBlock) == FALSE) {
      KeBugCheck(HAL_INITIALIZATION_FAILED);
    }

  ......
}

      跟到这里就没必要往上跟踪了,在往上就是内核入口函数了,这里附加一个内核原理与实现书上的一张图

 所以可以总结下时钟中断/APC/DPC注册的流程了:

   KiSystemStartUp->KiInitlizeKernel->ExpInitializeExecutive->HalInitSystem->HalpInitializePICs->注册中断

 

好了,以上都是理论,现在测试下, 启动windbg,这里要设置系统初始断点,以上其他函数的执行过程省略,直接从ExpInitializeExecutive开始

通过参数可以看到,传递给HalInitSystem的参数是0,代表是内核阶段0初始化,继续跟踪

HalInitSystem会判断是阶段0还是阶段1,这里是阶段0,所以会调用HalpInitializePICs注册时钟中断,但是可能因为硬件的问题,调用的不是APIC.C中的HalpInitializePICs,而是PIC中的HalpInitializePICs,这里先不深究了

 

posted @ 2016-05-13 11:30  极点寸芒  阅读(589)  评论(0编辑  收藏  举报