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