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