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