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,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,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,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,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,&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,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,(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,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,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,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有两个基本的属性,即MajorFunction和MinorFunction,分别记录IRP的主类型和子类型。操作系统根据MajorFunction决定将IRP分发到哪个派遣例程,然后派遣例程根据MinorFunction进行细分处理。 IRP的概念类似于ReactOS应用程序中“消息”的概念。在ReactOS编程中,程序由“消息”驱动,不同的消息被分发到不同的处理函数中,否则由系统默认处理。 文件I/O的相关函数例如CreateFile、ReadFile、WriteFile、CloseHandle等分别会引发操作系统产生IRP_MJ_CREATE、IRP_MJ_READ、IRP_MJ_WRITE、IRP_MJ_CLOSE等不同的IRP,这些IRP会被传送到驱动程序的相应派遣例程中。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |