reactos操作系统实现(83)

前面已经分析了函数IopInitializeSystemDrivers的过程,在这个函数里加载注册表里指定的驱动程序。遍历了所有驱动程序,并通过调用函数IopLoadDriver来实现加载。也许你会问,驱动程序一般什么时候加载呢?其实在ReactOS里有三种情况,一种是在Freeloader引导时,加载内核时一起加载的驱动程序。一种是函数IopInitializeSystemDrivers里根据注册表来加载,最后一种是动态地加载,也即是PnP加载。那么驱动程序到底是什么样的程序呢?其实驱动程序就是一个动态连接库,只不过它只能调用内核的基本函数,而不能调用其它系统的DLL函数。加载一个驱动程序的过程,其实就是把驱动程序读取到内存,然后调用它的入口函数。IopLoadDriver函数的实现代码如下:

#001  static INIT_FUNCTION NTSTATUS

#002  IopLoadDriver(PSERVICE Service)

#003  {

#004       NTSTATUS Status = STATUS_UNSUCCESSFUL;

#005 

 

把正在加载的驱动程序名称显示到屏幕上。

#006       IopDisplayLoadingMessage(Service->ServiceName.Buffer, TRUE);

 

下面调用函数ZwLoadDriver来加载这个驱动程序。这里要指出的一点,就是ZwLoadDriver函数是一个对外面名称的API函数,其实它就是函数NtLoadDriver

#007       Status = ZwLoadDriver(&Service->RegistryPath);

 

在引导的LOG文件里写上是否加载成功的消息。

#008       IopBootLog(&Service->ImagePath, NT_SUCCESS(Status) ? TRUE : FALSE);

#009       if (!NT_SUCCESS(Status))

#010       {

#011              DPRINT("IopLoadDriver() failed (Status %lx)/n", Status);

#012  #if 0

#013              if (Service->ErrorControl == 1)

#014              {

#015                     /* Log error */

#016              }

#017              else if (Service->ErrorControl == 2)

#018              {

#019                     if (IsLastKnownGood == FALSE)

#020                     {

#021                            /* Boot last known good configuration */

#022                     }

#023              }

#024              else if (Service->ErrorControl == 3)

#025              {

#026                     if (IsLastKnownGood == FALSE)

#027                     {

#028                            /* Boot last known good configuration */

#029                     }

#030                     else

#031                     {

#032                            /* BSOD! */

#033                     }

#034              }

#035  #endif

#036       }

#037       return Status;

#038  }

 

从上面的函数可以知道,需要进一步去分析函数NtLoadDriver的代码,才可以继续地深入地了解加载过程,它的代码如下:

#001  NTSTATUS NTAPI

#002  NtLoadDriver(IN PUNICODE_STRING DriverServiceName)

#003  {

#004      UNICODE_STRING CapturedDriverServiceName = { 0, 0, NULL };

#005      KPROCESSOR_MODE PreviousMode;

#006      LOAD_UNLOAD_PARAMS LoadParams;

#007      NTSTATUS Status;

#008 

 

检查是否使用分页特权级。

#009      PAGED_CODE();

#010 

 

获取当前系统的运行模式。

#011      PreviousMode = KeGetPreviousMode();

#012 

 

检查特权级,是否允许加载驱动程序。

#013      /*

#014      * Check security privileges

#015      */

#016 

#017      /* FIXME: Uncomment when privileges will be correctly implemented. */

#018  #if 0

#019      if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, PreviousMode))

#020      {

#021          DPRINT("Privilege not held/n");

#022          return STATUS_PRIVILEGE_NOT_HELD;

#023      }

#024  #endif

#025 

 

获取驱动程序的名称。

#026      Status = ProbeAndCaptureUnicodeString(&CapturedDriverServiceName,

#027                                            PreviousMode,

#028                                            DriverServiceName);

#029      if (!NT_SUCCESS(Status))

#030      {

#031          return Status;

#032      }

#033 

#034      DPRINT("2009 NtLoadDriver('%wZ')/n", &CapturedDriverServiceName);

#035 

#036      LoadParams.ServiceName = &CapturedDriverServiceName;

#037      LoadParams.DriverObject = NULL;

 

初始化加载驱动程序的事件。

#038      KeInitializeEvent(&LoadParams.Event, NotificationEvent, FALSE);

