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