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