#039 

 

根据当前进程是否为系统初始化进程来决定调用的方式。

#040      /* Call the load/unload routine, depending on current process */

#041      if (PsGetCurrentProcess() == PsInitialSystemProcess)

#042      {

 

这里是系统进程调用,直接调用就可以。

#043          /* Just call right away */

#044              DPRINT("NtLoadDriver(  IopLoadUnloadDriver )/n");

#045 

#046          IopLoadUnloadDriver(&LoadParams);

#047      }

#048      else

#049      {

 

这是用户模式的进程调用,采用工作消息的方式通知系统进程调用。

#050          /* Load/Unload must be called from system process */

#051          ExInitializeWorkItem(&LoadParams.WorkItem,

#052                               (PWORKER_THREAD_ROUTINE)IopLoadUnloadDriver,

#053                               (PVOID)&LoadParams);

#054 

#055          /* Queue it */

#056          ExQueueWorkItem(&LoadParams.WorkItem, DelayedWorkQueue);

#057 

#058          /* And wait when it completes */

#059          KeWaitForSingleObject(&LoadParams.Event, UserRequest, KernelMode,

#060              FALSE, NULL);

#061      }

#062 

#063      ReleaseCapturedUnicodeString(&CapturedDriverServiceName,

#064                                   PreviousMode);

#065 

#066      return LoadParams.Status;

#067  }

#068 

 

接着下来分析函数IopLoadUnloadDriver的代码,如下:

#001  VOID NTAPI

#002  IopLoadUnloadDriver(PLOAD_UNLOAD_PARAMS LoadParams)

#003  {

#004     RTL_QUERY_REGISTRY_TABLE QueryTable[3];

#005     UNICODE_STRING ImagePath;

#006     UNICODE_STRING ServiceName;

#007     NTSTATUS Status;

#008     ULONG Type;

#009     PDEVICE_NODE DeviceNode;

#010     PDRIVER_OBJECT DriverObject;

#011     PLDR_DATA_TABLE_ENTRY ModuleObject;

#012     PVOID BaseAddress;

#013     WCHAR *cur;

#014 

 

检查是否卸载驱动程序。

#015     /* Check if it's an unload request */

#016     if (LoadParams->DriverObject)

#017     {

 

这里是卸载驱动程序。

#018         (*LoadParams->DriverObject->DriverUnload)(LoadParams->DriverObject);

#019 

#020         /* Return success and signal the event */

#021         LoadParams->Status = STATUS_SUCCESS;

#022        (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);

#023         return;

#024     }

#025 

 

把驱动程序的路径名称转换为UNICODE字符串。

#026     RtlInitUnicodeString(&ImagePath, NULL);

#027 

 

从注册表的键值里分解出来路径名称。

#028     /*

#029      * Get the service name from the registry key name.

#030      */

#031     ASSERT(LoadParams->ServiceName->Length >= sizeof(WCHAR));

#032 

#033     ServiceName = *LoadParams->ServiceName;

#034     cur = LoadParams->ServiceName->Buffer +

#035         (LoadParams->ServiceName->Length / sizeof(WCHAR)) - 1;

#036     while (LoadParams->ServiceName->Buffer != cur)

#037     {

#038        if(*cur == L'//')

#039        {

#040           ServiceName.Buffer = cur + 1;

#041           ServiceName.Length = LoadParams->ServiceName->Length -

#042                                (USHORT)((ULONG_PTR)ServiceName.Buffer -

#043                                         (ULONG_PTR)LoadParams->ServiceName->Buffer);

#044           break;

#045        }

#046        cur--;

#047     }

#048 

 

获取驱动程序的类型。

#049     /*

#050      * Get service type.

#051      */

#052 

#053     RtlZeroMemory(&QueryTable, sizeof(QueryTable));

#054 

#055     RtlInitUnicodeString(&ImagePath, NULL);

#056 

#057     QueryTable[0].Name = L"Type";

#058     QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;

#059     QueryTable[0].EntryContext = &Type;

#060 

#061     QueryTable[1].Name = L"ImagePath";

#062     QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;

#063     QueryTable[1].EntryContext = &ImagePath;

#064 

#065     Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,

#066        LoadParams->ServiceName->Buffer, QueryTable, NULL, NULL);

#067 

