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