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