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