#068     if (!NT_SUCCESS(Status))

#069     {

#070        DPRINT("RtlQueryRegistryValues() failed (Status %lx)/n", Status);

#071        ExFreePool(ImagePath.Buffer);

#072        LoadParams->Status = Status;

#073        (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);

#074        return;

#075     }

#076 

 

把驱动程序路径名称进行规格化。

#077     /*

#078      * Normalize the image path for all later processing.

#079      */

#080 

#081     Status = IopNormalizeImagePath(&ImagePath, &ServiceName);

#082 

#083     if (!NT_SUCCESS(Status))

#084     {

#085        DPRINT("IopNormalizeImagePath() failed (Status %x)/n", Status);

#086        LoadParams->Status = Status;

#087        (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);

#088        return;

#089     }

#090 

#091     DPRINT("FullImagePath: '%wZ'/n", &ImagePath);

#092     DPRINT("Type: %lx/n", Type);

#093 

 

创建设备节点。

#094     /*

#095      * Create device node

#096      */

#097 

 

把驱动程序创建的节点保存到IopRootDeviceNode根节点里。

#098     /* Use IopRootDeviceNode for now */

#099     Status = IopCreateDeviceNode(IopRootDeviceNode, NULL, &ServiceName, &DeviceNode);

#100 

#101     if (!NT_SUCCESS(Status))

#102     {

#103        DPRINT("IopCreateDeviceNode() failed (Status %lx)/n", Status);

#104        LoadParams->Status = Status;

#105        (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);

#106        return;

#107     }

#108 

 

检查这个驱动程序是否已经加载和初始化。

#109     /* Get existing DriverObject pointer (in case the driver has

#110        already been loaded and initialized) */

#111     Status = IopGetDriverObject(

#112         &DriverObject,

#113         &ServiceName,

#114         (Type == 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||

#115          Type == 8 /* SERVICE_RECOGNIZER_DRIVER */));

#116 

#117     if (!NT_SUCCESS(Status))

#118     {

 

下面调用函数MmLoadSystemImage来加载驱动程序到内存里。

#119         /*

#120          * Load the driver module

#121          */

#122 

#123         Status = MmLoadSystemImage(&ImagePath, NULL, NULL, 0, (PVOID)&ModuleObject, &BaseAddress);

#124         if (!NT_SUCCESS(Status) && Status != STATUS_IMAGE_ALREADY_LOADED)

#125         {

#126             DPRINT("MmLoadSystemImage() failed (Status %lx)/n", Status);

#127             IopFreeDeviceNode(DeviceNode);

#128             LoadParams->Status = Status;

#129             (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);

#130             return;

#131         }

#132 

 

加载驱动程序文件成功,就可以给驱动程序节点分配服务的名称。

#133         /*

#134          * Set a service name for the device node

#135          */

#136 

#137         RtlCreateUnicodeString(&DeviceNode->ServiceName, ServiceName.Buffer);

#138 

#139         /*

#140          * Initialize the driver module if it's loaded for the first time

#141          */

#142         if (Status != STATUS_IMAGE_ALREADY_LOADED)

#143         {

 

加载驱动程序后,首先要对它初始化,这是通过函数IopInitializeDriverModule来实现。

#144             Status = IopInitializeDriverModule(

#145                 DeviceNode,

#146                 ModuleObject,

#147                 &DeviceNode->ServiceName,

#148                 (Type == 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||

#149                 Type == 8 /* SERVICE_RECOGNIZER_DRIVER */),

#150                 &DriverObject);

#151 

#152             if (!NT_SUCCESS(Status))

#153             {

#154                 DPRINT("IopInitializeDriver() failed (Status %lx)/n", Status);

#155                 MmUnloadSystemImage(ModuleObject);

#156                 IopFreeDeviceNode(DeviceNode);

#157                 LoadParams->Status = Status;

#158                 (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);

#159                 return;

#160             }

#161         }

#162 

 

保存驱动程序模块对象,以便卸载时使用。

#163         /* Store its DriverSection, so that it could be unloaded */

#164         DriverObject->DriverSection = ModuleObject;

#165     }

#166 

 

初始化驱动程序。

#167     IopInitializeDevice(DeviceNode, DriverObject);

 

启用驱动程序。

#168     LoadParams->Status = IopStartDevice(DeviceNode);

#169     (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);

