分步加载流驱动实现启动提速

http://dev.10086.cn/cmdn/bbs/thread-13951-1-1.html

Modify BusEnum to support asynchronous driver loading
a.      Currently, the BuiltIn drivers are loaded by BusEnum.dll in a single thread. BusEnum was designed to be able to call itself. BusEnum can load other bus drivers to enumerate other buses (e.g. PCI, USB, PCCard, SD, etc). We can have BusEnum to load itself with a different bus name.
b.      Add Flags bit for asynchronous driver loading (devload.h)
i.     DEVFLAGS_LOAD_ASYNC              // load driver in a separate thread
c.      Add the registry for asynchronous bus
; BusEnum for AsyncBus. Second instance of BusEnum.dll. Launch a separate thread if DEVFLAGS_LOAD_ASYNC is set.
[HKLM\Drivers\BuiltIn\AsyncBus]
“Dll”=”BusEnum.dll”
“BusName”=”AsyncBus”
“Order”=dword:10
“Flags”=dword: DEVFLAGS_NAKEDENTRIES          ; can have DEVFLAGS_LOAD_ASYNC set if needed
“StartEvent”=”AsyncGroup”      ; waiting for this event before loading. Load immediately if not set.
d.      Change the code in BusEnum around ActivateEx() call.
if(GetLoadFlag() & DEVFLAGS_LOAD_ASYNC)
{
        ; create a thread to call ActivateDeviceEx(). The thread will first wait for the StartEvent then call ActivateDeviceEx().      
}
else
{
m_hDevice = ActivateDeviceEx(m_lpTemplateRegPath, m_dwInitRegArray,  (m_dwInitRegArray!=NULL?m_dwInitRegCount:0) , NULL);
}
e.      Identify the drivers to be put in the asynchronous loading group.
f.       Change the registry for drivers to be loaded asynchronously by replacing [HKLM\Drivers\BuiltIn\xxx] to [HKLM\Drivers\BuiltIn\AsyncGroup\xxx]
g.      Write an application to set the StartEvent event after the OS boot is complete to load the drivers in asynchronous group.

 

