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