#170  }

 

上面可以看到先要调用函数MmLoadSystemImage把驱动程序文件加载到内存,然后调用函数IopInitializeDriverModule来初始化。驱动程序和一般的应用程序是不一样的,它没有作为入口的WinMain函数。与DLL相类似,它向操作系统提供了一个入口函数,叫做DriverEntry的函数,在启动驱动程序的时候,操作系统就调用这个入口。那么ReactOS是怎么样调用这个入口函数的呢?在那里调用的呢?要解开这个谜底,就需要分析函数IopInitializeDriverModule的代码实现了,如下:

#001  NTSTATUS FASTCALL

#002  IopInitializeDriverModule(

#003     IN PDEVICE_NODE DeviceNode,

#004     IN PLDR_DATA_TABLE_ENTRY ModuleObject,

#005     IN PUNICODE_STRING ServiceName,

#006     IN BOOLEAN FileSystemDriver,

#007     OUT PDRIVER_OBJECT *DriverObject)

#008  {

 

设置服务的键名称。

#009     const WCHAR ServicesKeyName[] = L"//Registry//Machine//System//CurrentControlSet//Services//";

#010     WCHAR NameBuffer[MAX_PATH];

#011     UNICODE_STRING DriverName;

#012     UNICODE_STRING RegistryKey;

#013     PDRIVER_INITIALIZE DriverEntry;

#014     PDRIVER_OBJECT Driver;

#015     PDEVICE_OBJECT DeviceObject;

#016     NTSTATUS Status;

#017 

 

获取驱动程序入口。

#018     DriverEntry = ModuleObject->EntryPoint;

#019 

 

把驱动程序服务名称写到注册表里。

#020     if (ServiceName != NULL && ServiceName->Length != 0)

#021     {

#022        RegistryKey.Length = 0;

#023        RegistryKey.MaximumLength = sizeof(ServicesKeyName) + ServiceName->Length;

#024        RegistryKey.Buffer = ExAllocatePool(PagedPool, RegistryKey.MaximumLength);

#025        if (RegistryKey.Buffer == NULL)

#026        {

#027           return STATUS_INSUFFICIENT_RESOURCES;

#028        }

#029        RtlAppendUnicodeToString(&RegistryKey, ServicesKeyName);

#030        RtlAppendUnicodeStringToString(&RegistryKey, ServiceName);

#031     }

#032     else

#033     {

#034        RtlInitUnicodeString(&RegistryKey, NULL);

#035     }

#036 

 

创建驱动程序的名称字符串。

#037     /* Create ModuleName string */

#038     if (ServiceName && ServiceName->Length > 0)

#039     {

#040        if (FileSystemDriver == TRUE)

#041           wcscpy(NameBuffer, FILESYSTEM_ROOT_NAME);

#042        else

#043           wcscpy(NameBuffer, DRIVER_ROOT_NAME);

#044 

#045        RtlInitUnicodeString(&DriverName, NameBuffer);

#046        DriverName.MaximumLength = sizeof(NameBuffer);

#047 

#048        RtlAppendUnicodeStringToString(&DriverName, ServiceName);

#049 

#050        DPRINT("Driver name: '%wZ'/n", &DriverName);

#051     }

#052     else

#053        DriverName.Length = 0;

#054 

 

调用函数IopCreateDriver来创建驱动程序对象。

#055     Status = IopCreateDriver(

#056         DriverName.Length > 0 ? &DriverName : NULL,

#057         DriverEntry,

#058         &RegistryKey,

#059         ModuleObject->DllBase,

#060         ModuleObject->SizeOfImage,

#061         &Driver);

#062     RtlFreeUnicodeString(&RegistryKey);

#063 

 

保存返回的驱动程序对象。

#064     *DriverObject = Driver;

#065     if (!NT_SUCCESS(Status))

#066     {

#067        DPRINT("IopCreateDriver() failed (Status 0x%08lx)/n", Status);

#068        return Status;

#069     }

#070 

 

设置这个驱动程序初始化完成。

#071     /* Set the driver as initialized */

#072     Driver->Flags |= DRVO_INITIALIZED;

#073     DeviceObject = Driver->DeviceObject;

#074     while (DeviceObject)

#075     {

#076         /* Set every device as initialized too */

#077         DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;

