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