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


     

          首先,时钟中断属于硬件中断,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,这里先不深究了

  • 相关阅读:
    微信出现BUG,发送“ 两位数字+15个句号 ”,双方系统会卡崩……
    手机 https 抓包---Charles篇
    AI通过了艺术创作图灵测试,你根本分不出来作者是不是人
    SublimeText SFTP连接Amazon EC2
    Facebook在代码里下毒,百度身受重伤。。。
    马斯克:有62%的程序员认为人工智能会被武器化 #精选AR人工智能算法
    映客创始人套现12.5亿之后,哪个行业最有可能成为未来造富神话?
    《A.I.爱》王力宏与人工智能谈恋爱 邀李开复来客串
    现代软件工程作业 – 计算最长英语单词链
    软件工程课的分数系统,和打分方法
  • 原文地址:https://www.cnblogs.com/testvt/p/5488777.html
Copyright © 2020-2023  润新知