#078         DeviceObject = DeviceObject->NextDevice;

#079     }

#080 

重新刷新要初始化的驱动程序。

#081     IopReinitializeDrivers();

#082 

#083     return STATUS_SUCCESS;

#084  }

 

接着来分析函数IopCreateDriver,它是怎么样创建驱动程序对象的,如下:

#001  NTSTATUS

#002  NTAPI

#003  IopCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL,

#004                  IN PDRIVER_INITIALIZE InitializationFunction,

#005                  IN PUNICODE_STRING RegistryPath,

#006                  IN PVOID DllBase,

#007                  IN ULONG SizeOfImage,

#008                  OUT PDRIVER_OBJECT *pDriverObject)

#009  {

#010      WCHAR NameBuffer[100];

#011      USHORT NameLength;

#012      UNICODE_STRING LocalDriverName;

#013      NTSTATUS Status;

#014      OBJECT_ATTRIBUTES ObjectAttributes;

#015      ULONG ObjectSize;

#016      PDRIVER_OBJECT DriverObject;

#017      UNICODE_STRING ServiceKeyName;

#018      HANDLE hDriver;

#019      ULONG i, RetryCount = 0;

#020 

#021  try_again:

 

如果驱动程序没有名称,就需要使用随机时间创建一个名称。

#022      /* First, create a unique name for the driver if we don't have one */

#023      if (!DriverName)

#024      {

#025          /* Create a random name and set up the string*/

#026          NameLength = (USHORT)swprintf(NameBuffer,

#027                                        L"//Driver//%08u",

#028                                        KeTickCount);

#029          LocalDriverName.Length = NameLength * sizeof(WCHAR);

#030          LocalDriverName.MaximumLength = LocalDriverName.Length + sizeof(UNICODE_NULL);

#031          LocalDriverName.Buffer = NameBuffer;

#032      }

#033      else

#034      {

#035          /* So we can avoid another code path, use a local var */

#036          LocalDriverName = *DriverName;

#037      }

#038 

 

初始化驱动程序对象的属性。

#039      /* Initialize the Attributes */

#040      ObjectSize = sizeof(DRIVER_OBJECT) + sizeof(EXTENDED_DRIVER_EXTENSION);

#041      InitializeObjectAttributes(&ObjectAttributes,

#042                                 &LocalDriverName,

#043                                 OBJ_PERMANENT | OBJ_CASE_INSENSITIVE,

#044                                 NULL,

#045                                 NULL);

#046 

 

创建驱动程序对象。

#047      /* Create the Object */

#048      Status = ObCreateObject(KernelMode,

#049                              IoDriverObjectType,

#050                              &ObjectAttributes,

#051                              KernelMode,

#052                              NULL,

#053                              ObjectSize,

#054                              0,

#055                              0,

#056                              (PVOID*)&DriverObject);

#057      if (!NT_SUCCESS(Status)) return Status;

#058 

#059      DPRINT("IopCreateDriver(): created DO %p/n", DriverObject);

#060 

 

设置驱动程序对象。

#061      /* Set up the Object */

#062      RtlZeroMemory(DriverObject, ObjectSize);

#063      DriverObject->Type = IO_TYPE_DRIVER;

#064      DriverObject->Size = sizeof(DRIVER_OBJECT);

#065      DriverObject->Flags = DRVO_BUILTIN_DRIVER;

#066      DriverObject->DriverExtension = (PDRIVER_EXTENSION)(DriverObject + 1);

#067      DriverObject->DriverExtension->DriverObject = DriverObject;

 

这里设置驱动程序入口函数DriverEntry

#068      DriverObject->DriverInit = InitializationFunction;

#069 

 

初始化所有主要调用函数为非法调用的回调函数。

#070      /* Loop all Major Functions */

#071      for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)

#072      {

#073          /* Invalidate each function */

#074          DriverObject->MajorFunction[i] = IopInvalidDeviceRequest;

#075      }

#076 

#077      /* Set up the service key name buffer */

#078      ServiceKeyName.Buffer = ExAllocatePoolWithTag(PagedPool,

#079                                                    LocalDriverName.Length +

#080                                                    sizeof(WCHAR),

#081                                                    TAG_IO);

#082      if (!ServiceKeyName.Buffer)

#083      {

#084          /* Fail */

#085          ObMakeTemporaryObject(DriverObject);

