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