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