#086          ObDereferenceObject(DriverObject);

#087          return STATUS_INSUFFICIENT_RESOURCES;

#088      }

#089 

#090      /* Fill out the key data and copy the buffer */

#091      ServiceKeyName.Length = LocalDriverName.Length;

#092      ServiceKeyName.MaximumLength = LocalDriverName.MaximumLength;

#093      RtlCopyMemory(ServiceKeyName.Buffer,

#094                    LocalDriverName.Buffer,

#095                    LocalDriverName.Length);

#096 

#097      /* Null-terminate it and set it */

#098      ServiceKeyName.Buffer[ServiceKeyName.Length / sizeof(WCHAR)] = UNICODE_NULL;

#099      DriverObject->DriverExtension->ServiceKeyName = ServiceKeyName;

#100 

#101      /* Also store it in the Driver Object. This is a bit of a hack. */

#102      RtlCopyMemory(&DriverObject->DriverName,

#103                    &ServiceKeyName,

#104                    sizeof(UNICODE_STRING));

#105 

 

添加对象到驱动程序管理器。

#106      /* Add the Object and get its handle */

#107      Status = ObInsertObject(DriverObject,

#108                              NULL,

#109                              FILE_READ_DATA,

#110                              0,

#111                              NULL,

#112                              &hDriver);

#113 

 

如果第一次初始化不成功,就再次尝试初始化。

#114      /* Eliminate small possibility when this function is called more than

#115         once in a row, and KeTickCount doesn't get enough time to change */

#116      if (!DriverName && (Status == STATUS_OBJECT_NAME_COLLISION) && (RetryCount < 100))

#117      {

#118          RetryCount++;

#119          goto try_again;

#120      }

#121 

#122      if (!NT_SUCCESS(Status)) return Status;

#123 

#124      /* Now reference it */

#125      Status = ObReferenceObjectByHandle(hDriver,

#126                                         0,

#127                                         IoDriverObjectType,

#128                                         KernelMode,

#129                                         (PVOID*)&DriverObject,

#130                                         NULL);

#131      if (!NT_SUCCESS(Status))

#132      {

#133          /* Fail */

#134          ObMakeTemporaryObject(DriverObject);

#135          ObDereferenceObject(DriverObject);

#136          return Status;

#137      }

#138 

#139      /* Close the extra handle */

#140      ZwClose(hDriver);

#141 

 

设置驱动程序硬件信息和驱动程序的文件信息。

#142      DriverObject->HardwareDatabase = &IopHardwareDatabaseKey;

#143      DriverObject->DriverStart = DllBase;

#144      DriverObject->DriverSize = SizeOfImage;

#145 

 

在这里就会调用驱动程序的入口点函数DriverEntry来运行,也就是设置了驱动程序对象里所写的回调函数,达到调用用户编写的程序的目标。

#146      /* Finally, call its init function */

#147      DPRINT("RegistryKey: %wZ/n", RegistryPath);

#148      DPRINT("Calling driver entrypoint at %p/n", InitializationFunction);

#149      Status = (*InitializationFunction)(DriverObject, RegistryPath);

#150      if (!NT_SUCCESS(Status))

#151      {

#152          /* If it didn't work, then kill the object */

#153          DPRINT1("'%wZ' initialization failed, status (0x%08lx)/n", DriverName, Status);

#154          ObMakeTemporaryObject(DriverObject);

#155          ObDereferenceObject(DriverObject);

#156      }

#157      else

#158      {

#159          /* Returns to caller the object */

#160          *pDriverObject = DriverObject;

#161      }

#162 

#163      /* Return the Status */

#164      return Status;

#165  }

 

通过上面的分析,就已经了解驱动程序在那里调用入口函数了。接着下来,驱动程序就需要进一步初始化是否有即插即用的设备,最后开始启动整个设备开始工作了。主要通过函数IopInitializeDevice和函数IopStartDevice来实现的。具体代码如下:

#001  NTSTATUS

#002  FASTCALL

#003  IopInitializeDevice(PDEVICE_NODE DeviceNode,

#004                      PDRIVER_OBJECT DriverObject)

#005  {

#006     PDEVICE_OBJECT Fdo;

#007     NTSTATUS Status;

#008 

 

如果没有添加设备功能,就退出。

