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