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