#009     if (!DriverObject->DriverExtension->AddDevice)

#010        return STATUS_SUCCESS;

#011 

 

这是一个即插即用的驱动程序初始化。

#012     /* This is a Plug and Play driver */

#013     DPRINT("Plug and Play driver found/n");

#014     ASSERT(DeviceNode->PhysicalDeviceObject);

#015 

 

检查这个驱动程序是否以前旧式驱动程序。

#016     /* Check if this plug-and-play driver is used as a legacy one for this device node */

#017     if (IopDeviceNodeHasFlag(DeviceNode, DNF_LEGACY_DRIVER))

#018     {

#019        IopDeviceNodeSetFlag(DeviceNode, DNF_ADDED);

#020        return STATUS_SUCCESS;

#021     }

#022 

 

下面开始调用即插即用的函数AddDevice来添加设备。

#023     DPRINT("Calling %wZ->AddDevice(%wZ)/n",

#024        &DriverObject->DriverName,

#025        &DeviceNode->InstancePath);

#026     Status = DriverObject->DriverExtension->AddDevice(

#027        DriverObject, DeviceNode->PhysicalDeviceObject);

#028     if (!NT_SUCCESS(Status))

#029     {

#030        IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);

#031        return Status;

#032     }

#033 

 

检查驱动程序的PDO上面是否有FDO的功能。

#034     /* Check if driver added a FDO above the PDO */

#035     Fdo = IoGetAttachedDeviceReference(DeviceNode->PhysicalDeviceObject);

#036     if (Fdo == DeviceNode->PhysicalDeviceObject)

#037     {

#038        /* FIXME: What do we do? Unload the driver or just disable the device? */

#039        DPRINT1("An FDO was not attached/n");

#040        ObDereferenceObject(Fdo);

#041        IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);

#042        return STATUS_UNSUCCESSFUL;

#043     }

#044 

 

检查设备是否有高级电源管理功能ACPI

#045     /* Check if we have a ACPI device (needed for power management) */

#046     if (Fdo->DeviceType == FILE_DEVICE_ACPI)

#047     {

#048        static BOOLEAN SystemPowerDeviceNodeCreated = FALSE;

#049 

 

系统电源管理设备创建。

#050        /* There can be only one system power device */

#051        if (!SystemPowerDeviceNodeCreated)

#052        {

#053           PopSystemPowerDeviceNode = DeviceNode;

#054           ObReferenceObject(PopSystemPowerDeviceNode);

#055           SystemPowerDeviceNodeCreated = TRUE;

#056        }

#057     }

#058 

 

添加引用对象。

#059     ObDereferenceObject(Fdo);

#060 

#061     IopDeviceNodeSetFlag(DeviceNode, DNF_ADDED);

#062     IopDeviceNodeSetFlag(DeviceNode, DNF_NEED_ENUMERATION_ONLY);

#063 

#064     return STATUS_SUCCESS;

#065  }

 

 

下面来分析启动设备函数IopStartDevice,实现代码如下:

#001  NTSTATUS

#002  IopStartDevice(

#003     PDEVICE_NODE DeviceNode)

#004  {

#005     IO_STATUS_BLOCK IoStatusBlock;

#006     IO_STACK_LOCATION Stack;

#007     ULONG RequiredLength;

#008     NTSTATUS Status;

#009 

 

设置设备节点已经分配资源。

#010     IopDeviceNodeSetFlag(DeviceNode, DNF_ASSIGNING_RESOURCES);

#011     DPRINT("Sending IRP_MN_FILTER_RESOURCE_REQUIREMENTS to device stack/n");

#012     Stack.Parameters.FilterResourceRequirements.IoResourceRequirementList = DeviceNode->ResourceRequirements;

 

发送一个IRP包,需要请求分配资源。

#013     Status = IopInitiatePnpIrp(

#014        DeviceNode->PhysicalDeviceObject,

#015        &IoStatusBlock,

#016        IRP_MN_FILTER_RESOURCE_REQUIREMENTS,

#017        &Stack);

#018     if (!NT_SUCCESS(Status) && Status != STATUS_NOT_SUPPORTED)

#019     {

#020        DPRINT("IopInitiatePnpIrp(IRP_MN_FILTER_RESOURCE_REQUIREMENTS) failed/n");

#021        return Status;

#022     }