实现流驱动的划分(引用此文需注明来源 http://www.armce.cn WinCE家园)
这个文章讲述的是如何利用BusEnum可以Active自己的特性,把一部分不是启动的时候必须的流驱动延迟到任何时间加载(依然可以用order来控制顺序,只是可以滞后到explorer跑起来后开始)。
原理是这样的,默认的device.exe只加载一个流驱动,它就是busenum.dll,然后其他的流驱动是靠busenum.dll去遍历和Active(加载)的。因为busenum.dll也是流驱动接口的,所以它自己也可以被自己Active,上文就是利用了这个特点,对busenum.dl做了一个微妙的改动,实现了我们可以对流驱动的分批加载,让最关键的dll在出现桌面前加载,其他的都滞后,让用户可以在较短时间见到桌面。
下面来解析实现的具体原理:
默认的,你的注册表肯定有下面的项目:
[HKEY_LOCAL_MACHINE\Drivers]
    "RootKey"="Drivers\\BuiltIn"
[HKEY_LOCAL_MACHINE\Drivers\BuiltIn]
    "Dll"="BusEnum.dll"
    "BusName"="BuiltIn"
    "Flags"=dword:8
    "BusIoctl"=dword:2a0048
    "InterfaceType"=dword:0
    "IClass"=multi_sz:"{B3CC6EBA-5507-4196-8E41-2BF42E4A47C9}=%b","{6F40791D-300E-44E4-BC38-E0E63CA8375C}=%b"
设备管理器Device.exe在初始化的时候会去读上面的rootkey,然后自己加载rootkey指向的那个驱动,这里就是[HKEY_LOCAL_MACHINE\Drivers\BuiltIn],所以在这里busenum.dll就跑起来了。详细的代码自己可以去private下面check,懒的可以看我借用的一篇文章http://www.armce.cn/bbs/thread-35-1-1.html ,它分析了device.exe的初始化过程,最下一行很有意思。
接下来busenum.dll会开始遍历它键值下面的流驱动并一一加载。比如:
[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\SDMEMORY]
[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\NAND]
[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\PowerButton]
所以类似的,如果你把BusEnum.dll放到[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\hStartEvent]下面并且把她Active起来,它就会去加载所有[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\hStartEvent\*****]键值下的流驱动。

分时加载已经分组的流驱动(引用此文需注明来源 http://www.armce.cn WinCE家园)
这楼来继续接着二楼讲如何加载两个BusEnum.dll的问题,和如何从时间上把他们分开。
刚才有讲,BusEnum.dll(后启动的)自己是可以被当做普通的流驱动被BusEnum.dll(先启动的,device加载)加载的,比如下面的键值。
[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\AsyncBus]
  "Dll"="BusEnum.dll"
  "BusName"="AsyncBus"
  "Order"=dword:10;
  "Flags"=dword:0  
    "BusIoctl"=dword:2a0048
    "InterfaceType"=dword:0
    "IClass"=multi_sz:"{B3CC6EBA-5507-4196-8E41-2BF42E4A47C9}=%b","{6F40791D-300E-44E4-BC38-E0E63CA8375C}=%b"
因为处于BuiltIn下面,所以肯定会被轮询到被加载。但是就简单这么写还不行,虽然它可以实现加载[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\AsyncBus\****]的所有流驱动,但是时间上面它无法控制,它会立刻开始加载操作,无法实现我们从时间上的分批次加载驱动的目的,所以一楼的文章就介绍了一种方法,在上面的键值里面加一个flag,如下:
  "Flags"=dword:408  ; 0x400+0x8 (0x400 is the asyncbus flag)
通过修改busenum.dll的源码,让这个flag会在第二个busenum.dll被加载的时候被第一个busenum读到,我们的例子里面加入的0x400就是代码里面宏定义DEVFLAGS_LOAD_ASYNC的值,第一个busenum就可以判断这个标志不立刻走正常的遍历和加载它,延迟第二个busenum的启动。
下面是一段修改devbus.cpp的一个sample,不去ActivateDeviceEx,而是去调用线程等待启动信号。
if(GetLoadFlag() & DEVFLAGS_LOAD_ASYNC)
{
        HANDLE hAsyncLoadThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) AsyncLoadThread, this, 0, NULL);      
}
else
{
m_hDevice = ActivateDeviceEx(m_lpTemplateRegPath, m_dwInitRegArray,  (m_dwInitRegArray!=NULL?m_dwInitRegCount:0) , NULL);
}
在AsyncLoadThread的线程里面去做类似下面的事情,等待一个hStartEvent事件,以便开始加载第二个busenum.dll. hStartEvent事件要你自己手动去发,比如你可以在explorer.exe起来之后调用一个AP去发这个自定义事件。
WaitForSingleObject(hStartEvent, INFINITE);
NKDbgPrintfW(L"[busenum]Start load %s\r\n",m_lpTemplateRegPath);
   m_hDevice = ActivateDeviceEx(m_lpTemplateRegPath, m_dwInitRegArray,  (m_dwInitRegArray!=NULL?m_dwInitRegCount:0) , NULL);
         m_fDriverLoaded = (m_hDevice!=NULL);
当你的AP调用SetEvent(hStartEvent)后,第二个busenum.dll就开始加载路径位于[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\AsyncBus\****]下的所有驱动,order依然有效。

 

打印消息:
DeviceFolder:oadDevice(Drivers\BuiltIn\SDHC_ZYLONITE2) last 163 Ticks
... ...
ActivateDeviceEx busenum.dll successful.m_lpTemplateRegPath=Drivers\BuiltIn\AsyncBus.
DeviceFolder:oadDevice(Drivers\BuiltIn\PCC_ZYLONITE0) last 1 Ticks
DeviceFolder:oadDevice(Drivers\BuiltIn\PCI) last 0 Ticks
... ...

下面是我的一些代码:

注册表里:
  [HKEY_LOCAL_MACHINE\Drivers\BuiltIn\AsyncBus]
        "Dll"="BusEnum.dll"
        "Order"=dword:10
        "Flags"=dword:1000008
        "BusName"="AsyncBus"
        "LoadAsyncEvent"="Start"            ;wait for the event to load the childkey of AsyncBus
        "LoadAsyncDelay"=dword:2710    ;setup the timeout is 10s

    [HKEY_LOCAL_MACHINE\Drivers\BuiltIn\AsyncBus\SWC]
        "refix"="SWC"
        "Dll"="$(_TGTPLAT_PFX)_SWC.dll"
        "Order"=dword:1  ; Must loading after MFP driver loading   
        "Flags"=dword:0

    [HKEY_LOCAL_MACHINE\Drivers\BuiltIn\AsyncBus\RTC]
        "refix"="RTC"
        "Dll"="$(_TGTPLAT_PFX)_RTC.dll"
        "Order"=dword:2
        "Flags"=dword:0

BOOL DeviceFolder:oadDeviceAsync()
{
    WCHAR  szEventName[MAX_PATH] = {};
    DWORD  dwEventTimeout = 0;

        BOOL aa = GetRegValue(DEVLOAD_LOAD_ASYNC_EVENT_TIMEOUT_VALNAME,(LPBYTE)&dwEventTimeout,sizeof(dwEventTimeout));
               
    if (!aa)
    {
        // no timeout/delay option set.
        dwEventTimeout = INFINITE;
               
    }

        BOOL bb = GetRegValue(DEVLOAD_LOAD_ASYNC_EVENT_VALNAME,(PUCHAR)szEventName,sizeof(szEventName));
        
    if (bb)
    {
        m_hAsyncLoadStartEvent = CreateEvent(NULL, TRUE, FALSE, szEventName);

        if(m_hAsyncLoadStartEvent && dwEventTimeout)
        {
            // Wait for event or timeout
            if(WAIT_FAILED == WaitForSingleObject(m_hAsyncLoadStartEvent, dwEventTimeout))//等待加载信号或超时
            {
                return FALSE;
            }
        }
    }
    else
    {
        // No event option set. Will start loading after delay
        if(dwEventTimeout && (dwEventTimeout != INFINITE))
        {
            Sleep(dwEventTimeout);
        }
    }

    // Time to load the driver.
    m_hDevice = ActivateDeviceEx(m_lpTemplateRegPath, m_dwInitRegArray,  (m_dwInitRegArray!=NULL?m_dwInitRegCount:0) , NULL);

        if (m_hDevice)
        {        //正确加载了第2个BusEnum.dll
        RETAILMSG(1,(TEXT("ActivateDeviceEx busenum.dll successful.m_lpTemplateRegPath=%s.\r\n"), m_lpTemplateRegPath));
        }
        else
        {
                RETAILMSG(1,(TEXT("ActivateDeviceEx faild.\r\n")));
        }
        
    Lock();
    m_PendingLoadAsync = FALSE;
    m_fDriverLoaded = (m_hDevice!=NULL);
    Unlock();

    return m_fDriverLoaded;
}
#endif



BOOL DeviceFolder:oadDevice()
{
    ... ...
                m_hAsyncLoadThread = CreateThread(NULL, 0,
                                     (LPTHREAD_START_ROUTINE) AsyncLoadThread, this, CREATE_SUSPENDED, NULL);

                if(m_hAsyncLoadThread)
                {
                RETAILMSG(1,(TEXT("m_hAsyncLoadThread succeed.\r\n")));
                    Lock();
                    m_PendingLoadAsync = TRUE;
                    Unlock();

                    ResumeThread(m_hAsyncLoadThread);

                    return TRUE;
                }
                // Failed creating the async loading thread for this driver.
                return FALSE;
             }
           m_hDevice = ActivateDeviceEx(m_lpTemplateRegPath, m_dwInitRegArray,  (m_dwInitRegArray!=NULL?m_dwInitRegCount:0) , NULL);
             m_fDriverLoaded = (m_hDevice!=NULL);

         //加载任何BuiltIn下的驱动都会打印
          RETAILMSG(1,(TEXT("DeviceFolder:oadDevice(%s) last %d Ticks\r\n"),m_lpTemplateRegPath,GetTickCount()-dwStartTicks));
... ...
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值