- Remove KD APIs from stub HAL, they've been in kdcom for a while (merge from kd...
[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 /*
878 * Strip the file extension from ServiceName
879 */
880 FileExtension = wcsrchr(DeviceNode->ServiceName.Buffer, '.');
881 if (FileExtension != NULL)
882 {
883 DeviceNode->ServiceName.Length -= wcslen(FileExtension) * sizeof(WCHAR);
884 FileExtension[0] = 0;
885 }
886
887 /*
888 * Initialize the driver
889 */
890 Status = IopInitializeDriverModule(DeviceNode, LdrEntry,
891 &DeviceNode->ServiceName, FALSE, &DriverObject);
892
893 if (!NT_SUCCESS(Status))
894 {
895 IopFreeDeviceNode(DeviceNode);
896 CPRINT("Driver '%wZ' load failed, status (%x)\n", ModuleName, Status);
897 return Status;
898 }
899
900 Status = IopInitializeDevice(DeviceNode, DriverObject);
901 if (NT_SUCCESS(Status))
902 {
903 Status = IopStartDevice(DeviceNode);
904 }
905
906 return Status;
907 }
908
909 /*
910 * IopInitializeBootDrivers
911 *
912 * Initialize boot drivers and free memory for boot files.
913 *
914 * Parameters
915 * None
916 *
917 * Return Value
918 * None
919 */
920 VOID
921 FASTCALL
922 IopInitializeBootDrivers(VOID)
923 {
924 PLIST_ENTRY ListHead, NextEntry;
925 PLDR_DATA_TABLE_ENTRY LdrEntry;
926 PDEVICE_NODE DeviceNode;
927 PDRIVER_OBJECT DriverObject;
928 LDR_DATA_TABLE_ENTRY ModuleObject;
929 NTSTATUS Status;
930
931 /* Use IopRootDeviceNode for now */
932 Status = IopCreateDeviceNode(IopRootDeviceNode, NULL, &DeviceNode);
933 if (!NT_SUCCESS(Status)) return;
934
935 /* Setup the module object for the RAW FS Driver */
936 ModuleObject.DllBase = NULL;
937 ModuleObject.SizeOfImage = 0;
938 ModuleObject.EntryPoint = RawFsDriverEntry;
939
940 /* Initialize it */
941 Status = IopInitializeDriverModule(DeviceNode,
942 &ModuleObject,
943 &DeviceNode->ServiceName,
944 TRUE,
945 &DriverObject);
946 if (!NT_SUCCESS(Status))
947 {
948 /* Fail */
949 IopFreeDeviceNode(DeviceNode);
950 return;
951 }
952
953 /* Now initialize the associated device */
954 Status = IopInitializeDevice(DeviceNode, DriverObject);
955 if (!NT_SUCCESS(Status))
956 {
957 /* Fail */
958 IopFreeDeviceNode(DeviceNode);
959 return;
960 }
961
962 /* Start it up */
963 Status = IopStartDevice(DeviceNode);
964 if (!NT_SUCCESS(Status))
965 {
966 /* Fail */
967 IopFreeDeviceNode(DeviceNode);
968 return;
969 }
970
971 /* Loop the boot modules */
972 ListHead = &KeLoaderBlock->LoadOrderListHead;
973 NextEntry = ListHead->Flink;
974 while (ListHead != NextEntry)
975 {
976 /* Get the entry */
977 LdrEntry = CONTAINING_RECORD(NextEntry,
978 LDR_DATA_TABLE_ENTRY,
979 InLoadOrderLinks);
980
981 /*
982 * HACK: Make sure we're loading a driver
983 * (we should be using BootDriverListHead!)
984 */
985 if (wcsstr(LdrEntry->BaseDllName.Buffer, L".sys"))
986 {
987 /* Make sure we didn't load this driver already */
988 if (!(LdrEntry->Flags & LDRP_ENTRY_INSERTED))
989 {
990 /* Initialize it */
991 IopInitializeBuiltinDriver(LdrEntry);
992 }
993 }
994
995 /* Go to the next driver */
996 NextEntry = NextEntry->Flink;
997 }
998
999 /* In old ROS, the loader list became empty after this point. Simulate. */
1000 InitializeListHead(&KeLoaderBlock->LoadOrderListHead);
1001 }
1002
1003 /*
1004 * IopUnloadDriver
1005 *
1006 * Unloads a device driver.
1007 *
1008 * Parameters
1009 * DriverServiceName
1010 * Name of the service to unload (registry key).
1011 *
1012 * UnloadPnpDrivers
1013 * Whether to unload Plug & Plug or only legacy drivers. If this
1014 * parameter is set to FALSE, the routine will unload only legacy
1015 * drivers.
1016 *
1017 * Return Value
1018 * Status
1019 *
1020 * To do
1021 * Guard the whole function by SEH.
1022 */
1023
1024 NTSTATUS STDCALL
1025 IopUnloadDriver(PUNICODE_STRING DriverServiceName, BOOLEAN UnloadPnpDrivers)
1026 {
1027 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
1028 UNICODE_STRING ImagePath;
1029 UNICODE_STRING ServiceName;
1030 UNICODE_STRING ObjectName;
1031 PDRIVER_OBJECT DriverObject;
1032 NTSTATUS Status;
1033 LPWSTR Start;
1034
1035 DPRINT("IopUnloadDriver('%wZ', %d)\n", DriverServiceName, UnloadPnpDrivers);
1036
1037 PAGED_CODE();
1038
1039 /*
1040 * Get the service name from the registry key name
1041 */
1042
1043 Start = wcsrchr(DriverServiceName->Buffer, L'\\');
1044 if (Start == NULL)
1045 Start = DriverServiceName->Buffer;
1046 else
1047 Start++;
1048
1049 RtlInitUnicodeString(&ServiceName, Start);
1050
1051 /*
1052 * Construct the driver object name
1053 */
1054
1055 ObjectName.Length = (wcslen(Start) + 8) * sizeof(WCHAR);
1056 ObjectName.MaximumLength = ObjectName.Length + sizeof(WCHAR);
1057 ObjectName.Buffer = ExAllocatePool(PagedPool, ObjectName.MaximumLength);
1058 wcscpy(ObjectName.Buffer, L"\\Driver\\");
1059 memcpy(ObjectName.Buffer + 8, Start, (ObjectName.Length - 8) * sizeof(WCHAR));
1060 ObjectName.Buffer[ObjectName.Length/sizeof(WCHAR)] = 0;
1061
1062 /*
1063 * Find the driver object
1064 */
1065
1066 Status = ObReferenceObjectByName(&ObjectName, 0, 0, 0, IoDriverObjectType,
1067 KernelMode, 0, (PVOID*)&DriverObject);
1068
1069 if (!NT_SUCCESS(Status))
1070 {
1071 DPRINT("Can't locate driver object for %wZ\n", ObjectName);
1072 return Status;
1073 }
1074
1075 /*
1076 * Free the buffer for driver object name
1077 */
1078
1079 ExFreePool(ObjectName.Buffer);
1080
1081 /*
1082 * Get path of service...
1083 */
1084
1085 RtlZeroMemory(QueryTable, sizeof(QueryTable));
1086
1087 RtlInitUnicodeString(&ImagePath, NULL);
1088
1089 QueryTable[0].Name = L"ImagePath";
1090 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
1091 QueryTable[0].EntryContext = &ImagePath;
1092
1093 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
1094 DriverServiceName->Buffer, QueryTable, NULL, NULL);
1095
1096 if (!NT_SUCCESS(Status))
1097 {
1098 DPRINT("RtlQueryRegistryValues() failed (Status %x)\n", Status);
1099 return Status;
1100 }
1101
1102 /*
1103 * Normalize the image path for all later processing.
1104 */
1105
1106 Status = IopNormalizeImagePath(&ImagePath, &ServiceName);
1107
1108 if (!NT_SUCCESS(Status))
1109 {
1110 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status);
1111 return Status;
1112 }
1113
1114 /*
1115 * Free the service path
1116 */
1117
1118 ExFreePool(ImagePath.Buffer);
1119
1120 /*
1121 * Unload the module and release the references to the device object
1122 */
1123
1124 if (DriverObject->DriverUnload)
1125 (*DriverObject->DriverUnload)(DriverObject);
1126 ObDereferenceObject(DriverObject);
1127 ObDereferenceObject(DriverObject);
1128 MmUnloadSystemImage(DriverObject->DriverSection);
1129
1130 return STATUS_SUCCESS;
1131 }
1132
1133 VOID
1134 NTAPI
1135 IopReinitializeDrivers(VOID)
1136 {
1137 PDRIVER_REINIT_ITEM ReinitItem;
1138 PLIST_ENTRY Entry;
1139
1140 /* Get the first entry and start looping */
1141 Entry = ExInterlockedRemoveHeadList(&DriverReinitListHead,
1142 &DriverReinitListLock);
1143 while (Entry)
1144 {
1145 /* Get the item*/
1146 ReinitItem = CONTAINING_RECORD(Entry, DRIVER_REINIT_ITEM, ItemEntry);
1147
1148 /* Increment reinitialization counter */
1149 ReinitItem->DriverObject->DriverExtension->Count++;
1150
1151 /* Remove the device object flag */
1152 ReinitItem->DriverObject->Flags &= ~DRVO_REINIT_REGISTERED;
1153
1154 /* Call the routine */
1155 ReinitItem->ReinitRoutine(ReinitItem->DriverObject,
1156 ReinitItem->Context,
1157 ReinitItem->DriverObject->
1158 DriverExtension->Count);
1159
1160 /* Free the entry */
1161 ExFreePool(Entry);
1162
1163 /* Move to the next one */
1164 Entry = ExInterlockedRemoveHeadList(&DriverReinitListHead,
1165 &DriverReinitListLock);
1166 }
1167 }
1168
1169 VOID
1170 NTAPI
1171 IopReinitializeBootDrivers(VOID)
1172 {
1173 PDRIVER_REINIT_ITEM ReinitItem;
1174 PLIST_ENTRY Entry;
1175
1176 /* Get the first entry and start looping */
1177 Entry = ExInterlockedRemoveHeadList(&DriverBootReinitListHead,
1178 &DriverBootReinitListLock);
1179 while (Entry)
1180 {
1181 /* Get the item*/
1182 ReinitItem = CONTAINING_RECORD(Entry, DRIVER_REINIT_ITEM, ItemEntry);
1183
1184 /* Increment reinitialization counter */
1185 ReinitItem->DriverObject->DriverExtension->Count++;
1186
1187 /* Remove the device object flag */
1188 ReinitItem->DriverObject->Flags &= ~DRVO_BOOTREINIT_REGISTERED;
1189
1190 /* Call the routine */
1191 ReinitItem->ReinitRoutine(ReinitItem->DriverObject,
1192 ReinitItem->Context,
1193 ReinitItem->DriverObject->
1194 DriverExtension->Count);
1195
1196 /* Free the entry */
1197 ExFreePool(Entry);
1198
1199 /* Move to the next one */
1200 Entry = ExInterlockedRemoveHeadList(&DriverBootReinitListHead,
1201 &DriverBootReinitListLock);
1202 }
1203 }
1204
1205 /* PUBLIC FUNCTIONS ***********************************************************/
1206
1207 /*
1208 * @implemented
1209 */
1210 NTSTATUS
1211 NTAPI
1212 IoCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL,
1213 IN PDRIVER_INITIALIZE InitializationFunction)
1214 {
1215 WCHAR NameBuffer[100];
1216 USHORT NameLength;
1217 UNICODE_STRING LocalDriverName;
1218 NTSTATUS Status;
1219 OBJECT_ATTRIBUTES ObjectAttributes;
1220 ULONG ObjectSize;
1221 PDRIVER_OBJECT DriverObject;
1222 UNICODE_STRING ServiceKeyName;
1223 HANDLE hDriver;
1224 ULONG i;
1225
1226 /* First, create a unique name for the driver if we don't have one */
1227 if (!DriverName)
1228 {
1229 /* Create a random name and set up the string*/
1230 NameLength = swprintf(NameBuffer, L"\\Driver\\%08u", KeTickCount);
1231 LocalDriverName.Length = NameLength * sizeof(WCHAR);
1232 LocalDriverName.MaximumLength = LocalDriverName.Length + sizeof(UNICODE_NULL);
1233 LocalDriverName.Buffer = NameBuffer;
1234 }
1235 else
1236 {
1237 /* So we can avoid another code path, use a local var */
1238 LocalDriverName = *DriverName;
1239 }
1240
1241 /* Initialize the Attributes */
1242 ObjectSize = sizeof(DRIVER_OBJECT) + sizeof(EXTENDED_DRIVER_EXTENSION);
1243 InitializeObjectAttributes(&ObjectAttributes,
1244 &LocalDriverName,
1245 OBJ_PERMANENT | OBJ_CASE_INSENSITIVE,
1246 NULL,
1247 NULL);
1248
1249 /* Create the Object */
1250 Status = ObCreateObject(KernelMode,
1251 IoDriverObjectType,
1252 &ObjectAttributes,
1253 KernelMode,
1254 NULL,
1255 ObjectSize,
1256 0,
1257 0,
1258 (PVOID*)&DriverObject);
1259 if (!NT_SUCCESS(Status)) return Status;
1260
1261 /* Set up the Object */
1262 RtlZeroMemory(DriverObject, ObjectSize);
1263 DriverObject->Type = IO_TYPE_DRIVER;
1264 DriverObject->Size = sizeof(DRIVER_OBJECT);
1265 DriverObject->Flags = DRVO_BUILTIN_DRIVER;
1266 DriverObject->DriverExtension = (PDRIVER_EXTENSION)(DriverObject + 1);
1267 DriverObject->DriverExtension->DriverObject = DriverObject;
1268 DriverObject->DriverInit = InitializationFunction;
1269
1270 /* Loop all Major Functions */
1271 for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
1272 {
1273 /* Invalidate each function */
1274 DriverObject->MajorFunction[i] = IopInvalidDeviceRequest;
1275 }
1276
1277 /* Set up the service key name buffer */
1278 ServiceKeyName.Buffer = ExAllocatePoolWithTag(PagedPool,
1279 LocalDriverName.Length +
1280 sizeof(WCHAR),
1281 TAG_IO);
1282 if (!ServiceKeyName.Buffer)
1283 {
1284 /* Fail */
1285 ObMakeTemporaryObject(DriverObject);
1286 ObDereferenceObject(DriverObject);
1287 return STATUS_INSUFFICIENT_RESOURCES;
1288 }
1289
1290 /* Fill out the key data and copy the buffer */
1291 ServiceKeyName.Length = LocalDriverName.Length;
1292 ServiceKeyName.MaximumLength = LocalDriverName.MaximumLength;
1293 RtlCopyMemory(ServiceKeyName.Buffer,
1294 LocalDriverName.Buffer,
1295 LocalDriverName.Length);
1296
1297 /* Null-terminate it and set it */
1298 ServiceKeyName.Buffer[ServiceKeyName.Length / sizeof(WCHAR)] = UNICODE_NULL;
1299 DriverObject->DriverExtension->ServiceKeyName = ServiceKeyName;
1300
1301 /* Also store it in the Driver Object. This is a bit of a hack. */
1302 RtlCopyMemory(&DriverObject->DriverName,
1303 &ServiceKeyName,
1304 sizeof(UNICODE_STRING));
1305
1306 /* Add the Object and get its handle */
1307 Status = ObInsertObject(DriverObject,
1308 NULL,
1309 FILE_READ_DATA,
1310 0,
1311 NULL,
1312 &hDriver);
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 /* Finally, call its init function */
1334 Status = (*InitializationFunction)(DriverObject, NULL);
1335 if (!NT_SUCCESS(Status))
1336 {
1337 /* If it didn't work, then kill the object */
1338 ObMakeTemporaryObject(DriverObject);
1339 ObDereferenceObject(DriverObject);
1340 }
1341
1342 /* Return the Status */
1343 return Status;
1344 }
1345
1346 /*
1347 * @implemented
1348 */
1349 VOID
1350 NTAPI
1351 IoDeleteDriver(IN PDRIVER_OBJECT DriverObject)
1352 {
1353 /* Simply derefence the Object */
1354 ObDereferenceObject(DriverObject);
1355 }
1356
1357 /*
1358 * @implemented
1359 */
1360 VOID
1361 NTAPI
1362 IoRegisterBootDriverReinitialization(IN PDRIVER_OBJECT DriverObject,
1363 IN PDRIVER_REINITIALIZE ReinitRoutine,
1364 IN PVOID Context)
1365 {
1366 PDRIVER_REINIT_ITEM ReinitItem;
1367
1368 /* Allocate the entry */
1369 ReinitItem = ExAllocatePoolWithTag(NonPagedPool,
1370 sizeof(DRIVER_REINIT_ITEM),
1371 TAG_REINIT);
1372 if (!ReinitItem) return;
1373
1374 /* Fill it out */
1375 ReinitItem->DriverObject = DriverObject;
1376 ReinitItem->ReinitRoutine = ReinitRoutine;
1377 ReinitItem->Context = Context;
1378
1379 /* Set the Driver Object flag and insert the entry into the list */
1380 DriverObject->Flags |= DRVO_BOOTREINIT_REGISTERED;
1381 ExInterlockedInsertTailList(&DriverBootReinitListHead,
1382 &ReinitItem->ItemEntry,
1383 &DriverBootReinitListLock);
1384 }
1385
1386 /*
1387 * @implemented
1388 */
1389 VOID
1390 NTAPI
1391 IoRegisterDriverReinitialization(IN PDRIVER_OBJECT DriverObject,
1392 IN PDRIVER_REINITIALIZE ReinitRoutine,
1393 IN PVOID Context)
1394 {
1395 PDRIVER_REINIT_ITEM ReinitItem;
1396
1397 /* Allocate the entry */
1398 ReinitItem = ExAllocatePoolWithTag(NonPagedPool,
1399 sizeof(DRIVER_REINIT_ITEM),
1400 TAG_REINIT);
1401 if (!ReinitItem) return;
1402
1403 /* Fill it out */
1404 ReinitItem->DriverObject = DriverObject;
1405 ReinitItem->ReinitRoutine = ReinitRoutine;
1406 ReinitItem->Context = Context;
1407
1408 /* Set the Driver Object flag and insert the entry into the list */
1409 DriverObject->Flags |= DRVO_REINIT_REGISTERED;
1410 ExInterlockedInsertTailList(&DriverReinitListHead,
1411 &ReinitItem->ItemEntry,
1412 &DriverReinitListLock);
1413 }
1414
1415 /*
1416 * @implemented
1417 */
1418 NTSTATUS
1419 NTAPI
1420 IoAllocateDriverObjectExtension(IN PDRIVER_OBJECT DriverObject,
1421 IN PVOID ClientIdentificationAddress,
1422 IN ULONG DriverObjectExtensionSize,
1423 OUT PVOID *DriverObjectExtension)
1424 {
1425 KIRQL OldIrql;
1426 PIO_CLIENT_EXTENSION DriverExtensions, NewDriverExtension;
1427 BOOLEAN Inserted = FALSE;
1428
1429 /* Assume failure */
1430 *DriverObjectExtension = NULL;
1431
1432 /* Allocate the extension */
1433 NewDriverExtension = ExAllocatePoolWithTag(NonPagedPool,
1434 sizeof(IO_CLIENT_EXTENSION) +
1435 DriverObjectExtensionSize,
1436 TAG_DRIVER_EXTENSION);
1437 if (!NewDriverExtension) return STATUS_INSUFFICIENT_RESOURCES;
1438
1439 /* Clear the extension for teh caller */
1440 RtlZeroMemory(NewDriverExtension,
1441 sizeof(IO_CLIENT_EXTENSION) + DriverObjectExtensionSize);
1442
1443 /* Acqure lock */
1444 OldIrql = KeRaiseIrqlToDpcLevel();
1445
1446 /* Fill out the extension */
1447 NewDriverExtension->ClientIdentificationAddress = ClientIdentificationAddress;
1448
1449 /* Loop the current extensions */
1450 DriverExtensions = IoGetDrvObjExtension(DriverObject)->
1451 ClientDriverExtension;
1452 while (DriverExtensions)
1453 {
1454 /* Check if the identifier matches */
1455 if (DriverExtensions->ClientIdentificationAddress ==
1456 ClientIdentificationAddress)
1457 {
1458 /* We have a collision, break out */
1459 break;
1460 }
1461
1462 /* Go to the next one */
1463 DriverExtensions = DriverExtensions->NextExtension;
1464 }
1465
1466 /* Check if we didn't collide */
1467 if (!DriverExtensions)
1468 {
1469 /* Link this one in */
1470 NewDriverExtension->NextExtension =
1471 IoGetDrvObjExtension(DriverObject)->ClientDriverExtension;
1472 IoGetDrvObjExtension(DriverObject)->ClientDriverExtension =
1473 NewDriverExtension;
1474 Inserted = TRUE;
1475 }
1476
1477 /* Release the lock */
1478 KfLowerIrql(OldIrql);
1479
1480 /* Check if insertion failed */
1481 if (!Inserted)
1482 {
1483 /* Free the entry and fail */
1484 ExFreePool(NewDriverExtension);
1485 return STATUS_OBJECT_NAME_COLLISION;
1486 }
1487
1488 /* Otherwise, return the pointer */
1489 *DriverObjectExtension = NewDriverExtension + 1;
1490 return STATUS_SUCCESS;
1491 }
1492
1493 /*
1494 * @implemented
1495 */
1496 PVOID
1497 NTAPI
1498 IoGetDriverObjectExtension(IN PDRIVER_OBJECT DriverObject,
1499 IN PVOID ClientIdentificationAddress)
1500 {
1501 KIRQL OldIrql;
1502 PIO_CLIENT_EXTENSION DriverExtensions;
1503
1504 /* Acquire lock */
1505 OldIrql = KeRaiseIrqlToDpcLevel();
1506
1507 /* Loop the list until we find the right one */
1508 DriverExtensions = IoGetDrvObjExtension(DriverObject)->ClientDriverExtension;
1509 while (DriverExtensions)
1510 {
1511 /* Check for a match */
1512 if (DriverExtensions->ClientIdentificationAddress ==
1513 ClientIdentificationAddress)
1514 {
1515 /* Break out */
1516 break;
1517 }
1518
1519 /* Keep looping */
1520 DriverExtensions = DriverExtensions->NextExtension;
1521 }
1522
1523 /* Release lock */
1524 KfLowerIrql(OldIrql);
1525
1526 /* Return nothing or the extension */
1527 if (!DriverExtensions) return NULL;
1528 return DriverExtensions + 1;
1529 }
1530
1531 /*
1532 * NtLoadDriver
1533 *
1534 * Loads a device driver.
1535 *
1536 * Parameters
1537 * DriverServiceName
1538 * Name of the service to load (registry key).
1539 *
1540 * Return Value
1541 * Status
1542 *
1543 * Status
1544 * implemented
1545 */
1546 NTSTATUS STDCALL
1547 NtLoadDriver(IN PUNICODE_STRING DriverServiceName)
1548 {
1549 RTL_QUERY_REGISTRY_TABLE QueryTable[3];
1550 UNICODE_STRING ImagePath;
1551 UNICODE_STRING ServiceName;
1552 UNICODE_STRING CapturedDriverServiceName = {0};
1553 KPROCESSOR_MODE PreviousMode;
1554 NTSTATUS Status;
1555 ULONG Type;
1556 PDEVICE_NODE DeviceNode;
1557 PLDR_DATA_TABLE_ENTRY ModuleObject;
1558 PDRIVER_OBJECT DriverObject;
1559 WCHAR *cur;
1560
1561 PAGED_CODE();
1562
1563 PreviousMode = KeGetPreviousMode();
1564
1565 /*
1566 * Check security privileges
1567 */
1568
1569 /* FIXME: Uncomment when privileges will be correctly implemented. */
1570 #if 0
1571 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, PreviousMode))
1572 {
1573 DPRINT("Privilege not held\n");
1574 return STATUS_PRIVILEGE_NOT_HELD;
1575 }
1576 #endif
1577
1578 Status = ProbeAndCaptureUnicodeString(&CapturedDriverServiceName,
1579 PreviousMode,
1580 DriverServiceName);
1581 if (!NT_SUCCESS(Status))
1582 {
1583 return Status;
1584 }
1585
1586 DPRINT("NtLoadDriver('%wZ')\n", &CapturedDriverServiceName);
1587
1588 RtlInitUnicodeString(&ImagePath, NULL);
1589
1590 /*
1591 * Get the service name from the registry key name.
1592 */
1593 ASSERT(CapturedDriverServiceName.Length >= sizeof(WCHAR));
1594
1595 ServiceName = CapturedDriverServiceName;
1596 cur = CapturedDriverServiceName.Buffer + (CapturedDriverServiceName.Length / sizeof(WCHAR)) - 1;
1597 while (CapturedDriverServiceName.Buffer != cur)
1598 {
1599 if(*cur == L'\\')
1600 {
1601 ServiceName.Buffer = cur + 1;
1602 ServiceName.Length = CapturedDriverServiceName.Length -
1603 (USHORT)((ULONG_PTR)ServiceName.Buffer -
1604 (ULONG_PTR)CapturedDriverServiceName.Buffer);
1605 break;
1606 }
1607 cur--;
1608 }
1609
1610 /*
1611 * Get service type.
1612 */
1613
1614 RtlZeroMemory(&QueryTable, sizeof(QueryTable));
1615
1616 RtlInitUnicodeString(&ImagePath, NULL);
1617
1618 QueryTable[0].Name = L"Type";
1619 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
1620 QueryTable[0].EntryContext = &Type;
1621
1622 QueryTable[1].Name = L"ImagePath";
1623 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
1624 QueryTable[1].EntryContext = &ImagePath;
1625
1626 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
1627 CapturedDriverServiceName.Buffer, QueryTable, NULL, NULL);
1628
1629 if (!NT_SUCCESS(Status))
1630 {
1631 DPRINT("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
1632 ExFreePool(ImagePath.Buffer);
1633 goto ReleaseCapturedString;
1634 }
1635
1636 /*
1637 * Normalize the image path for all later processing.
1638 */
1639
1640 Status = IopNormalizeImagePath(&ImagePath, &ServiceName);
1641
1642 if (!NT_SUCCESS(Status))
1643 {
1644 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status);
1645 goto ReleaseCapturedString;
1646 }
1647
1648 DPRINT("FullImagePath: '%wZ'\n", &ImagePath);
1649 DPRINT("Type: %lx\n", Type);
1650
1651 /*
1652 * Create device node
1653 */
1654
1655 /* Use IopRootDeviceNode for now */
1656 Status = IopCreateDeviceNode(IopRootDeviceNode, NULL, &DeviceNode);
1657
1658 if (!NT_SUCCESS(Status))
1659 {
1660 DPRINT("IopCreateDeviceNode() failed (Status %lx)\n", Status);
1661 goto ReleaseCapturedString;
1662 }
1663
1664 /*
1665 * Load the driver module
1666 */
1667
1668 Status = MmLoadSystemImage(&ImagePath, NULL, NULL, 0, (PVOID)&ModuleObject, NULL);
1669 if (!NT_SUCCESS(Status))
1670 {
1671 DPRINT("MmLoadSystemImage() failed (Status %lx)\n", Status);
1672 IopFreeDeviceNode(DeviceNode);
1673 goto ReleaseCapturedString;
1674 }
1675
1676 /*
1677 * Set a service name for the device node
1678 */
1679
1680 RtlCreateUnicodeString(&DeviceNode->ServiceName, ServiceName.Buffer);
1681
1682 /*
1683 * Initialize the driver module
1684 */
1685
1686 Status = IopInitializeDriverModule(
1687 DeviceNode,
1688 ModuleObject,
1689 &DeviceNode->ServiceName,
1690 (Type == 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
1691 Type == 8 /* SERVICE_RECOGNIZER_DRIVER */),
1692 &DriverObject);
1693
1694 if (!NT_SUCCESS(Status))
1695 {
1696 DPRINT("IopInitializeDriver() failed (Status %lx)\n", Status);
1697 MmUnloadSystemImage(ModuleObject);
1698 IopFreeDeviceNode(DeviceNode);
1699 goto ReleaseCapturedString;
1700 }
1701
1702 IopInitializeDevice(DeviceNode, DriverObject);
1703 Status = IopStartDevice(DeviceNode);
1704
1705 ReleaseCapturedString:
1706 ReleaseCapturedUnicodeString(&CapturedDriverServiceName,
1707 PreviousMode);
1708
1709 return Status;
1710 }
1711
1712 /*
1713 * NtUnloadDriver
1714 *
1715 * Unloads a legacy device driver.
1716 *
1717 * Parameters
1718 * DriverServiceName
1719 * Name of the service to unload (registry key).
1720 *
1721 * Return Value
1722 * Status
1723 *
1724 * Status
1725 * implemented
1726 */
1727
1728 NTSTATUS STDCALL
1729 NtUnloadDriver(IN PUNICODE_STRING DriverServiceName)
1730 {
1731 return IopUnloadDriver(DriverServiceName, FALSE);
1732 }
1733
1734 /* EOF */