#023     DeviceNode->ResourceRequirements = Stack.Parameters.FilterResourceRequirements.IoResourceRequirementList;

#024 

 

分配资源。

#025     Status = IopAssignDeviceResources(DeviceNode, &RequiredLength);

#026     if (NT_SUCCESS(Status))

#027     {

#028        Status = IopTranslateDeviceResources(DeviceNode, RequiredLength);

#029        if (NT_SUCCESS(Status))

#030        {

#031           IopDeviceNodeSetFlag(DeviceNode, DNF_RESOURCE_ASSIGNED);

#032        }

#033        else

#034        {

#035           DPRINT("IopTranslateDeviceResources() failed (Status 0x%08lx)/n", Status);

#036        }

#037     }

#038     else

#039     {

#040        DPRINT("IopAssignDeviceResources() failed (Status 0x%08lx)/n", Status);

#041     }

#042     IopDeviceNodeClearFlag(DeviceNode, DNF_ASSIGNING_RESOURCES);

#043 

#044     DPRINT("Sending IRP_MN_START_DEVICE to driver/n");

#045     Stack.Parameters.StartDevice.AllocatedResources = DeviceNode->ResourceList;

#046     Stack.Parameters.StartDevice.AllocatedResourcesTranslated = DeviceNode->ResourceListTranslated;

#047 

 

发送启动设备的IRP消息。

#048     /*

#049      * Windows NT Drivers receive IRP_MN_START_DEVICE in a critical region and

#050      * actually _depend_ on this!. This is because NT will lock the Device Node

#051      * with an ERESOURCE, which of course requires APCs to be disabled.

#052      */

#053     KeEnterCriticalRegion();

#054 

#055     //

#056     DPRINT("IopInitiatePnpIrp to driver/n");

#057 

#058     Status = IopInitiatePnpIrp(

#059        DeviceNode->PhysicalDeviceObject,

#060        &IoStatusBlock,

#061        IRP_MN_START_DEVICE,

#062        &Stack);

#063 

#064     KeLeaveCriticalRegion();

#065 

#066     //

#067     DPRINT("IopInitiatePnpIrp to driver  NT_SUCCESS/n");

#068 

#069 

#070     if (!NT_SUCCESS(Status))

#071     {

#072        DPRINT("IopInitiatePnpIrp() failed/n");

#073     }

#074     else

#075     {

#076        if (IopDeviceNodeHasFlag(DeviceNode, DNF_NEED_ENUMERATION_ONLY))

#077        {

#078           DPRINT("Device needs enumeration, invalidating bus relations/n");

#079           /* Invalidate device relations synchronously

#080              (otherwise there will be dirty read of DeviceNode) */

#081           IopEnumerateDevice(DeviceNode->PhysicalDeviceObject);

#082           IopDeviceNodeClearFlag(DeviceNode, DNF_NEED_ENUMERATION_ONLY);

#083        }

#084     }

#085 

#086     if (NT_SUCCESS(Status))

#087         IopDeviceNodeSetFlag(DeviceNode, DNF_STARTED);

#088 

#089     //

#090     DPRINT("IopInitiatePnpIrp to driver  Finish/n");

#091 

#092     return Status;

#093  }

#094 

IRP的全名是I/O Request Package,即输入输出请求包,它是ReactOS内核中的一种非常重要的数据结构。上层应用程序与底层驱动程序通信时,应用程序会发出I/O请求,操作系统将相应的I/O请求转换成相应的IRP,不同的IRP会根据类型被分派到不同的派遣例程中进行处理。

      IRP有两个基本的属性,即MajorFunctionMinorFunction,分别记录IRP的主类型和子类型。操作系统根据MajorFunction决定将IRP分发到哪个派遣例程,然后派遣例程根据MinorFunction进行细分处理。

      IRP的概念类似于ReactOS应用程序中“消息”的概念。在ReactOS编程中,程序由“消息”驱动,不同的消息被分发到不同的处理函数中,否则由系统默认处理。

      文件I/O的相关函数例如CreateFileReadFileWriteFileCloseHandle等分别会引发操作系统产生IRP_MJ_CREATEIRP_MJ_READIRP_MJ_WRITEIRP_MJ_CLOSE等不同的IRP,这些IRP会被传送到驱动程序的相应派遣例程中。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

caimouse

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值