a1584f58109c47187c2f47f2c8c20757c59eb417
[reactos.git] / ntoskrnl / io / iomgr / driver.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/iomgr/driver.c
5 * PURPOSE: Driver Object Management
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Filip Navara (navaraf@reactos.org)
8 * Hervé Poussineau (hpoussin@reactos.org)
9 */
10
11 /* INCLUDES *******************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <debug.h>
16
17 /* GLOBALS ********************************************************************/
18
19 ERESOURCE IopDriverLoadResource;
20
21 LIST_ENTRY DriverReinitListHead;
22 KSPIN_LOCK DriverReinitListLock;
23 PLIST_ENTRY DriverReinitTailEntry;
24
25 PLIST_ENTRY DriverBootReinitTailEntry;
26 LIST_ENTRY DriverBootReinitListHead;
27 KSPIN_LOCK DriverBootReinitListLock;
28
29 UNICODE_STRING IopHardwareDatabaseKey =
30 RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\HARDWARE\\DESCRIPTION\\SYSTEM");
31
32 POBJECT_TYPE IoDriverObjectType = NULL;
33
34 #define TAG_RTLREGISTRY 'vrqR'
35
36 extern BOOLEAN ExpInTextModeSetup;
37 extern BOOLEAN PnpSystemInit;
38
39 USHORT IopGroupIndex;
40 PLIST_ENTRY IopGroupTable;
41
42 /* PRIVATE FUNCTIONS **********************************************************/
43
44 NTSTATUS
45 NTAPI
46 IopInvalidDeviceRequest(
47 PDEVICE_OBJECT DeviceObject,
48 PIRP Irp)
49 {
50 Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
51 Irp->IoStatus.Information = 0;
52 IoCompleteRequest(Irp, IO_NO_INCREMENT);
53 return STATUS_INVALID_DEVICE_REQUEST;
54 }
55
56 VOID
57 NTAPI
58 IopDeleteDriver(IN PVOID ObjectBody)
59 {
60 PDRIVER_OBJECT DriverObject = ObjectBody;
61 PIO_CLIENT_EXTENSION DriverExtension, NextDriverExtension;
62 PAGED_CODE();
63
64 DPRINT1("Deleting driver object '%wZ'\n", &DriverObject->DriverName);
65
66 /* There must be no device objects remaining at this point */
67 ASSERT(!DriverObject->DeviceObject);
68
69 /* Get the extension and loop them */
70 DriverExtension = IoGetDrvObjExtension(DriverObject)->ClientDriverExtension;
71 while (DriverExtension)
72 {
73 /* Get the next one */
74 NextDriverExtension = DriverExtension->NextExtension;
75 ExFreePoolWithTag(DriverExtension, TAG_DRIVER_EXTENSION);
76
77 /* Move on */
78 DriverExtension = NextDriverExtension;
79 }
80
81 /* Check if the driver image is still loaded */
82 if (DriverObject->DriverSection)
83 {
84 /* Unload it */
85 MmUnloadSystemImage(DriverObject->DriverSection);
86 }
87
88 /* Check if it has a name */
89 if (DriverObject->DriverName.Buffer)
90 {
91 /* Free it */
92 ExFreePool(DriverObject->DriverName.Buffer);
93 }
94
95 /* Check if it has a service key name */
96 if (DriverObject->DriverExtension->ServiceKeyName.Buffer)
97 {
98 /* Free it */
99 ExFreePool(DriverObject->DriverExtension->ServiceKeyName.Buffer);
100 }
101 }
102
103 NTSTATUS
104 FASTCALL
105 IopGetDriverObject(
106 PDRIVER_OBJECT *DriverObject,
107 PUNICODE_STRING ServiceName,
108 BOOLEAN FileSystem)
109 {
110 PDRIVER_OBJECT Object;
111 WCHAR NameBuffer[MAX_PATH];
112 UNICODE_STRING DriverName;
113 NTSTATUS Status;
114
115 DPRINT("IopGetDriverObject(%p '%wZ' %x)\n",
116 DriverObject, ServiceName, FileSystem);
117
118 ASSERT(ExIsResourceAcquiredExclusiveLite(&IopDriverLoadResource));
119 *DriverObject = NULL;
120
121 /* Create ModuleName string */
122 if (ServiceName == NULL || ServiceName->Buffer == NULL)
123 /* We don't know which DriverObject we have to open */
124 return STATUS_INVALID_PARAMETER_2;
125
126 DriverName.Buffer = NameBuffer;
127 DriverName.Length = 0;
128 DriverName.MaximumLength = sizeof(NameBuffer);
129
130 if (FileSystem != FALSE)
131 RtlAppendUnicodeToString(&DriverName, FILESYSTEM_ROOT_NAME);
132 else
133 RtlAppendUnicodeToString(&DriverName, DRIVER_ROOT_NAME);
134 RtlAppendUnicodeStringToString(&DriverName, ServiceName);
135
136 DPRINT("Driver name: '%wZ'\n", &DriverName);
137
138 /* Open driver object */
139 Status = ObReferenceObjectByName(&DriverName,
140 OBJ_OPENIF | OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, /* Attributes */
141 NULL, /* PassedAccessState */
142 0, /* DesiredAccess */
143 IoDriverObjectType,
144 KernelMode,
145 NULL, /* ParseContext */
146 (PVOID*)&Object);
147 if (!NT_SUCCESS(Status))
148 {
149 DPRINT("Failed to reference driver object, status=0x%08x\n", Status);
150 return Status;
151 }
152
153 *DriverObject = Object;
154
155 DPRINT("Driver Object: %p\n", Object);
156
157 return STATUS_SUCCESS;
158 }
159
160 /*
161 * RETURNS
162 * TRUE if String2 contains String1 as a suffix.
163 */
164 BOOLEAN
165 NTAPI
166 IopSuffixUnicodeString(
167 IN PCUNICODE_STRING String1,
168 IN PCUNICODE_STRING String2)
169 {
170 PWCHAR pc1;
171 PWCHAR pc2;
172 ULONG Length;
173
174 if (String2->Length < String1->Length)
175 return FALSE;
176
177 Length = String1->Length / 2;
178 pc1 = String1->Buffer;
179 pc2 = &String2->Buffer[String2->Length / sizeof(WCHAR) - Length];
180
181 if (pc1 && pc2)
182 {
183 while (Length--)
184 {
185 if( *pc1++ != *pc2++ )
186 return FALSE;
187 }
188 return TRUE;
189 }
190 return FALSE;
191 }
192
193 /*
194 * IopDisplayLoadingMessage
195 *
196 * Display 'Loading XXX...' message.
197 */
198 VOID
199 FASTCALL
200 IopDisplayLoadingMessage(PUNICODE_STRING ServiceName)
201 {
202 CHAR TextBuffer[256];
203 UNICODE_STRING DotSys = RTL_CONSTANT_STRING(L".SYS");
204
205 if (ExpInTextModeSetup) return;
206 if (!KeLoaderBlock) return;
207 RtlUpcaseUnicodeString(ServiceName, ServiceName, FALSE);
208 snprintf(TextBuffer, sizeof(TextBuffer),
209 "%s%sSystem32\\Drivers\\%wZ%s\r\n",
210 KeLoaderBlock->ArcBootDeviceName,
211 KeLoaderBlock->NtBootPathName,
212 ServiceName,
213 IopSuffixUnicodeString(&DotSys, ServiceName) ? "" : ".SYS");
214 HalDisplayString(TextBuffer);
215 }
216
217 /*
218 * IopNormalizeImagePath
219 *
220 * Normalize an image path to contain complete path.
221 *
222 * Parameters
223 * ImagePath
224 * The input path and on exit the result path. ImagePath.Buffer
225 * must be allocated by ExAllocatePool on input. Caller is responsible
226 * for freeing the buffer when it's no longer needed.
227 *
228 * ServiceName
229 * Name of the service that ImagePath belongs to.
230 *
231 * Return Value
232 * Status
233 *
234 * Remarks
235 * The input image path isn't freed on error.
236 */
237 NTSTATUS
238 FASTCALL
239 IopNormalizeImagePath(
240 _Inout_ _When_(return>=0, _At_(ImagePath->Buffer, _Post_notnull_ __drv_allocatesMem(Mem)))
241 PUNICODE_STRING ImagePath,
242 _In_ PUNICODE_STRING ServiceName)
243 {
244 UNICODE_STRING SystemRootString = RTL_CONSTANT_STRING(L"\\SystemRoot\\");
245 UNICODE_STRING DriversPathString = RTL_CONSTANT_STRING(L"\\SystemRoot\\System32\\drivers\\");
246 UNICODE_STRING DotSysString = RTL_CONSTANT_STRING(L".sys");
247 UNICODE_STRING InputImagePath;
248
249 DPRINT("Normalizing image path '%wZ' for service '%wZ'\n", ImagePath, ServiceName);
250
251 InputImagePath = *ImagePath;
252 if (InputImagePath.Length == 0)
253 {
254 ImagePath->Length = 0;
255 ImagePath->MaximumLength = DriversPathString.Length +
256 ServiceName->Length +
257 DotSysString.Length +
258 sizeof(UNICODE_NULL);
259 ImagePath->Buffer = ExAllocatePoolWithTag(NonPagedPool,
260 ImagePath->MaximumLength,
261 TAG_IO);
262 if (ImagePath->Buffer == NULL)
263 return STATUS_NO_MEMORY;
264
265 RtlCopyUnicodeString(ImagePath, &DriversPathString);
266 RtlAppendUnicodeStringToString(ImagePath, ServiceName);
267 RtlAppendUnicodeStringToString(ImagePath, &DotSysString);
268 }
269 else if (InputImagePath.Buffer[0] != L'\\')
270 {
271 ImagePath->Length = 0;
272 ImagePath->MaximumLength = SystemRootString.Length +
273 InputImagePath.Length +
274 sizeof(UNICODE_NULL);
275 ImagePath->Buffer = ExAllocatePoolWithTag(NonPagedPool,
276 ImagePath->MaximumLength,
277 TAG_IO);
278 if (ImagePath->Buffer == NULL)
279 return STATUS_NO_MEMORY;
280
281 RtlCopyUnicodeString(ImagePath, &SystemRootString);
282 RtlAppendUnicodeStringToString(ImagePath, &InputImagePath);
283
284 /* Free caller's string */
285 ExFreePoolWithTag(InputImagePath.Buffer, TAG_RTLREGISTRY);
286 }
287
288 DPRINT("Normalized image path is '%wZ' for service '%wZ'\n", ImagePath, ServiceName);
289
290 return STATUS_SUCCESS;
291 }
292
293 /*
294 * IopLoadServiceModule
295 *
296 * Load a module specified by registry settings for service.
297 *
298 * Parameters
299 * ServiceName
300 * Name of the service to load.
301 *
302 * Return Value
303 * Status
304 */
305 NTSTATUS
306 FASTCALL
307 IopLoadServiceModule(
308 IN PUNICODE_STRING ServiceName,
309 OUT PLDR_DATA_TABLE_ENTRY *ModuleObject)
310 {
311 RTL_QUERY_REGISTRY_TABLE QueryTable[3];
312 ULONG ServiceStart;
313 UNICODE_STRING ServiceImagePath, CCSName;
314 NTSTATUS Status;
315 HANDLE CCSKey, ServiceKey;
316 PVOID BaseAddress;
317
318 ASSERT(ExIsResourceAcquiredExclusiveLite(&IopDriverLoadResource));
319 ASSERT(ServiceName->Length);
320 DPRINT("IopLoadServiceModule(%wZ, 0x%p)\n", ServiceName, ModuleObject);
321
322 if (ExpInTextModeSetup)
323 {
324 /* We have no registry, but luckily we know where all the drivers are */
325 DPRINT1("IopLoadServiceModule(%wZ, 0x%p) called in ExpInTextModeSetup mode...\n", ServiceName, ModuleObject);
326
327 /* ServiceStart < 4 is all that matters */
328 ServiceStart = 0;
329
330 /* IopNormalizeImagePath will do all of the work for us if we give it an empty string */
331 RtlInitEmptyUnicodeString(&ServiceImagePath, NULL, 0);
332 }
333 else
334 {
335 /* Open CurrentControlSet */
336 RtlInitUnicodeString(&CCSName,
337 L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services");
338 Status = IopOpenRegistryKeyEx(&CCSKey, NULL, &CCSName, KEY_READ);
339 if (!NT_SUCCESS(Status))
340 {
341 DPRINT1("IopOpenRegistryKeyEx() failed for '%wZ' with status 0x%lx\n",
342 &CCSName, Status);
343 return Status;
344 }
345
346 /* Open service key */
347 Status = IopOpenRegistryKeyEx(&ServiceKey, CCSKey, ServiceName, KEY_READ);
348 if (!NT_SUCCESS(Status))
349 {
350 DPRINT1("IopOpenRegistryKeyEx() failed for '%wZ' with status 0x%lx\n",
351 ServiceName, Status);
352 ZwClose(CCSKey);
353 return Status;
354 }
355
356 /*
357 * Get information about the service.
358 */
359 RtlZeroMemory(QueryTable, sizeof(QueryTable));
360
361 RtlInitUnicodeString(&ServiceImagePath, NULL);
362
363 QueryTable[0].Name = L"Start";
364 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
365 QueryTable[0].EntryContext = &ServiceStart;
366
367 QueryTable[1].Name = L"ImagePath";
368 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
369 QueryTable[1].EntryContext = &ServiceImagePath;
370
371 Status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
372 (PWSTR)ServiceKey,
373 QueryTable,
374 NULL,
375 NULL);
376
377 ZwClose(ServiceKey);
378 ZwClose(CCSKey);
379
380 if (!NT_SUCCESS(Status))
381 {
382 DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status);
383 return Status;
384 }
385 }
386
387 /*
388 * Normalize the image path for all later processing.
389 */
390 Status = IopNormalizeImagePath(&ServiceImagePath, ServiceName);
391
392 if (!NT_SUCCESS(Status))
393 {
394 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status);
395 return Status;
396 }
397
398 /*
399 * Case for disabled drivers
400 */
401 if (ServiceStart >= 4)
402 {
403 /* We can't load this */
404 Status = STATUS_DRIVER_UNABLE_TO_LOAD;
405 }
406 else
407 {
408 DPRINT("Loading module from %wZ\n", &ServiceImagePath);
409 Status = MmLoadSystemImage(&ServiceImagePath, NULL, NULL, 0, (PVOID)ModuleObject, &BaseAddress);
410 if (NT_SUCCESS(Status))
411 {
412 IopDisplayLoadingMessage(ServiceName);
413 }
414 }
415
416 ExFreePool(ServiceImagePath.Buffer);
417
418 /*
419 * Now check if the module was loaded successfully.
420 */
421 if (!NT_SUCCESS(Status))
422 {
423 DPRINT("Module loading failed (Status %x)\n", Status);
424 }
425
426 DPRINT("Module loading (Status %x)\n", Status);
427
428 return Status;
429 }
430
431 VOID
432 NTAPI
433 MmFreeDriverInitialization(IN PLDR_DATA_TABLE_ENTRY LdrEntry);
434
435 /*
436 * IopInitializeDriverModule
437 *
438 * Initialize a loaded driver.
439 *
440 * Parameters
441 * DeviceNode
442 * Pointer to device node.
443 *
444 * ModuleObject
445 * Module object representing the driver. It can be retrieve by
446 * IopLoadServiceModule.
447 *
448 * ServiceName
449 * Name of the service (as in registry).
450 *
451 * FileSystemDriver
452 * Set to TRUE for file system drivers.
453 *
454 * DriverObject
455 * On successful return this contains the driver object representing
456 * the loaded driver.
457 */
458 NTSTATUS
459 FASTCALL
460 IopInitializeDriverModule(
461 IN PDEVICE_NODE DeviceNode,
462 IN PLDR_DATA_TABLE_ENTRY ModuleObject,
463 IN PUNICODE_STRING ServiceName,
464 IN BOOLEAN FileSystemDriver,
465 OUT PDRIVER_OBJECT *DriverObject)
466 {
467 static const WCHAR ServicesKeyName[] = L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
468 UNICODE_STRING DriverName;
469 UNICODE_STRING RegistryKey;
470 PDRIVER_INITIALIZE DriverEntry;
471 PDRIVER_OBJECT Driver;
472 NTSTATUS Status;
473
474 DriverEntry = ModuleObject->EntryPoint;
475
476 if (ServiceName != NULL && ServiceName->Length != 0)
477 {
478 RegistryKey.Length = 0;
479 RegistryKey.MaximumLength = sizeof(ServicesKeyName) + ServiceName->Length;
480 RegistryKey.Buffer = ExAllocatePoolWithTag(PagedPool,
481 RegistryKey.MaximumLength,
482 TAG_IO);
483 if (RegistryKey.Buffer == NULL)
484 {
485 return STATUS_INSUFFICIENT_RESOURCES;
486 }
487 RtlAppendUnicodeToString(&RegistryKey, ServicesKeyName);
488 RtlAppendUnicodeStringToString(&RegistryKey, ServiceName);
489 }
490 else
491 {
492 RtlInitEmptyUnicodeString(&RegistryKey, NULL, 0);
493 }
494
495 /* Create ModuleName string */
496 if (ServiceName && ServiceName->Length > 0)
497 {
498 DriverName.Length = 0;
499 DriverName.MaximumLength = sizeof(FILESYSTEM_ROOT_NAME) + ServiceName->Length;
500 DriverName.Buffer = ExAllocatePoolWithTag(PagedPool,
501 DriverName.MaximumLength,
502 TAG_IO);
503 if (DriverName.Buffer == NULL)
504 {
505 RtlFreeUnicodeString(&RegistryKey);
506 return STATUS_INSUFFICIENT_RESOURCES;
507 }
508
509 if (FileSystemDriver != FALSE)
510 RtlAppendUnicodeToString(&DriverName, FILESYSTEM_ROOT_NAME);
511 else
512 RtlAppendUnicodeToString(&DriverName, DRIVER_ROOT_NAME);
513 RtlAppendUnicodeStringToString(&DriverName, ServiceName);
514
515 DPRINT("Driver name: '%wZ'\n", &DriverName);
516 }
517 else
518 {
519 RtlInitEmptyUnicodeString(&DriverName, NULL, 0);
520 }
521
522 Status = IopCreateDriver(DriverName.Length > 0 ? &DriverName : NULL,
523 DriverEntry,
524 &RegistryKey,
525 ServiceName,
526 ModuleObject,
527 &Driver);
528 RtlFreeUnicodeString(&RegistryKey);
529 RtlFreeUnicodeString(&DriverName);
530
531 if (!NT_SUCCESS(Status))
532 {
533 DPRINT("IopCreateDriver() failed (Status 0x%08lx)\n", Status);
534 return Status;
535 }
536
537 *DriverObject = Driver;
538
539 MmFreeDriverInitialization((PLDR_DATA_TABLE_ENTRY)Driver->DriverSection);
540
541 /* Set the driver as initialized */
542 IopReadyDeviceObjects(Driver);
543
544 if (PnpSystemInit) IopReinitializeDrivers();
545
546 return STATUS_SUCCESS;
547 }
548
549 /*
550 * IopAttachFilterDriversCallback
551 *
552 * Internal routine used by IopAttachFilterDrivers.
553 */
554 NTSTATUS
555 NTAPI
556 IopAttachFilterDriversCallback(
557 PWSTR ValueName,
558 ULONG ValueType,
559 PVOID ValueData,
560 ULONG ValueLength,
561 PVOID Context,
562 PVOID EntryContext)
563 {
564 PDEVICE_NODE DeviceNode = Context;
565 UNICODE_STRING ServiceName;
566 PWCHAR Filters;
567 PLDR_DATA_TABLE_ENTRY ModuleObject;
568 PDRIVER_OBJECT DriverObject;
569 NTSTATUS Status;
570
571 /* No filter value present */
572 if (ValueType == REG_NONE)
573 return STATUS_SUCCESS;
574
575 for (Filters = ValueData;
576 ((ULONG_PTR)Filters - (ULONG_PTR)ValueData) < ValueLength &&
577 *Filters != 0;
578 Filters += (ServiceName.Length / sizeof(WCHAR)) + 1)
579 {
580 DPRINT("Filter Driver: %S (%wZ)\n", Filters, &DeviceNode->InstancePath);
581
582 ServiceName.Buffer = Filters;
583 ServiceName.MaximumLength =
584 ServiceName.Length = (USHORT)wcslen(Filters) * sizeof(WCHAR);
585
586 KeEnterCriticalRegion();
587 ExAcquireResourceExclusiveLite(&IopDriverLoadResource, TRUE);
588 Status = IopGetDriverObject(&DriverObject,
589 &ServiceName,
590 FALSE);
591 if (!NT_SUCCESS(Status))
592 {
593 /* Load and initialize the filter driver */
594 Status = IopLoadServiceModule(&ServiceName, &ModuleObject);
595 if (!NT_SUCCESS(Status))
596 {
597 ExReleaseResourceLite(&IopDriverLoadResource);
598 KeLeaveCriticalRegion();
599 return Status;
600 }
601
602 Status = IopInitializeDriverModule(DeviceNode,
603 ModuleObject,
604 &ServiceName,
605 FALSE,
606 &DriverObject);
607 if (!NT_SUCCESS(Status))
608 {
609 ExReleaseResourceLite(&IopDriverLoadResource);
610 KeLeaveCriticalRegion();
611 return Status;
612 }
613 }
614
615 ExReleaseResourceLite(&IopDriverLoadResource);
616 KeLeaveCriticalRegion();
617
618 Status = IopInitializeDevice(DeviceNode, DriverObject);
619
620 /* Remove extra reference */
621 ObDereferenceObject(DriverObject);
622
623 if (!NT_SUCCESS(Status))
624 return Status;
625 }
626
627 return STATUS_SUCCESS;
628 }
629
630 /*
631 * IopAttachFilterDrivers
632 *
633 * Load filter drivers for specified device node.
634 *
635 * Parameters
636 * Lower
637 * Set to TRUE for loading lower level filters or FALSE for upper
638 * level filters.
639 */
640 NTSTATUS
641 FASTCALL
642 IopAttachFilterDrivers(
643 PDEVICE_NODE DeviceNode,
644 HANDLE EnumSubKey,
645 HANDLE ClassKey,
646 BOOLEAN Lower)
647 {
648 RTL_QUERY_REGISTRY_TABLE QueryTable[2] = { { NULL, 0, NULL, NULL, 0, NULL, 0 }, };
649 NTSTATUS Status;
650
651 /*
652 * First load the device filters
653 */
654 QueryTable[0].QueryRoutine = IopAttachFilterDriversCallback;
655 if (Lower)
656 QueryTable[0].Name = L"LowerFilters";
657 else
658 QueryTable[0].Name = L"UpperFilters";
659 QueryTable[0].Flags = 0;
660 QueryTable[0].DefaultType = REG_NONE;
661
662 Status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
663 (PWSTR)EnumSubKey,
664 QueryTable,
665 DeviceNode,
666 NULL);
667 if (!NT_SUCCESS(Status))
668 {
669 DPRINT1("Failed to load device %s filters: %08X\n",
670 Lower ? "lower" : "upper", Status);
671 return Status;
672 }
673
674 QueryTable[0].QueryRoutine = IopAttachFilterDriversCallback;
675 if (Lower)
676 QueryTable[0].Name = L"LowerFilters";
677 else
678 QueryTable[0].Name = L"UpperFilters";
679 QueryTable[0].EntryContext = NULL;
680 QueryTable[0].Flags = 0;
681 QueryTable[0].DefaultType = REG_NONE;
682
683 if (ClassKey == NULL)
684 {
685 return STATUS_SUCCESS;
686 }
687
688 Status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
689 (PWSTR)ClassKey,
690 QueryTable,
691 DeviceNode,
692 NULL);
693
694 if (!NT_SUCCESS(Status))
695 {
696 DPRINT1("Failed to load class %s filters: %08X\n",
697 Lower ? "lower" : "upper", Status);
698 return Status;
699 }
700
701 return STATUS_SUCCESS;
702 }
703
704 NTSTATUS
705 NTAPI
706 MiResolveImageReferences(IN PVOID ImageBase,
707 IN PUNICODE_STRING ImageFileDirectory,
708 IN PUNICODE_STRING NamePrefix OPTIONAL,
709 OUT PCHAR *MissingApi,
710 OUT PWCHAR *MissingDriver,
711 OUT PLOAD_IMPORTS *LoadImports);
712
713 //
714 // Used for images already loaded (boot drivers)
715 //
716 NTSTATUS
717 NTAPI
718 INIT_FUNCTION
719 LdrProcessDriverModule(PLDR_DATA_TABLE_ENTRY LdrEntry,
720 PUNICODE_STRING FileName,
721 PLDR_DATA_TABLE_ENTRY *ModuleObject)
722 {
723 NTSTATUS Status;
724 UNICODE_STRING BaseName, BaseDirectory;
725 PLOAD_IMPORTS LoadedImports = (PVOID)-2;
726 PCHAR MissingApiName, Buffer;
727 PWCHAR MissingDriverName;
728 PVOID DriverBase = LdrEntry->DllBase;
729
730 /* Allocate a buffer we'll use for names */
731 Buffer = ExAllocatePoolWithTag(NonPagedPool, MAX_PATH, TAG_LDR_WSTR);
732 if (!Buffer)
733 {
734 /* Fail */
735 return STATUS_INSUFFICIENT_RESOURCES;
736 }
737
738 /* Check for a separator */
739 if (FileName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR)
740 {
741 PWCHAR p;
742 ULONG BaseLength;
743
744 /* Loop the path until we get to the base name */
745 p = &FileName->Buffer[FileName->Length / sizeof(WCHAR)];
746 while (*(p - 1) != OBJ_NAME_PATH_SEPARATOR) p--;
747
748 /* Get the length */
749 BaseLength = (ULONG)(&FileName->Buffer[FileName->Length / sizeof(WCHAR)] - p);
750 BaseLength *= sizeof(WCHAR);
751
752 /* Setup the string */
753 BaseName.Length = (USHORT)BaseLength;
754 BaseName.Buffer = p;
755 }
756 else
757 {
758 /* Otherwise, we already have a base name */
759 BaseName.Length = FileName->Length;
760 BaseName.Buffer = FileName->Buffer;
761 }
762
763 /* Setup the maximum length */
764 BaseName.MaximumLength = BaseName.Length;
765
766 /* Now compute the base directory */
767 BaseDirectory = *FileName;
768 BaseDirectory.Length -= BaseName.Length;
769 BaseDirectory.MaximumLength = BaseDirectory.Length;
770
771 /* Resolve imports */
772 MissingApiName = Buffer;
773 Status = MiResolveImageReferences(DriverBase,
774 &BaseDirectory,
775 NULL,
776 &MissingApiName,
777 &MissingDriverName,
778 &LoadedImports);
779
780 /* Free the temporary buffer */
781 ExFreePoolWithTag(Buffer, TAG_LDR_WSTR);
782
783 /* Check the result of the imports resolution */
784 if (!NT_SUCCESS(Status)) return Status;
785
786 /* Return */
787 *ModuleObject = LdrEntry;
788 return STATUS_SUCCESS;
789 }
790
791 /*
792 * IopInitializeBuiltinDriver
793 *
794 * Initialize a driver that is already loaded in memory.
795 */
796 NTSTATUS
797 NTAPI
798 INIT_FUNCTION
799 IopInitializeBuiltinDriver(IN PLDR_DATA_TABLE_ENTRY BootLdrEntry)
800 {
801 PDEVICE_NODE DeviceNode;
802 PDRIVER_OBJECT DriverObject;
803 NTSTATUS Status;
804 PWCHAR Buffer, FileNameWithoutPath;
805 PWSTR FileExtension;
806 PUNICODE_STRING ModuleName = &BootLdrEntry->BaseDllName;
807 PLDR_DATA_TABLE_ENTRY LdrEntry;
808 PLIST_ENTRY NextEntry;
809 UNICODE_STRING ServiceName;
810 BOOLEAN Success;
811
812 /*
813 * Display 'Loading XXX...' message
814 */
815 IopDisplayLoadingMessage(ModuleName);
816 InbvIndicateProgress();
817
818 Buffer = ExAllocatePoolWithTag(PagedPool,
819 ModuleName->Length + sizeof(UNICODE_NULL),
820 TAG_IO);
821 if (Buffer == NULL)
822 {
823 return STATUS_INSUFFICIENT_RESOURCES;
824 }
825
826 RtlCopyMemory(Buffer, ModuleName->Buffer, ModuleName->Length);
827 Buffer[ModuleName->Length / sizeof(WCHAR)] = UNICODE_NULL;
828
829 /*
830 * Generate filename without path (not needed by freeldr)
831 */
832 FileNameWithoutPath = wcsrchr(Buffer, L'\\');
833 if (FileNameWithoutPath == NULL)
834 {
835 FileNameWithoutPath = Buffer;
836 }
837 else
838 {
839 FileNameWithoutPath++;
840 }
841
842 /*
843 * Strip the file extension from ServiceName
844 */
845 Success = RtlCreateUnicodeString(&ServiceName, FileNameWithoutPath);
846 ExFreePoolWithTag(Buffer, TAG_IO);
847 if (!Success)
848 {
849 return STATUS_INSUFFICIENT_RESOURCES;
850 }
851
852 FileExtension = wcsrchr(ServiceName.Buffer, L'.');
853 if (FileExtension != NULL)
854 {
855 ServiceName.Length -= (USHORT)wcslen(FileExtension) * sizeof(WCHAR);
856 FileExtension[0] = UNICODE_NULL;
857 }
858
859 /*
860 * Determine the right device object
861 */
862 /* Use IopRootDeviceNode for now */
863 Status = IopCreateDeviceNode(IopRootDeviceNode,
864 NULL,
865 &ServiceName,
866 &DeviceNode);
867 RtlFreeUnicodeString(&ServiceName);
868 if (!NT_SUCCESS(Status))
869 {
870 DPRINT1("Driver '%wZ' load failed, status (%x)\n", ModuleName, Status);
871 return Status;
872 }
873
874 /* Lookup the new Ldr entry in PsLoadedModuleList */
875 NextEntry = PsLoadedModuleList.Flink;
876 while (NextEntry != &PsLoadedModuleList)
877 {
878 LdrEntry = CONTAINING_RECORD(NextEntry,
879 LDR_DATA_TABLE_ENTRY,
880 InLoadOrderLinks);
881 if (RtlEqualUnicodeString(ModuleName, &LdrEntry->BaseDllName, TRUE))
882 {
883 break;
884 }
885
886 NextEntry = NextEntry->Flink;
887 }
888 ASSERT(NextEntry != &PsLoadedModuleList);
889
890 /*
891 * Initialize the driver
892 */
893 Status = IopInitializeDriverModule(DeviceNode,
894 LdrEntry,
895 &DeviceNode->ServiceName,
896 FALSE,
897 &DriverObject);
898
899 if (!NT_SUCCESS(Status))
900 {
901 return Status;
902 }
903
904 Status = IopInitializeDevice(DeviceNode, DriverObject);
905 if (NT_SUCCESS(Status))
906 {
907 Status = IopStartDevice(DeviceNode);
908 }
909
910 /* Remove extra reference from IopInitializeDriverModule */
911 ObDereferenceObject(DriverObject);
912
913 return Status;
914 }
915
916 /*
917 * IopInitializeBootDrivers
918 *
919 * Initialize boot drivers and free memory for boot files.
920 *
921 * Parameters
922 * None
923 *
924 * Return Value
925 * None
926 */
927 VOID
928 FASTCALL
929 INIT_FUNCTION
930 IopInitializeBootDrivers(VOID)
931 {
932 PLIST_ENTRY ListHead, NextEntry, NextEntry2;
933 PLDR_DATA_TABLE_ENTRY LdrEntry;
934 PDEVICE_NODE DeviceNode;
935 PDRIVER_OBJECT DriverObject;
936 LDR_DATA_TABLE_ENTRY ModuleObject;
937 NTSTATUS Status;
938 UNICODE_STRING DriverName;
939 ULONG i, Index;
940 PDRIVER_INFORMATION DriverInfo, DriverInfoTag;
941 HANDLE KeyHandle;
942 PBOOT_DRIVER_LIST_ENTRY BootEntry;
943 DPRINT("IopInitializeBootDrivers()\n");
944
945 /* Use IopRootDeviceNode for now */
946 Status = IopCreateDeviceNode(IopRootDeviceNode, NULL, NULL, &DeviceNode);
947 if (!NT_SUCCESS(Status)) return;
948
949 /* Setup the module object for the RAW FS Driver */
950 ModuleObject.DllBase = NULL;
951 ModuleObject.SizeOfImage = 0;
952 ModuleObject.EntryPoint = RawFsDriverEntry;
953 RtlInitUnicodeString(&DriverName, L"RAW");
954
955 /* Initialize it */
956 Status = IopInitializeDriverModule(DeviceNode,
957 &ModuleObject,
958 &DriverName,
959 TRUE,
960 &DriverObject);
961 if (!NT_SUCCESS(Status))
962 {
963 /* Fail */
964 return;
965 }
966
967 /* Now initialize the associated device */
968 Status = IopInitializeDevice(DeviceNode, DriverObject);
969 if (!NT_SUCCESS(Status))
970 {
971 /* Fail */
972 ObDereferenceObject(DriverObject);
973 return;
974 }
975
976 /* Start it up */
977 Status = IopStartDevice(DeviceNode);
978 if (!NT_SUCCESS(Status))
979 {
980 /* Fail */
981 ObDereferenceObject(DriverObject);
982 return;
983 }
984
985 /* Get highest group order index */
986 IopGroupIndex = PpInitGetGroupOrderIndex(NULL);
987 if (IopGroupIndex == 0xFFFF) ASSERT(FALSE);
988
989 /* Allocate the group table */
990 IopGroupTable = ExAllocatePoolWithTag(PagedPool,
991 IopGroupIndex * sizeof(LIST_ENTRY),
992 TAG_IO);
993 if (IopGroupTable == NULL) ASSERT(FALSE);
994
995 /* Initialize the group table lists */
996 for (i = 0; i < IopGroupIndex; i++) InitializeListHead(&IopGroupTable[i]);
997
998 /* Loop the boot modules */
999 ListHead = &KeLoaderBlock->LoadOrderListHead;
1000 NextEntry = ListHead->Flink;
1001 while (ListHead != NextEntry)
1002 {
1003 /* Get the entry */
1004 LdrEntry = CONTAINING_RECORD(NextEntry,
1005 LDR_DATA_TABLE_ENTRY,
1006 InLoadOrderLinks);
1007
1008 /* Check if the DLL needs to be initialized */
1009 if (LdrEntry->Flags & LDRP_DRIVER_DEPENDENT_DLL)
1010 {
1011 /* Call its entrypoint */
1012 MmCallDllInitialize(LdrEntry, NULL);
1013 }
1014
1015 /* Go to the next driver */
1016 NextEntry = NextEntry->Flink;
1017 }
1018
1019 /* Loop the boot drivers */
1020 ListHead = &KeLoaderBlock->BootDriverListHead;
1021 NextEntry = ListHead->Flink;
1022 while (ListHead != NextEntry)
1023 {
1024 /* Get the entry */
1025 BootEntry = CONTAINING_RECORD(NextEntry,
1026 BOOT_DRIVER_LIST_ENTRY,
1027 Link);
1028
1029 /* Get the driver loader entry */
1030 LdrEntry = BootEntry->LdrEntry;
1031
1032 /* Allocate our internal accounting structure */
1033 DriverInfo = ExAllocatePoolWithTag(PagedPool,
1034 sizeof(DRIVER_INFORMATION),
1035 TAG_IO);
1036 if (DriverInfo)
1037 {
1038 /* Zero it and initialize it */
1039 RtlZeroMemory(DriverInfo, sizeof(DRIVER_INFORMATION));
1040 InitializeListHead(&DriverInfo->Link);
1041 DriverInfo->DataTableEntry = BootEntry;
1042
1043 /* Open the registry key */
1044 Status = IopOpenRegistryKeyEx(&KeyHandle,
1045 NULL,
1046 &BootEntry->RegistryPath,
1047 KEY_READ);
1048 DPRINT("IopOpenRegistryKeyEx(%wZ) returned 0x%08lx\n", &BootEntry->RegistryPath, Status);
1049 #if 0
1050 if (NT_SUCCESS(Status))
1051 #else // Hack still needed...
1052 if ((NT_SUCCESS(Status)) || /* ReactOS HACK for SETUPLDR */
1053 ((KeLoaderBlock->SetupLdrBlock) && ((KeyHandle = (PVOID)1)))) // yes, it's an assignment!
1054 #endif
1055 {
1056 /* Save the handle */
1057 DriverInfo->ServiceHandle = KeyHandle;
1058
1059 /* Get the group oder index */
1060 Index = PpInitGetGroupOrderIndex(KeyHandle);
1061
1062 /* Get the tag position */
1063 DriverInfo->TagPosition = PipGetDriverTagPriority(KeyHandle);
1064
1065 /* Insert it into the list, at the right place */
1066 ASSERT(Index < IopGroupIndex);
1067 NextEntry2 = IopGroupTable[Index].Flink;
1068 while (NextEntry2 != &IopGroupTable[Index])
1069 {
1070 /* Get the driver info */
1071 DriverInfoTag = CONTAINING_RECORD(NextEntry2,
1072 DRIVER_INFORMATION,
1073 Link);
1074
1075 /* Check if we found the right tag position */
1076 if (DriverInfoTag->TagPosition > DriverInfo->TagPosition)
1077 {
1078 /* We're done */
1079 break;
1080 }
1081
1082 /* Next entry */
1083 NextEntry2 = NextEntry2->Flink;
1084 }
1085
1086 /* Insert us right before the next entry */
1087 NextEntry2 = NextEntry2->Blink;
1088 InsertHeadList(NextEntry2, &DriverInfo->Link);
1089 }
1090 }
1091
1092 /* Go to the next driver */
1093 NextEntry = NextEntry->Flink;
1094 }
1095
1096 /* Loop each group index */
1097 for (i = 0; i < IopGroupIndex; i++)
1098 {
1099 /* Loop each group table */
1100 NextEntry = IopGroupTable[i].Flink;
1101 while (NextEntry != &IopGroupTable[i])
1102 {
1103 /* Get the entry */
1104 DriverInfo = CONTAINING_RECORD(NextEntry,
1105 DRIVER_INFORMATION,
1106 Link);
1107
1108 /* Get the driver loader entry */
1109 LdrEntry = DriverInfo->DataTableEntry->LdrEntry;
1110
1111 /* Initialize it */
1112 IopInitializeBuiltinDriver(LdrEntry);
1113
1114 /* Next entry */
1115 NextEntry = NextEntry->Flink;
1116 }
1117 }
1118
1119 /* In old ROS, the loader list became empty after this point. Simulate. */
1120 InitializeListHead(&KeLoaderBlock->LoadOrderListHead);
1121 }
1122
1123 VOID
1124 FASTCALL
1125 INIT_FUNCTION
1126 IopInitializeSystemDrivers(VOID)
1127 {
1128 PUNICODE_STRING *DriverList, *SavedList;
1129
1130 /* No system drivers on the boot cd */
1131 if (KeLoaderBlock->SetupLdrBlock) return; // ExpInTextModeSetup
1132
1133 /* Get the driver list */
1134 SavedList = DriverList = CmGetSystemDriverList();
1135 ASSERT(DriverList);
1136
1137 /* Loop it */
1138 while (*DriverList)
1139 {
1140 /* Load the driver */
1141 ZwLoadDriver(*DriverList);
1142
1143 /* Free the entry */
1144 RtlFreeUnicodeString(*DriverList);
1145 ExFreePool(*DriverList);
1146
1147 /* Next entry */
1148 InbvIndicateProgress();
1149 DriverList++;
1150 }
1151
1152 /* Free the list */
1153 ExFreePool(SavedList);
1154 }
1155
1156 /*
1157 * IopUnloadDriver
1158 *
1159 * Unloads a device driver.
1160 *
1161 * Parameters
1162 * DriverServiceName
1163 * Name of the service to unload (registry key).
1164 *
1165 * UnloadPnpDrivers
1166 * Whether to unload Plug & Plug or only legacy drivers. If this
1167 * parameter is set to FALSE, the routine will unload only legacy
1168 * drivers.
1169 *
1170 * Return Value
1171 * Status
1172 *
1173 * To do
1174 * Guard the whole function by SEH.
1175 */
1176
1177 NTSTATUS NTAPI
1178 IopUnloadDriver(PUNICODE_STRING DriverServiceName, BOOLEAN UnloadPnpDrivers)
1179 {
1180 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
1181 UNICODE_STRING ImagePath;
1182 UNICODE_STRING ServiceName;
1183 UNICODE_STRING ObjectName;
1184 PDRIVER_OBJECT DriverObject;
1185 PDEVICE_OBJECT DeviceObject;
1186 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension;
1187 NTSTATUS Status;
1188 PWSTR Start;
1189 BOOLEAN SafeToUnload = TRUE;
1190 KPROCESSOR_MODE PreviousMode;
1191 UNICODE_STRING CapturedServiceName;
1192
1193 PAGED_CODE();
1194
1195 PreviousMode = ExGetPreviousMode();
1196
1197 /* Need the appropriate priviliege */
1198 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, PreviousMode))
1199 {
1200 DPRINT1("No unload privilege!\n");
1201 return STATUS_PRIVILEGE_NOT_HELD;
1202 }
1203
1204 /* Capture the service name */
1205 Status = ProbeAndCaptureUnicodeString(&CapturedServiceName, PreviousMode, DriverServiceName);
1206 if (!NT_SUCCESS(Status))
1207 {
1208 return Status;
1209 }
1210
1211 DPRINT("IopUnloadDriver('%wZ', %u)\n", &CapturedServiceName, UnloadPnpDrivers);
1212
1213
1214 /* We need a service name */
1215 if (CapturedServiceName.Length == 0)
1216 {
1217 ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode);
1218 return STATUS_INVALID_PARAMETER;
1219 }
1220
1221 /*
1222 * Get the service name from the registry key name
1223 */
1224 Start = wcsrchr(CapturedServiceName.Buffer, L'\\');
1225 if (Start == NULL)
1226 Start = CapturedServiceName.Buffer;
1227 else
1228 Start++;
1229
1230 RtlInitUnicodeString(&ServiceName, Start);
1231
1232 /*
1233 * Construct the driver object name
1234 */
1235 ObjectName.Length = ((USHORT)wcslen(Start) + 8) * sizeof(WCHAR);
1236 ObjectName.MaximumLength = ObjectName.Length + sizeof(WCHAR);
1237 ObjectName.Buffer = ExAllocatePoolWithTag(PagedPool,
1238 ObjectName.MaximumLength,
1239 TAG_IO);
1240 if (!ObjectName.Buffer)
1241 {
1242 ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode);
1243 return STATUS_INSUFFICIENT_RESOURCES;
1244 }
1245 wcscpy(ObjectName.Buffer, DRIVER_ROOT_NAME);
1246 memcpy(ObjectName.Buffer + 8, Start, ObjectName.Length - 8 * sizeof(WCHAR));
1247 ObjectName.Buffer[ObjectName.Length/sizeof(WCHAR)] = UNICODE_NULL;
1248
1249 /*
1250 * Find the driver object
1251 */
1252 Status = ObReferenceObjectByName(&ObjectName,
1253 0,
1254 0,
1255 0,
1256 IoDriverObjectType,
1257 KernelMode,
1258 0,
1259 (PVOID*)&DriverObject);
1260
1261 if (!NT_SUCCESS(Status))
1262 {
1263 DPRINT1("Can't locate driver object for %wZ\n", &ObjectName);
1264 ExFreePoolWithTag(ObjectName.Buffer, TAG_IO);
1265 ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode);
1266 return Status;
1267 }
1268
1269 /* Free the buffer for driver object name */
1270 ExFreePoolWithTag(ObjectName.Buffer, TAG_IO);
1271
1272 /* Check that driver is not already unloading */
1273 if (DriverObject->Flags & DRVO_UNLOAD_INVOKED)
1274 {
1275 DPRINT1("Driver deletion pending\n");
1276 ObDereferenceObject(DriverObject);
1277 ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode);
1278 return STATUS_DELETE_PENDING;
1279 }
1280
1281 /*
1282 * Get path of service...
1283 */
1284 RtlZeroMemory(QueryTable, sizeof(QueryTable));
1285
1286 RtlInitUnicodeString(&ImagePath, NULL);
1287
1288 QueryTable[0].Name = L"ImagePath";
1289 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
1290 QueryTable[0].EntryContext = &ImagePath;
1291
1292 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
1293 CapturedServiceName.Buffer,
1294 QueryTable,
1295 NULL,
1296 NULL);
1297
1298 /* We no longer need service name */
1299 ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode);
1300
1301 if (!NT_SUCCESS(Status))
1302 {
1303 DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status);
1304 ObDereferenceObject(DriverObject);
1305 return Status;
1306 }
1307
1308 /*
1309 * Normalize the image path for all later processing.
1310 */
1311 Status = IopNormalizeImagePath(&ImagePath, &ServiceName);
1312
1313 if (!NT_SUCCESS(Status))
1314 {
1315 DPRINT1("IopNormalizeImagePath() failed (Status %x)\n", Status);
1316 ObDereferenceObject(DriverObject);
1317 return Status;
1318 }
1319
1320 /* Free the service path */
1321 ExFreePool(ImagePath.Buffer);
1322
1323 /*
1324 * Unload the module and release the references to the device object
1325 */
1326
1327 /* Call the load/unload routine, depending on current process */
1328 if (DriverObject->DriverUnload && DriverObject->DriverSection &&
1329 (UnloadPnpDrivers || (DriverObject->Flags & DRVO_LEGACY_DRIVER)))
1330 {
1331 /* Loop through each device object of the driver
1332 and set DOE_UNLOAD_PENDING flag */
1333 DeviceObject = DriverObject->DeviceObject;
1334 while (DeviceObject)
1335 {
1336 /* Set the unload pending flag for the device */
1337 DeviceExtension = IoGetDevObjExtension(DeviceObject);
1338 DeviceExtension->ExtensionFlags |= DOE_UNLOAD_PENDING;
1339
1340 /* Make sure there are no attached devices or no reference counts */
1341 if ((DeviceObject->ReferenceCount) || (DeviceObject->AttachedDevice))
1342 {
1343 /* Not safe to unload */
1344 DPRINT1("Drivers device object is referenced or has attached devices\n");
1345
1346 SafeToUnload = FALSE;
1347 }
1348
1349 DeviceObject = DeviceObject->NextDevice;
1350 }
1351
1352 /* If not safe to unload, then return success */
1353 if (!SafeToUnload)
1354 {
1355 ObDereferenceObject(DriverObject);
1356 return STATUS_SUCCESS;
1357 }
1358
1359 DPRINT1("Unloading driver '%wZ' (manual)\n", &DriverObject->DriverName);
1360
1361 /* Set the unload invoked flag and call the unload routine */
1362 DriverObject->Flags |= DRVO_UNLOAD_INVOKED;
1363 Status = IopLoadUnloadDriver(NULL, &DriverObject);
1364 ASSERT(Status == STATUS_SUCCESS);
1365
1366 /* Mark the driver object temporary, so it could be deleted later */
1367 ObMakeTemporaryObject(DriverObject);
1368
1369 /* Dereference it 2 times */
1370 ObDereferenceObject(DriverObject);
1371 ObDereferenceObject(DriverObject);
1372
1373 return Status;
1374 }
1375 else
1376 {
1377 DPRINT1("No DriverUnload function! '%wZ' will not be unloaded!\n", &DriverObject->DriverName);
1378
1379 /* Dereference one time (refd inside this function) */
1380 ObDereferenceObject(DriverObject);
1381
1382 /* Return unloading failure */
1383 return STATUS_INVALID_DEVICE_REQUEST;
1384 }
1385 }
1386
1387 VOID
1388 NTAPI
1389 IopReinitializeDrivers(VOID)
1390 {
1391 PDRIVER_REINIT_ITEM ReinitItem;
1392 PLIST_ENTRY Entry;
1393
1394 /* Get the first entry and start looping */
1395 Entry = ExInterlockedRemoveHeadList(&DriverReinitListHead,
1396 &DriverReinitListLock);
1397 while (Entry)
1398 {
1399 /* Get the item */
1400 ReinitItem = CONTAINING_RECORD(Entry, DRIVER_REINIT_ITEM, ItemEntry);
1401
1402 /* Increment reinitialization counter */
1403 ReinitItem->DriverObject->DriverExtension->Count++;
1404
1405 /* Remove the device object flag */
1406 ReinitItem->DriverObject->Flags &= ~DRVO_REINIT_REGISTERED;
1407
1408 /* Call the routine */
1409 ReinitItem->ReinitRoutine(ReinitItem->DriverObject,
1410 ReinitItem->Context,
1411 ReinitItem->DriverObject->
1412 DriverExtension->Count);
1413
1414 /* Free the entry */
1415 ExFreePool(Entry);
1416
1417 /* Move to the next one */
1418 Entry = ExInterlockedRemoveHeadList(&DriverReinitListHead,
1419 &DriverReinitListLock);
1420 }
1421 }
1422
1423 VOID
1424 NTAPI
1425 IopReinitializeBootDrivers(VOID)
1426 {
1427 PDRIVER_REINIT_ITEM ReinitItem;
1428 PLIST_ENTRY Entry;
1429
1430 /* Get the first entry and start looping */
1431 Entry = ExInterlockedRemoveHeadList(&DriverBootReinitListHead,
1432 &DriverBootReinitListLock);
1433 while (Entry)
1434 {
1435 /* Get the item */
1436 ReinitItem = CONTAINING_RECORD(Entry, DRIVER_REINIT_ITEM, ItemEntry);
1437
1438 /* Increment reinitialization counter */
1439 ReinitItem->DriverObject->DriverExtension->Count++;
1440
1441 /* Remove the device object flag */
1442 ReinitItem->DriverObject->Flags &= ~DRVO_BOOTREINIT_REGISTERED;
1443
1444 /* Call the routine */
1445 ReinitItem->ReinitRoutine(ReinitItem->DriverObject,
1446 ReinitItem->Context,
1447 ReinitItem->DriverObject->
1448 DriverExtension->Count);
1449
1450 /* Free the entry */
1451 ExFreePool(Entry);
1452
1453 /* Move to the next one */
1454 Entry = ExInterlockedRemoveHeadList(&DriverBootReinitListHead,
1455 &DriverBootReinitListLock);
1456 }
1457 }
1458
1459 NTSTATUS
1460 NTAPI
1461 IopCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL,
1462 IN PDRIVER_INITIALIZE InitializationFunction,
1463 IN PUNICODE_STRING RegistryPath OPTIONAL,
1464 IN PCUNICODE_STRING ServiceName,
1465 IN PLDR_DATA_TABLE_ENTRY ModuleObject OPTIONAL,
1466 OUT PDRIVER_OBJECT *pDriverObject)
1467 {
1468 WCHAR NameBuffer[100];
1469 USHORT NameLength;
1470 UNICODE_STRING LocalDriverName;
1471 NTSTATUS Status;
1472 OBJECT_ATTRIBUTES ObjectAttributes;
1473 ULONG ObjectSize;
1474 PDRIVER_OBJECT DriverObject;
1475 UNICODE_STRING ServiceKeyName;
1476 HANDLE hDriver;
1477 ULONG i, RetryCount = 0;
1478
1479 try_again:
1480 /* First, create a unique name for the driver if we don't have one */
1481 if (!DriverName)
1482 {
1483 /* Create a random name and set up the string */
1484 NameLength = (USHORT)swprintf(NameBuffer,
1485 DRIVER_ROOT_NAME L"%08u",
1486 KeTickCount.LowPart);
1487 LocalDriverName.Length = NameLength * sizeof(WCHAR);
1488 LocalDriverName.MaximumLength = LocalDriverName.Length + sizeof(UNICODE_NULL);
1489 LocalDriverName.Buffer = NameBuffer;
1490 }
1491 else
1492 {
1493 /* So we can avoid another code path, use a local var */
1494 LocalDriverName = *DriverName;
1495 }
1496
1497 /* Initialize the Attributes */
1498 ObjectSize = sizeof(DRIVER_OBJECT) + sizeof(EXTENDED_DRIVER_EXTENSION);
1499 InitializeObjectAttributes(&ObjectAttributes,
1500 &LocalDriverName,
1501 OBJ_PERMANENT | OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1502 NULL,
1503 NULL);
1504
1505 /* Create the Object */
1506 Status = ObCreateObject(KernelMode,
1507 IoDriverObjectType,
1508 &ObjectAttributes,
1509 KernelMode,
1510 NULL,
1511 ObjectSize,
1512 0,
1513 0,
1514 (PVOID*)&DriverObject);
1515 if (!NT_SUCCESS(Status)) return Status;
1516
1517 DPRINT("IopCreateDriver(): created DO %p\n", DriverObject);
1518
1519 /* Set up the Object */
1520 RtlZeroMemory(DriverObject, ObjectSize);
1521 DriverObject->Type = IO_TYPE_DRIVER;
1522 DriverObject->Size = sizeof(DRIVER_OBJECT);
1523
1524 /*
1525 * Check whether RegistryPath and ModuleObject are both NULL because
1526 * IoCreateDriver() was called to initialize a built-in driver.
1527 */
1528 if ((RegistryPath != NULL) || (ModuleObject != NULL))
1529 DriverObject->Flags = DRVO_LEGACY_DRIVER;
1530 else
1531 DriverObject->Flags = DRVO_BUILTIN_DRIVER;
1532
1533 DriverObject->DriverExtension = (PDRIVER_EXTENSION)(DriverObject + 1);
1534 DriverObject->DriverExtension->DriverObject = DriverObject;
1535 DriverObject->DriverInit = InitializationFunction;
1536 DriverObject->DriverSection = ModuleObject;
1537 /* Loop all Major Functions */
1538 for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
1539 {
1540 /* Invalidate each function */
1541 DriverObject->MajorFunction[i] = IopInvalidDeviceRequest;
1542 }
1543
1544 /* Set up the service key name buffer */
1545 ServiceKeyName.MaximumLength = ServiceName->Length + sizeof(UNICODE_NULL);
1546 ServiceKeyName.Buffer = ExAllocatePoolWithTag(NonPagedPool,
1547 ServiceKeyName.MaximumLength,
1548 TAG_IO);
1549 if (!ServiceKeyName.Buffer)
1550 {
1551 /* Fail */
1552 ObMakeTemporaryObject(DriverObject);
1553 ObDereferenceObject(DriverObject);
1554 return STATUS_INSUFFICIENT_RESOURCES;
1555 }
1556
1557 /* Copy the name and set it in the driver extension */
1558 RtlCopyUnicodeString(&ServiceKeyName,
1559 ServiceName);
1560 DriverObject->DriverExtension->ServiceKeyName = ServiceKeyName;
1561
1562 /* Make a copy of the driver name to store in the driver object */
1563 DriverObject->DriverName.MaximumLength = LocalDriverName.Length;
1564 DriverObject->DriverName.Buffer = ExAllocatePoolWithTag(PagedPool,
1565 DriverObject->DriverName.MaximumLength,
1566 TAG_IO);
1567 if (!DriverObject->DriverName.Buffer)
1568 {
1569 /* Fail */
1570 ObMakeTemporaryObject(DriverObject);
1571 ObDereferenceObject(DriverObject);
1572 return STATUS_INSUFFICIENT_RESOURCES;
1573 }
1574
1575 RtlCopyUnicodeString(&DriverObject->DriverName,
1576 &LocalDriverName);
1577
1578 /* Add the Object and get its handle */
1579 Status = ObInsertObject(DriverObject,
1580 NULL,
1581 FILE_READ_DATA,
1582 0,
1583 NULL,
1584 &hDriver);
1585
1586 /* Eliminate small possibility when this function is called more than
1587 once in a row, and KeTickCount doesn't get enough time to change */
1588 if (!DriverName && (Status == STATUS_OBJECT_NAME_COLLISION) && (RetryCount < 100))
1589 {
1590 RetryCount++;
1591 goto try_again;
1592 }
1593
1594 if (!NT_SUCCESS(Status)) return Status;
1595
1596 /* Now reference it */
1597 Status = ObReferenceObjectByHandle(hDriver,
1598 0,
1599 IoDriverObjectType,
1600 KernelMode,
1601 (PVOID*)&DriverObject,
1602 NULL);
1603
1604 /* Close the extra handle */
1605 ZwClose(hDriver);
1606
1607 if (!NT_SUCCESS(Status))
1608 {
1609 /* Fail */
1610 ObMakeTemporaryObject(DriverObject);
1611 ObDereferenceObject(DriverObject);
1612 return Status;
1613 }
1614
1615 DriverObject->HardwareDatabase = &IopHardwareDatabaseKey;
1616 DriverObject->DriverStart = ModuleObject ? ModuleObject->DllBase : 0;
1617 DriverObject->DriverSize = ModuleObject ? ModuleObject->SizeOfImage : 0;
1618
1619 /* Finally, call its init function */
1620 DPRINT("RegistryKey: %wZ\n", RegistryPath);
1621 DPRINT("Calling driver entrypoint at %p\n", InitializationFunction);
1622 Status = (*InitializationFunction)(DriverObject, RegistryPath);
1623 if (!NT_SUCCESS(Status))
1624 {
1625 /* If it didn't work, then kill the object */
1626 DPRINT1("'%wZ' initialization failed, status (0x%08lx)\n", DriverName, Status);
1627 DriverObject->DriverSection = NULL;
1628 ObMakeTemporaryObject(DriverObject);
1629 ObDereferenceObject(DriverObject);
1630 return Status;
1631 }
1632 else
1633 {
1634 /* Returns to caller the object */
1635 *pDriverObject = DriverObject;
1636 }
1637
1638 /* We're going to say if we don't have any DOs from DriverEntry, then we're not legacy.
1639 * Other parts of the I/O manager depend on this behavior */
1640 if (!DriverObject->DeviceObject) DriverObject->Flags &= ~DRVO_LEGACY_DRIVER;
1641
1642 /* Loop all Major Functions */
1643 for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
1644 {
1645 /*
1646 * Make sure the driver didn't set any dispatch entry point to NULL!
1647 * Doing so is illegal; drivers shouldn't touch entry points they
1648 * do not implement.
1649 */
1650
1651 /* Check if it did so anyway */
1652 if (!DriverObject->MajorFunction[i])
1653 {
1654 /* Print a warning in the debug log */
1655 DPRINT1("Driver <%wZ> set DriverObject->MajorFunction[%lu] to NULL!\n",
1656 &DriverObject->DriverName, i);
1657
1658 /* Fix it up */
1659 DriverObject->MajorFunction[i] = IopInvalidDeviceRequest;
1660 }
1661 }
1662
1663 /* Return the Status */
1664 return Status;
1665 }
1666
1667 /* PUBLIC FUNCTIONS ***********************************************************/
1668
1669 /*
1670 * @implemented
1671 */
1672 NTSTATUS
1673 NTAPI
1674 IoCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL,
1675 IN PDRIVER_INITIALIZE InitializationFunction)
1676 {
1677 PDRIVER_OBJECT DriverObject;
1678 return IopCreateDriver(DriverName, InitializationFunction, NULL, DriverName, NULL, &DriverObject);
1679 }
1680
1681 /*
1682 * @implemented
1683 */
1684 VOID
1685 NTAPI
1686 IoDeleteDriver(IN PDRIVER_OBJECT DriverObject)
1687 {
1688 /* Simply dereference the Object */
1689 ObDereferenceObject(DriverObject);
1690 }
1691
1692 /*
1693 * @implemented
1694 */
1695 VOID
1696 NTAPI
1697 IoRegisterBootDriverReinitialization(IN PDRIVER_OBJECT DriverObject,
1698 IN PDRIVER_REINITIALIZE ReinitRoutine,
1699 IN PVOID Context)
1700 {
1701 PDRIVER_REINIT_ITEM ReinitItem;
1702
1703 /* Allocate the entry */
1704 ReinitItem = ExAllocatePoolWithTag(NonPagedPool,
1705 sizeof(DRIVER_REINIT_ITEM),
1706 TAG_REINIT);
1707 if (!ReinitItem) return;
1708
1709 /* Fill it out */
1710 ReinitItem->DriverObject = DriverObject;
1711 ReinitItem->ReinitRoutine = ReinitRoutine;
1712 ReinitItem->Context = Context;
1713
1714 /* Set the Driver Object flag and insert the entry into the list */
1715 DriverObject->Flags |= DRVO_BOOTREINIT_REGISTERED;
1716 ExInterlockedInsertTailList(&DriverBootReinitListHead,
1717 &ReinitItem->ItemEntry,
1718 &DriverBootReinitListLock);
1719 }
1720
1721 /*
1722 * @implemented
1723 */
1724 VOID
1725 NTAPI
1726 IoRegisterDriverReinitialization(IN PDRIVER_OBJECT DriverObject,
1727 IN PDRIVER_REINITIALIZE ReinitRoutine,
1728 IN PVOID Context)
1729 {
1730 PDRIVER_REINIT_ITEM ReinitItem;
1731
1732 /* Allocate the entry */
1733 ReinitItem = ExAllocatePoolWithTag(NonPagedPool,
1734 sizeof(DRIVER_REINIT_ITEM),
1735 TAG_REINIT);
1736 if (!ReinitItem) return;
1737
1738 /* Fill it out */
1739 ReinitItem->DriverObject = DriverObject;
1740 ReinitItem->ReinitRoutine = ReinitRoutine;
1741 ReinitItem->Context = Context;
1742
1743 /* Set the Driver Object flag and insert the entry into the list */
1744 DriverObject->Flags |= DRVO_REINIT_REGISTERED;
1745 ExInterlockedInsertTailList(&DriverReinitListHead,
1746 &ReinitItem->ItemEntry,
1747 &DriverReinitListLock);
1748 }
1749
1750 /*
1751 * @implemented
1752 */
1753 NTSTATUS
1754 NTAPI
1755 IoAllocateDriverObjectExtension(IN PDRIVER_OBJECT DriverObject,
1756 IN PVOID ClientIdentificationAddress,
1757 IN ULONG DriverObjectExtensionSize,
1758 OUT PVOID *DriverObjectExtension)
1759 {
1760 KIRQL OldIrql;
1761 PIO_CLIENT_EXTENSION DriverExtensions, NewDriverExtension;
1762 BOOLEAN Inserted = FALSE;
1763
1764 /* Assume failure */
1765 *DriverObjectExtension = NULL;
1766
1767 /* Allocate the extension */
1768 NewDriverExtension = ExAllocatePoolWithTag(NonPagedPool,
1769 sizeof(IO_CLIENT_EXTENSION) +
1770 DriverObjectExtensionSize,
1771 TAG_DRIVER_EXTENSION);
1772 if (!NewDriverExtension) return STATUS_INSUFFICIENT_RESOURCES;
1773
1774 /* Clear the extension for teh caller */
1775 RtlZeroMemory(NewDriverExtension,
1776 sizeof(IO_CLIENT_EXTENSION) + DriverObjectExtensionSize);
1777
1778 /* Acqure lock */
1779 OldIrql = KeRaiseIrqlToDpcLevel();
1780
1781 /* Fill out the extension */
1782 NewDriverExtension->ClientIdentificationAddress = ClientIdentificationAddress;
1783
1784 /* Loop the current extensions */
1785 DriverExtensions = IoGetDrvObjExtension(DriverObject)->
1786 ClientDriverExtension;
1787 while (DriverExtensions)
1788 {
1789 /* Check if the identifier matches */
1790 if (DriverExtensions->ClientIdentificationAddress ==
1791 ClientIdentificationAddress)
1792 {
1793 /* We have a collision, break out */
1794 break;
1795 }
1796
1797 /* Go to the next one */
1798 DriverExtensions = DriverExtensions->NextExtension;
1799 }
1800
1801 /* Check if we didn't collide */
1802 if (!DriverExtensions)
1803 {
1804 /* Link this one in */
1805 NewDriverExtension->NextExtension =
1806 IoGetDrvObjExtension(DriverObject)->ClientDriverExtension;
1807 IoGetDrvObjExtension(DriverObject)->ClientDriverExtension =
1808 NewDriverExtension;
1809 Inserted = TRUE;
1810 }
1811
1812 /* Release the lock */
1813 KeLowerIrql(OldIrql);
1814
1815 /* Check if insertion failed */
1816 if (!Inserted)
1817 {
1818 /* Free the entry and fail */
1819 ExFreePoolWithTag(NewDriverExtension, TAG_DRIVER_EXTENSION);
1820 return STATUS_OBJECT_NAME_COLLISION;
1821 }
1822
1823 /* Otherwise, return the pointer */
1824 *DriverObjectExtension = NewDriverExtension + 1;
1825 return STATUS_SUCCESS;
1826 }
1827
1828 /*
1829 * @implemented
1830 */
1831 PVOID
1832 NTAPI
1833 IoGetDriverObjectExtension(IN PDRIVER_OBJECT DriverObject,
1834 IN PVOID ClientIdentificationAddress)
1835 {
1836 KIRQL OldIrql;
1837 PIO_CLIENT_EXTENSION DriverExtensions;
1838
1839 /* Acquire lock */
1840 OldIrql = KeRaiseIrqlToDpcLevel();
1841
1842 /* Loop the list until we find the right one */
1843 DriverExtensions = IoGetDrvObjExtension(DriverObject)->ClientDriverExtension;
1844 while (DriverExtensions)
1845 {
1846 /* Check for a match */
1847 if (DriverExtensions->ClientIdentificationAddress ==
1848 ClientIdentificationAddress)
1849 {
1850 /* Break out */
1851 break;
1852 }
1853
1854 /* Keep looping */
1855 DriverExtensions = DriverExtensions->NextExtension;
1856 }
1857
1858 /* Release lock */
1859 KeLowerIrql(OldIrql);
1860
1861 /* Return nothing or the extension */
1862 if (!DriverExtensions) return NULL;
1863 return DriverExtensions + 1;
1864 }
1865
1866 VOID
1867 NTAPI
1868 IopLoadUnloadDriverWorker(
1869 _Inout_ PVOID Parameter)
1870 {
1871 PLOAD_UNLOAD_PARAMS LoadParams = Parameter;
1872
1873 ASSERT(PsGetCurrentProcess() == PsInitialSystemProcess);
1874 LoadParams->Status = IopLoadUnloadDriver(LoadParams->RegistryPath,
1875 &LoadParams->DriverObject);
1876 KeSetEvent(&LoadParams->Event, 0, FALSE);
1877 }
1878
1879 NTSTATUS
1880 NTAPI
1881 IopLoadUnloadDriver(
1882 _In_opt_ PCUNICODE_STRING RegistryPath,
1883 _Inout_ PDRIVER_OBJECT *DriverObject)
1884 {
1885 RTL_QUERY_REGISTRY_TABLE QueryTable[3];
1886 UNICODE_STRING ImagePath;
1887 UNICODE_STRING ServiceName;
1888 NTSTATUS Status;
1889 ULONG Type;
1890 PDEVICE_NODE DeviceNode;
1891 PLDR_DATA_TABLE_ENTRY ModuleObject;
1892 PVOID BaseAddress;
1893 WCHAR *cur;
1894
1895 /* Load/Unload must be called from system process */
1896 if (PsGetCurrentProcess() != PsInitialSystemProcess)
1897 {
1898 LOAD_UNLOAD_PARAMS LoadParams;
1899
1900 /* Prepare parameters block */
1901 LoadParams.RegistryPath = RegistryPath;
1902 LoadParams.DriverObject = *DriverObject;
1903 KeInitializeEvent(&LoadParams.Event, NotificationEvent, FALSE);
1904
1905 /* Initialize and queue a work item */
1906 ExInitializeWorkItem(&LoadParams.WorkItem,
1907 IopLoadUnloadDriverWorker,
1908 &LoadParams);
1909 ExQueueWorkItem(&LoadParams.WorkItem, DelayedWorkQueue);
1910
1911 /* And wait till it completes */
1912 KeWaitForSingleObject(&LoadParams.Event,
1913 UserRequest,
1914 KernelMode,
1915 FALSE,
1916 NULL);
1917 return LoadParams.Status;
1918 }
1919
1920 /* Check if it's an unload request */
1921 if (*DriverObject)
1922 {
1923 (*DriverObject)->DriverUnload(*DriverObject);
1924 return STATUS_SUCCESS;
1925 }
1926
1927 RtlInitUnicodeString(&ImagePath, NULL);
1928
1929 /*
1930 * Get the service name from the registry key name.
1931 */
1932 ASSERT(RegistryPath->Length >= sizeof(WCHAR));
1933
1934 ServiceName = *RegistryPath;
1935 cur = RegistryPath->Buffer + RegistryPath->Length / sizeof(WCHAR) - 1;
1936 while (RegistryPath->Buffer != cur)
1937 {
1938 if (*cur == L'\\')
1939 {
1940 ServiceName.Buffer = cur + 1;
1941 ServiceName.Length = RegistryPath->Length -
1942 (USHORT)((ULONG_PTR)ServiceName.Buffer -
1943 (ULONG_PTR)RegistryPath->Buffer);
1944 break;
1945 }
1946 cur--;
1947 }
1948
1949 /*
1950 * Get service type.
1951 */
1952 RtlZeroMemory(&QueryTable, sizeof(QueryTable));
1953
1954 RtlInitUnicodeString(&ImagePath, NULL);
1955
1956 QueryTable[0].Name = L"Type";
1957 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
1958 QueryTable[0].EntryContext = &Type;
1959
1960 QueryTable[1].Name = L"ImagePath";
1961 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
1962 QueryTable[1].EntryContext = &ImagePath;
1963
1964 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
1965 RegistryPath->Buffer,
1966 QueryTable, NULL, NULL);
1967 if (!NT_SUCCESS(Status))
1968 {
1969 DPRINT("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
1970 if (ImagePath.Buffer) ExFreePool(ImagePath.Buffer);
1971 return Status;
1972 }
1973
1974 /*
1975 * Normalize the image path for all later processing.
1976 */
1977 Status = IopNormalizeImagePath(&ImagePath, &ServiceName);
1978 if (!NT_SUCCESS(Status))
1979 {
1980 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status);
1981 return Status;
1982 }
1983
1984 DPRINT("FullImagePath: '%wZ'\n", &ImagePath);
1985 DPRINT("Type: %lx\n", Type);
1986
1987 KeEnterCriticalRegion();
1988 ExAcquireResourceExclusiveLite(&IopDriverLoadResource, TRUE);
1989 /*
1990 * Get existing DriverObject pointer (in case the driver
1991 * has already been loaded and initialized).
1992 */
1993 Status = IopGetDriverObject(DriverObject,
1994 &ServiceName,
1995 (Type == SERVICE_FILE_SYSTEM_DRIVER ||
1996 Type == SERVICE_RECOGNIZER_DRIVER));
1997
1998 if (!NT_SUCCESS(Status))
1999 {
2000 /*
2001 * Load the driver module
2002 */
2003 DPRINT("Loading module from %wZ\n", &ImagePath);
2004 Status = MmLoadSystemImage(&ImagePath, NULL, NULL, 0, (PVOID)&ModuleObject, &BaseAddress);
2005 if (!NT_SUCCESS(Status))
2006 {
2007 DPRINT("MmLoadSystemImage() failed (Status %lx)\n", Status);
2008 ExReleaseResourceLite(&IopDriverLoadResource);
2009 KeLeaveCriticalRegion();
2010 return Status;
2011 }
2012
2013 /*
2014 * Initialize the driver module if it's loaded for the first time
2015 */
2016 Status = IopCreateDeviceNode(IopRootDeviceNode, NULL, &ServiceName, &DeviceNode);
2017 if (!NT_SUCCESS(Status))
2018 {
2019 DPRINT1("IopCreateDeviceNode() failed (Status %lx)\n", Status);
2020 ExReleaseResourceLite(&IopDriverLoadResource);
2021 KeLeaveCriticalRegion();
2022 MmUnloadSystemImage(ModuleObject);
2023 return Status;
2024 }
2025
2026 IopDisplayLoadingMessage(&DeviceNode->ServiceName);
2027
2028 Status = IopInitializeDriverModule(DeviceNode,
2029 ModuleObject,
2030 &DeviceNode->ServiceName,
2031 (Type == SERVICE_FILE_SYSTEM_DRIVER ||
2032 Type == SERVICE_RECOGNIZER_DRIVER),
2033 DriverObject);
2034 if (!NT_SUCCESS(Status))
2035 {
2036 DPRINT1("IopInitializeDriverModule() failed (Status %lx)\n", Status);
2037 ExReleaseResourceLite(&IopDriverLoadResource);
2038 KeLeaveCriticalRegion();
2039 MmUnloadSystemImage(ModuleObject);
2040 return Status;
2041 }
2042
2043 ExReleaseResourceLite(&IopDriverLoadResource);
2044 KeLeaveCriticalRegion();
2045
2046 /* Initialize and start device */
2047 IopInitializeDevice(DeviceNode, *DriverObject);
2048 Status = IopStartDevice(DeviceNode);
2049 }
2050 else
2051 {
2052 ExReleaseResourceLite(&IopDriverLoadResource);
2053 KeLeaveCriticalRegion();
2054
2055 DPRINT("DriverObject already exist in ObjectManager\n");
2056 Status = STATUS_IMAGE_ALREADY_LOADED;
2057
2058 /* IopGetDriverObject references the DriverObject, so dereference it */
2059 ObDereferenceObject(*DriverObject);
2060 }
2061
2062 return Status;
2063 }
2064
2065 /*
2066 * NtLoadDriver
2067 *
2068 * Loads a device driver.
2069 *
2070 * Parameters
2071 * DriverServiceName
2072 * Name of the service to load (registry key).
2073 *
2074 * Return Value
2075 * Status
2076 *
2077 * Status
2078 * implemented
2079 */
2080 NTSTATUS NTAPI
2081 NtLoadDriver(IN PUNICODE_STRING DriverServiceName)
2082 {
2083 UNICODE_STRING CapturedDriverServiceName = { 0, 0, NULL };
2084 KPROCESSOR_MODE PreviousMode;
2085 PDRIVER_OBJECT DriverObject;
2086 NTSTATUS Status;
2087
2088 PAGED_CODE();
2089
2090 PreviousMode = KeGetPreviousMode();
2091
2092 /*
2093 * Check security privileges
2094 */
2095
2096 /* FIXME: Uncomment when privileges will be correctly implemented. */
2097 #if 0
2098 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, PreviousMode))
2099 {
2100 DPRINT("Privilege not held\n");
2101 return STATUS_PRIVILEGE_NOT_HELD;
2102 }
2103 #endif
2104
2105 Status = ProbeAndCaptureUnicodeString(&CapturedDriverServiceName,
2106 PreviousMode,
2107 DriverServiceName);
2108 if (!NT_SUCCESS(Status))
2109 {
2110 return Status;
2111 }
2112
2113 DPRINT("NtLoadDriver('%wZ')\n", &CapturedDriverServiceName);
2114
2115 /* Load driver and call its entry point */
2116 DriverObject = NULL;
2117 Status = IopLoadUnloadDriver(&CapturedDriverServiceName, &DriverObject);
2118
2119 ReleaseCapturedUnicodeString(&CapturedDriverServiceName,
2120 PreviousMode);
2121
2122 return Status;
2123 }
2124
2125 /*
2126 * NtUnloadDriver
2127 *
2128 * Unloads a legacy device driver.
2129 *
2130 * Parameters
2131 * DriverServiceName
2132 * Name of the service to unload (registry key).
2133 *
2134 * Return Value
2135 * Status
2136 *
2137 * Status
2138 * implemented
2139 */
2140
2141 NTSTATUS NTAPI
2142 NtUnloadDriver(IN PUNICODE_STRING DriverServiceName)
2143 {
2144 return IopUnloadDriver(DriverServiceName, FALSE);
2145 }
2146
2147 /* EOF */