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