merge 37282 from amd64-branch:
[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 TAG('R', 'q', 'r', 'v')
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 LOAD_UNLOAD_PARAMS LoadParams;
981 NTSTATUS Status;
982 LPWSTR Start;
983
984 DPRINT("IopUnloadDriver('%wZ', %d)\n", DriverServiceName, UnloadPnpDrivers);
985
986 PAGED_CODE();
987
988 /*
989 * Get the service name from the registry key name
990 */
991
992 Start = wcsrchr(DriverServiceName->Buffer, L'\\');
993 if (Start == NULL)
994 Start = DriverServiceName->Buffer;
995 else
996 Start++;
997
998 RtlInitUnicodeString(&ServiceName, Start);
999
1000 /*
1001 * Construct the driver object name
1002 */
1003
1004 ObjectName.Length = (wcslen(Start) + 8) * sizeof(WCHAR);
1005 ObjectName.MaximumLength = ObjectName.Length + sizeof(WCHAR);
1006 ObjectName.Buffer = ExAllocatePool(PagedPool, ObjectName.MaximumLength);
1007 wcscpy(ObjectName.Buffer, L"\\Driver\\");
1008 memcpy(ObjectName.Buffer + 8, Start, ObjectName.Length - 8 * sizeof(WCHAR));
1009 ObjectName.Buffer[ObjectName.Length/sizeof(WCHAR)] = 0;
1010
1011 /*
1012 * Find the driver object
1013 */
1014 Status = ObReferenceObjectByName(&ObjectName,
1015 0,
1016 0,
1017 0,
1018 IoDriverObjectType,
1019 KernelMode,
1020 0,
1021 (PVOID*)&DriverObject);
1022
1023 /*
1024 * Free the buffer for driver object name
1025 */
1026 ExFreePool(ObjectName.Buffer);
1027
1028 if (!NT_SUCCESS(Status))
1029 {
1030 DPRINT1("Can't locate driver object for %wZ\n", &ObjectName);
1031 return Status;
1032 }
1033
1034 /*
1035 * Get path of service...
1036 */
1037
1038 RtlZeroMemory(QueryTable, sizeof(QueryTable));
1039
1040 RtlInitUnicodeString(&ImagePath, NULL);
1041
1042 QueryTable[0].Name = L"ImagePath";
1043 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
1044 QueryTable[0].EntryContext = &ImagePath;
1045
1046 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
1047 DriverServiceName->Buffer, QueryTable, NULL, NULL);
1048
1049 if (!NT_SUCCESS(Status))
1050 {
1051 DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status);
1052 return Status;
1053 }
1054
1055 /*
1056 * Normalize the image path for all later processing.
1057 */
1058
1059 Status = IopNormalizeImagePath(&ImagePath, &ServiceName);
1060
1061 if (!NT_SUCCESS(Status))
1062 {
1063 DPRINT1("IopNormalizeImagePath() failed (Status %x)\n", Status);
1064 return Status;
1065 }
1066
1067 /*
1068 * Free the service path
1069 */
1070
1071 ExFreePool(ImagePath.Buffer);
1072
1073 /*
1074 * Unload the module and release the references to the device object
1075 */
1076
1077 /* Call the load/unload routine, depending on current process */
1078 if (DriverObject->DriverUnload && DriverObject->DriverSection)
1079 {
1080 if (PsGetCurrentProcess() == PsInitialSystemProcess)
1081 {
1082 /* Just call right away */
1083 (*DriverObject->DriverUnload)(DriverObject);
1084 }
1085 else
1086 {
1087 /* Load/Unload must be called from system process */
1088
1089 /* Prepare parameters block */
1090 LoadParams.DriverObject = DriverObject;
1091 KeInitializeEvent(&LoadParams.Event, NotificationEvent, FALSE);
1092
1093 ExInitializeWorkItem(&LoadParams.WorkItem,
1094 (PWORKER_THREAD_ROUTINE)IopLoadUnloadDriver,
1095 (PVOID)&LoadParams);
1096
1097 /* Queue it */
1098 ExQueueWorkItem(&LoadParams.WorkItem, DelayedWorkQueue);
1099
1100 /* And wait when it completes */
1101 KeWaitForSingleObject(&LoadParams.Event, UserRequest, KernelMode,
1102 FALSE, NULL);
1103 }
1104
1105 /* Mark the driver object temporary, so it could be deleted later */
1106 ObMakeTemporaryObject(DriverObject);
1107
1108 /* Dereference it 2 times */
1109 ObDereferenceObject(DriverObject);
1110 ObDereferenceObject(DriverObject);
1111
1112 return STATUS_SUCCESS;
1113 }
1114 else
1115 {
1116 /* Dereference one time (refd inside this function) */
1117 ObDereferenceObject(DriverObject);
1118
1119 /* Return unloading failure */
1120 return STATUS_INVALID_DEVICE_REQUEST;
1121 }
1122 }
1123
1124 VOID
1125 NTAPI
1126 IopReinitializeDrivers(VOID)
1127 {
1128 PDRIVER_REINIT_ITEM ReinitItem;
1129 PLIST_ENTRY Entry;
1130
1131 /* Get the first entry and start looping */
1132 Entry = ExInterlockedRemoveHeadList(&DriverReinitListHead,
1133 &DriverReinitListLock);
1134 while (Entry)
1135 {
1136 /* Get the item*/
1137 ReinitItem = CONTAINING_RECORD(Entry, DRIVER_REINIT_ITEM, ItemEntry);
1138
1139 /* Increment reinitialization counter */
1140 ReinitItem->DriverObject->DriverExtension->Count++;
1141
1142 /* Remove the device object flag */
1143 ReinitItem->DriverObject->Flags &= ~DRVO_REINIT_REGISTERED;
1144
1145 /* Call the routine */
1146 ReinitItem->ReinitRoutine(ReinitItem->DriverObject,
1147 ReinitItem->Context,
1148 ReinitItem->DriverObject->
1149 DriverExtension->Count);
1150
1151 /* Free the entry */
1152 ExFreePool(Entry);
1153
1154 /* Move to the next one */
1155 Entry = ExInterlockedRemoveHeadList(&DriverReinitListHead,
1156 &DriverReinitListLock);
1157 }
1158 }
1159
1160 VOID
1161 NTAPI
1162 IopReinitializeBootDrivers(VOID)
1163 {
1164 PDRIVER_REINIT_ITEM ReinitItem;
1165 PLIST_ENTRY Entry;
1166
1167 /* Get the first entry and start looping */
1168 Entry = ExInterlockedRemoveHeadList(&DriverBootReinitListHead,
1169 &DriverBootReinitListLock);
1170 while (Entry)
1171 {
1172 /* Get the item*/
1173 ReinitItem = CONTAINING_RECORD(Entry, DRIVER_REINIT_ITEM, ItemEntry);
1174
1175 /* Increment reinitialization counter */
1176 ReinitItem->DriverObject->DriverExtension->Count++;
1177
1178 /* Remove the device object flag */
1179 ReinitItem->DriverObject->Flags &= ~DRVO_BOOTREINIT_REGISTERED;
1180
1181 /* Call the routine */
1182 ReinitItem->ReinitRoutine(ReinitItem->DriverObject,
1183 ReinitItem->Context,
1184 ReinitItem->DriverObject->
1185 DriverExtension->Count);
1186
1187 /* Free the entry */
1188 ExFreePool(Entry);
1189
1190 /* Move to the next one */
1191 Entry = ExInterlockedRemoveHeadList(&DriverBootReinitListHead,
1192 &DriverBootReinitListLock);
1193 }
1194 }
1195
1196 NTSTATUS
1197 NTAPI
1198 IopCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL,
1199 IN PDRIVER_INITIALIZE InitializationFunction,
1200 IN PUNICODE_STRING RegistryPath,
1201 IN PVOID DllBase,
1202 IN ULONG SizeOfImage,
1203 OUT PDRIVER_OBJECT *pDriverObject)
1204 {
1205 WCHAR NameBuffer[100];
1206 USHORT NameLength;
1207 UNICODE_STRING LocalDriverName;
1208 NTSTATUS Status;
1209 OBJECT_ATTRIBUTES ObjectAttributes;
1210 ULONG ObjectSize;
1211 PDRIVER_OBJECT DriverObject;
1212 UNICODE_STRING ServiceKeyName;
1213 HANDLE hDriver;
1214 ULONG i, RetryCount = 0;
1215
1216 try_again:
1217 /* First, create a unique name for the driver if we don't have one */
1218 if (!DriverName)
1219 {
1220 /* Create a random name and set up the string*/
1221 NameLength = (USHORT)swprintf(NameBuffer,
1222 L"\\Driver\\%08u",
1223 KeTickCount);
1224 LocalDriverName.Length = NameLength * sizeof(WCHAR);
1225 LocalDriverName.MaximumLength = LocalDriverName.Length + sizeof(UNICODE_NULL);
1226 LocalDriverName.Buffer = NameBuffer;
1227 }
1228 else
1229 {
1230 /* So we can avoid another code path, use a local var */
1231 LocalDriverName = *DriverName;
1232 }
1233
1234 /* Initialize the Attributes */
1235 ObjectSize = sizeof(DRIVER_OBJECT) + sizeof(EXTENDED_DRIVER_EXTENSION);
1236 InitializeObjectAttributes(&ObjectAttributes,
1237 &LocalDriverName,
1238 OBJ_PERMANENT | OBJ_CASE_INSENSITIVE,
1239 NULL,
1240 NULL);
1241
1242 /* Create the Object */
1243 Status = ObCreateObject(KernelMode,
1244 IoDriverObjectType,
1245 &ObjectAttributes,
1246 KernelMode,
1247 NULL,
1248 ObjectSize,
1249 0,
1250 0,
1251 (PVOID*)&DriverObject);
1252 if (!NT_SUCCESS(Status)) return Status;
1253
1254 DPRINT("IopCreateDriver(): created DO %p\n", DriverObject);
1255
1256 /* Set up the Object */
1257 RtlZeroMemory(DriverObject, ObjectSize);
1258 DriverObject->Type = IO_TYPE_DRIVER;
1259 DriverObject->Size = sizeof(DRIVER_OBJECT);
1260 DriverObject->Flags = DRVO_BUILTIN_DRIVER;
1261 DriverObject->DriverExtension = (PDRIVER_EXTENSION)(DriverObject + 1);
1262 DriverObject->DriverExtension->DriverObject = DriverObject;
1263 DriverObject->DriverInit = InitializationFunction;
1264
1265 /* Loop all Major Functions */
1266 for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
1267 {
1268 /* Invalidate each function */
1269 DriverObject->MajorFunction[i] = IopInvalidDeviceRequest;
1270 }
1271
1272 /* Set up the service key name buffer */
1273 ServiceKeyName.Buffer = ExAllocatePoolWithTag(PagedPool,
1274 LocalDriverName.Length +
1275 sizeof(WCHAR),
1276 TAG_IO);
1277 if (!ServiceKeyName.Buffer)
1278 {
1279 /* Fail */
1280 ObMakeTemporaryObject(DriverObject);
1281 ObDereferenceObject(DriverObject);
1282 return STATUS_INSUFFICIENT_RESOURCES;
1283 }
1284
1285 /* Fill out the key data and copy the buffer */
1286 ServiceKeyName.Length = LocalDriverName.Length;
1287 ServiceKeyName.MaximumLength = LocalDriverName.MaximumLength;
1288 RtlCopyMemory(ServiceKeyName.Buffer,
1289 LocalDriverName.Buffer,
1290 LocalDriverName.Length);
1291
1292 /* Null-terminate it and set it */
1293 ServiceKeyName.Buffer[ServiceKeyName.Length / sizeof(WCHAR)] = UNICODE_NULL;
1294 DriverObject->DriverExtension->ServiceKeyName = ServiceKeyName;
1295
1296 /* Also store it in the Driver Object. This is a bit of a hack. */
1297 RtlCopyMemory(&DriverObject->DriverName,
1298 &ServiceKeyName,
1299 sizeof(UNICODE_STRING));
1300
1301 /* Add the Object and get its handle */
1302 Status = ObInsertObject(DriverObject,
1303 NULL,
1304 FILE_READ_DATA,
1305 0,
1306 NULL,
1307 &hDriver);
1308
1309 /* Eliminate small possibility when this function is called more than
1310 once in a row, and KeTickCount doesn't get enough time to change */
1311 if (!DriverName && (Status == STATUS_OBJECT_NAME_COLLISION) && (RetryCount < 100))
1312 {
1313 RetryCount++;
1314 goto try_again;
1315 }
1316
1317 if (!NT_SUCCESS(Status)) return Status;
1318
1319 /* Now reference it */
1320 Status = ObReferenceObjectByHandle(hDriver,
1321 0,
1322 IoDriverObjectType,
1323 KernelMode,
1324 (PVOID*)&DriverObject,
1325 NULL);
1326 if (!NT_SUCCESS(Status))
1327 {
1328 /* Fail */
1329 ObMakeTemporaryObject(DriverObject);
1330 ObDereferenceObject(DriverObject);
1331 return Status;
1332 }
1333
1334 /* Close the extra handle */
1335 ZwClose(hDriver);
1336
1337 DriverObject->HardwareDatabase = &IopHardwareDatabaseKey;
1338 DriverObject->DriverStart = DllBase;
1339 DriverObject->DriverSize = SizeOfImage;
1340
1341 /* Finally, call its init function */
1342 DPRINT("RegistryKey: %wZ\n", RegistryPath);
1343 DPRINT("Calling driver entrypoint at %p\n", InitializationFunction);
1344 Status = (*InitializationFunction)(DriverObject, RegistryPath);
1345 if (!NT_SUCCESS(Status))
1346 {
1347 /* If it didn't work, then kill the object */
1348 DPRINT1("'%wZ' initialization failed, status (0x%08lx)\n", DriverName, Status);
1349 ObMakeTemporaryObject(DriverObject);
1350 ObDereferenceObject(DriverObject);
1351 }
1352 else
1353 {
1354 /* Returns to caller the object */
1355 *pDriverObject = DriverObject;
1356 }
1357
1358 /* Return the Status */
1359 return Status;
1360 }
1361
1362 /* PUBLIC FUNCTIONS ***********************************************************/
1363
1364 /*
1365 * @implemented
1366 */
1367 NTSTATUS
1368 NTAPI
1369 IoCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL,
1370 IN PDRIVER_INITIALIZE InitializationFunction)
1371 {
1372 PDRIVER_OBJECT DriverObject;
1373 return IopCreateDriver(DriverName, InitializationFunction, NULL, 0, 0, &DriverObject);
1374 }
1375
1376 /*
1377 * @implemented
1378 */
1379 VOID
1380 NTAPI
1381 IoDeleteDriver(IN PDRIVER_OBJECT DriverObject)
1382 {
1383 /* Simply dereference the Object */
1384 ObDereferenceObject(DriverObject);
1385 }
1386
1387 /*
1388 * @implemented
1389 */
1390 VOID
1391 NTAPI
1392 IoRegisterBootDriverReinitialization(IN PDRIVER_OBJECT DriverObject,
1393 IN PDRIVER_REINITIALIZE ReinitRoutine,
1394 IN PVOID Context)
1395 {
1396 PDRIVER_REINIT_ITEM ReinitItem;
1397
1398 /* Allocate the entry */
1399 ReinitItem = ExAllocatePoolWithTag(NonPagedPool,
1400 sizeof(DRIVER_REINIT_ITEM),
1401 TAG_REINIT);
1402 if (!ReinitItem) return;
1403
1404 /* Fill it out */
1405 ReinitItem->DriverObject = DriverObject;
1406 ReinitItem->ReinitRoutine = ReinitRoutine;
1407 ReinitItem->Context = Context;
1408
1409 /* Set the Driver Object flag and insert the entry into the list */
1410 DriverObject->Flags |= DRVO_BOOTREINIT_REGISTERED;
1411 ExInterlockedInsertTailList(&DriverBootReinitListHead,
1412 &ReinitItem->ItemEntry,
1413 &DriverBootReinitListLock);
1414 }
1415
1416 /*
1417 * @implemented
1418 */
1419 VOID
1420 NTAPI
1421 IoRegisterDriverReinitialization(IN PDRIVER_OBJECT DriverObject,
1422 IN PDRIVER_REINITIALIZE ReinitRoutine,
1423 IN PVOID Context)
1424 {
1425 PDRIVER_REINIT_ITEM ReinitItem;
1426
1427 /* Allocate the entry */
1428 ReinitItem = ExAllocatePoolWithTag(NonPagedPool,
1429 sizeof(DRIVER_REINIT_ITEM),
1430 TAG_REINIT);
1431 if (!ReinitItem) return;
1432
1433 /* Fill it out */
1434 ReinitItem->DriverObject = DriverObject;
1435 ReinitItem->ReinitRoutine = ReinitRoutine;
1436 ReinitItem->Context = Context;
1437
1438 /* Set the Driver Object flag and insert the entry into the list */
1439 DriverObject->Flags |= DRVO_REINIT_REGISTERED;
1440 ExInterlockedInsertTailList(&DriverReinitListHead,
1441 &ReinitItem->ItemEntry,
1442 &DriverReinitListLock);
1443 }
1444
1445 /*
1446 * @implemented
1447 */
1448 NTSTATUS
1449 NTAPI
1450 IoAllocateDriverObjectExtension(IN PDRIVER_OBJECT DriverObject,
1451 IN PVOID ClientIdentificationAddress,
1452 IN ULONG DriverObjectExtensionSize,
1453 OUT PVOID *DriverObjectExtension)
1454 {
1455 KIRQL OldIrql;
1456 PIO_CLIENT_EXTENSION DriverExtensions, NewDriverExtension;
1457 BOOLEAN Inserted = FALSE;
1458
1459 /* Assume failure */
1460 *DriverObjectExtension = NULL;
1461
1462 /* Allocate the extension */
1463 NewDriverExtension = ExAllocatePoolWithTag(NonPagedPool,
1464 sizeof(IO_CLIENT_EXTENSION) +
1465 DriverObjectExtensionSize,
1466 TAG_DRIVER_EXTENSION);
1467 if (!NewDriverExtension) return STATUS_INSUFFICIENT_RESOURCES;
1468
1469 /* Clear the extension for teh caller */
1470 RtlZeroMemory(NewDriverExtension,
1471 sizeof(IO_CLIENT_EXTENSION) + DriverObjectExtensionSize);
1472
1473 /* Acqure lock */
1474 OldIrql = KeRaiseIrqlToDpcLevel();
1475
1476 /* Fill out the extension */
1477 NewDriverExtension->ClientIdentificationAddress = ClientIdentificationAddress;
1478
1479 /* Loop the current extensions */
1480 DriverExtensions = IoGetDrvObjExtension(DriverObject)->
1481 ClientDriverExtension;
1482 while (DriverExtensions)
1483 {
1484 /* Check if the identifier matches */
1485 if (DriverExtensions->ClientIdentificationAddress ==
1486 ClientIdentificationAddress)
1487 {
1488 /* We have a collision, break out */
1489 break;
1490 }
1491
1492 /* Go to the next one */
1493 DriverExtensions = DriverExtensions->NextExtension;
1494 }
1495
1496 /* Check if we didn't collide */
1497 if (!DriverExtensions)
1498 {
1499 /* Link this one in */
1500 NewDriverExtension->NextExtension =
1501 IoGetDrvObjExtension(DriverObject)->ClientDriverExtension;
1502 IoGetDrvObjExtension(DriverObject)->ClientDriverExtension =
1503 NewDriverExtension;
1504 Inserted = TRUE;
1505 }
1506
1507 /* Release the lock */
1508 KeLowerIrql(OldIrql);
1509
1510 /* Check if insertion failed */
1511 if (!Inserted)
1512 {
1513 /* Free the entry and fail */
1514 ExFreePool(NewDriverExtension);
1515 return STATUS_OBJECT_NAME_COLLISION;
1516 }
1517
1518 /* Otherwise, return the pointer */
1519 *DriverObjectExtension = NewDriverExtension + 1;
1520 return STATUS_SUCCESS;
1521 }
1522
1523 /*
1524 * @implemented
1525 */
1526 PVOID
1527 NTAPI
1528 IoGetDriverObjectExtension(IN PDRIVER_OBJECT DriverObject,
1529 IN PVOID ClientIdentificationAddress)
1530 {
1531 KIRQL OldIrql;
1532 PIO_CLIENT_EXTENSION DriverExtensions;
1533
1534 /* Acquire lock */
1535 OldIrql = KeRaiseIrqlToDpcLevel();
1536
1537 /* Loop the list until we find the right one */
1538 DriverExtensions = IoGetDrvObjExtension(DriverObject)->ClientDriverExtension;
1539 while (DriverExtensions)
1540 {
1541 /* Check for a match */
1542 if (DriverExtensions->ClientIdentificationAddress ==
1543 ClientIdentificationAddress)
1544 {
1545 /* Break out */
1546 break;
1547 }
1548
1549 /* Keep looping */
1550 DriverExtensions = DriverExtensions->NextExtension;
1551 }
1552
1553 /* Release lock */
1554 KeLowerIrql(OldIrql);
1555
1556 /* Return nothing or the extension */
1557 if (!DriverExtensions) return NULL;
1558 return DriverExtensions + 1;
1559 }
1560
1561 VOID NTAPI
1562 IopLoadUnloadDriver(PLOAD_UNLOAD_PARAMS LoadParams)
1563 {
1564 RTL_QUERY_REGISTRY_TABLE QueryTable[3];
1565 UNICODE_STRING ImagePath;
1566 UNICODE_STRING ServiceName;
1567 NTSTATUS Status;
1568 ULONG Type;
1569 PDEVICE_NODE DeviceNode;
1570 PDRIVER_OBJECT DriverObject;
1571 PLDR_DATA_TABLE_ENTRY ModuleObject;
1572 PVOID BaseAddress;
1573 WCHAR *cur;
1574
1575 /* Check if it's an unload request */
1576 if (LoadParams->DriverObject)
1577 {
1578 (*LoadParams->DriverObject->DriverUnload)(LoadParams->DriverObject);
1579
1580 /* Return success and signal the event */
1581 LoadParams->Status = STATUS_SUCCESS;
1582 (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
1583 return;
1584 }
1585
1586 RtlInitUnicodeString(&ImagePath, NULL);
1587
1588 /*
1589 * Get the service name from the registry key name.
1590 */
1591 ASSERT(LoadParams->ServiceName->Length >= sizeof(WCHAR));
1592
1593 ServiceName = *LoadParams->ServiceName;
1594 cur = LoadParams->ServiceName->Buffer +
1595 (LoadParams->ServiceName->Length / sizeof(WCHAR)) - 1;
1596 while (LoadParams->ServiceName->Buffer != cur)
1597 {
1598 if(*cur == L'\\')
1599 {
1600 ServiceName.Buffer = cur + 1;
1601 ServiceName.Length = LoadParams->ServiceName->Length -
1602 (USHORT)((ULONG_PTR)ServiceName.Buffer -
1603 (ULONG_PTR)LoadParams->ServiceName->Buffer);
1604 break;
1605 }
1606 cur--;
1607 }
1608
1609 /*
1610 * Get service type.
1611 */
1612
1613 RtlZeroMemory(&QueryTable, sizeof(QueryTable));
1614
1615 RtlInitUnicodeString(&ImagePath, NULL);
1616
1617 QueryTable[0].Name = L"Type";
1618 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
1619 QueryTable[0].EntryContext = &Type;
1620
1621 QueryTable[1].Name = L"ImagePath";
1622 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
1623 QueryTable[1].EntryContext = &ImagePath;
1624
1625 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
1626 LoadParams->ServiceName->Buffer, QueryTable, NULL, NULL);
1627
1628 if (!NT_SUCCESS(Status))
1629 {
1630 DPRINT("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
1631 ExFreePool(ImagePath.Buffer);
1632 LoadParams->Status = Status;
1633 (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
1634 return;
1635 }
1636
1637 /*
1638 * Normalize the image path for all later processing.
1639 */
1640
1641 Status = IopNormalizeImagePath(&ImagePath, &ServiceName);
1642
1643 if (!NT_SUCCESS(Status))
1644 {
1645 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status);
1646 LoadParams->Status = Status;
1647 (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
1648 return;
1649 }
1650
1651 DPRINT("FullImagePath: '%wZ'\n", &ImagePath);
1652 DPRINT("Type: %lx\n", Type);
1653
1654 /*
1655 * Create device node
1656 */
1657
1658 /* Use IopRootDeviceNode for now */
1659 Status = IopCreateDeviceNode(IopRootDeviceNode, NULL, &ServiceName, &DeviceNode);
1660
1661 if (!NT_SUCCESS(Status))
1662 {
1663 DPRINT("IopCreateDeviceNode() failed (Status %lx)\n", Status);
1664 LoadParams->Status = Status;
1665 (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
1666 return;
1667 }
1668
1669 /* Get existing DriverObject pointer (in case the driver has
1670 already been loaded and initialized) */
1671 Status = IopGetDriverObject(
1672 &DriverObject,
1673 &ServiceName,
1674 (Type == 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
1675 Type == 8 /* SERVICE_RECOGNIZER_DRIVER */));
1676
1677 if (!NT_SUCCESS(Status))
1678 {
1679 /*
1680 * Load the driver module
1681 */
1682
1683 Status = MmLoadSystemImage(&ImagePath, NULL, NULL, 0, (PVOID)&ModuleObject, &BaseAddress);
1684 if (!NT_SUCCESS(Status) && Status != STATUS_IMAGE_ALREADY_LOADED)
1685 {
1686 DPRINT("MmLoadSystemImage() failed (Status %lx)\n", Status);
1687 IopFreeDeviceNode(DeviceNode);
1688 LoadParams->Status = Status;
1689 (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
1690 return;
1691 }
1692
1693 /*
1694 * Set a service name for the device node
1695 */
1696
1697 RtlCreateUnicodeString(&DeviceNode->ServiceName, ServiceName.Buffer);
1698
1699 /*
1700 * Initialize the driver module if it's loaded for the first time
1701 */
1702 if (Status != STATUS_IMAGE_ALREADY_LOADED)
1703 {
1704 Status = IopInitializeDriverModule(
1705 DeviceNode,
1706 ModuleObject,
1707 &DeviceNode->ServiceName,
1708 (Type == 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
1709 Type == 8 /* SERVICE_RECOGNIZER_DRIVER */),
1710 &DriverObject);
1711
1712 if (!NT_SUCCESS(Status))
1713 {
1714 DPRINT("IopInitializeDriver() failed (Status %lx)\n", Status);
1715 MmUnloadSystemImage(ModuleObject);
1716 IopFreeDeviceNode(DeviceNode);
1717 LoadParams->Status = Status;
1718 (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
1719 return;
1720 }
1721 }
1722
1723 /* Store its DriverSection, so that it could be unloaded */
1724 DriverObject->DriverSection = ModuleObject;
1725 }
1726
1727 IopInitializeDevice(DeviceNode, DriverObject);
1728 LoadParams->Status = IopStartDevice(DeviceNode);
1729 (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
1730 }
1731
1732 /*
1733 * NtLoadDriver
1734 *
1735 * Loads a device driver.
1736 *
1737 * Parameters
1738 * DriverServiceName
1739 * Name of the service to load (registry key).
1740 *
1741 * Return Value
1742 * Status
1743 *
1744 * Status
1745 * implemented
1746 */
1747 NTSTATUS NTAPI
1748 NtLoadDriver(IN PUNICODE_STRING DriverServiceName)
1749 {
1750 UNICODE_STRING CapturedDriverServiceName = { 0, 0, NULL };
1751 KPROCESSOR_MODE PreviousMode;
1752 LOAD_UNLOAD_PARAMS LoadParams;
1753 NTSTATUS Status;
1754
1755 PAGED_CODE();
1756
1757 PreviousMode = KeGetPreviousMode();
1758
1759 /*
1760 * Check security privileges
1761 */
1762
1763 /* FIXME: Uncomment when privileges will be correctly implemented. */
1764 #if 0
1765 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, PreviousMode))
1766 {
1767 DPRINT("Privilege not held\n");
1768 return STATUS_PRIVILEGE_NOT_HELD;
1769 }
1770 #endif
1771
1772 Status = ProbeAndCaptureUnicodeString(&CapturedDriverServiceName,
1773 PreviousMode,
1774 DriverServiceName);
1775 if (!NT_SUCCESS(Status))
1776 {
1777 return Status;
1778 }
1779
1780 DPRINT("NtLoadDriver('%wZ')\n", &CapturedDriverServiceName);
1781
1782 LoadParams.ServiceName = &CapturedDriverServiceName;
1783 LoadParams.DriverObject = NULL;
1784 KeInitializeEvent(&LoadParams.Event, NotificationEvent, FALSE);
1785
1786 /* Call the load/unload routine, depending on current process */
1787 if (PsGetCurrentProcess() == PsInitialSystemProcess)
1788 {
1789 /* Just call right away */
1790 IopLoadUnloadDriver(&LoadParams);
1791 }
1792 else
1793 {
1794 /* Load/Unload must be called from system process */
1795 ExInitializeWorkItem(&LoadParams.WorkItem,
1796 (PWORKER_THREAD_ROUTINE)IopLoadUnloadDriver,
1797 (PVOID)&LoadParams);
1798
1799 /* Queue it */
1800 ExQueueWorkItem(&LoadParams.WorkItem, DelayedWorkQueue);
1801
1802 /* And wait when it completes */
1803 KeWaitForSingleObject(&LoadParams.Event, UserRequest, KernelMode,
1804 FALSE, NULL);
1805 }
1806
1807 ReleaseCapturedUnicodeString(&CapturedDriverServiceName,
1808 PreviousMode);
1809
1810 return LoadParams.Status;
1811 }
1812
1813 /*
1814 * NtUnloadDriver
1815 *
1816 * Unloads a legacy device driver.
1817 *
1818 * Parameters
1819 * DriverServiceName
1820 * Name of the service to unload (registry key).
1821 *
1822 * Return Value
1823 * Status
1824 *
1825 * Status
1826 * implemented
1827 */
1828
1829 NTSTATUS NTAPI
1830 NtUnloadDriver(IN PUNICODE_STRING DriverServiceName)
1831 {
1832 return IopUnloadDriver(DriverServiceName, FALSE);
1833 }
1834
1835 /* EOF */