Fix driver loading. patch by tinus
[reactos.git] / reactos / ntoskrnl / io / driver.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/io/driver.c
6 * PURPOSE: Loading and unloading of drivers
7 *
8 * PROGRAMMERS: David Welch (welch@cwcom.net)
9 * Filip Navara (xnavara@volny.cz)
10 */
11
12 /* INCLUDES *******************************************************************/
13
14 #include <ntoskrnl.h>
15 #define NDEBUG
16 #include <internal/debug.h>
17
18 /* ke/main.c */
19 extern LOADER_PARAMETER_BLOCK EXPORTED KeLoaderBlock;
20 extern ULONG KeTickCount;
21
22 NTSTATUS
23 LdrProcessModule(PVOID ModuleLoadBase,
24 PUNICODE_STRING ModuleName,
25 PMODULE_OBJECT *ModuleObject);
26
27 typedef struct _SERVICE_GROUP
28 {
29 LIST_ENTRY GroupListEntry;
30 UNICODE_STRING GroupName;
31 BOOLEAN ServicesRunning;
32 ULONG TagCount;
33 PULONG TagArray;
34 } SERVICE_GROUP, *PSERVICE_GROUP;
35
36 typedef struct _SERVICE
37 {
38 LIST_ENTRY ServiceListEntry;
39 UNICODE_STRING ServiceName;
40 UNICODE_STRING RegistryPath;
41 UNICODE_STRING ServiceGroup;
42 UNICODE_STRING ImagePath;
43
44 ULONG Start;
45 ULONG Type;
46 ULONG ErrorControl;
47 ULONG Tag;
48
49 /* BOOLEAN ServiceRunning;*/ // needed ??
50 } SERVICE, *PSERVICE;
51
52 typedef struct _DRIVER_REINIT_ITEM
53 {
54 LIST_ENTRY ItemEntry;
55 PDRIVER_OBJECT DriverObject;
56 PDRIVER_REINITIALIZE ReinitRoutine;
57 PVOID Context;
58 } DRIVER_REINIT_ITEM, *PDRIVER_REINIT_ITEM;
59
60 /* GLOBALS ********************************************************************/
61
62 static LIST_ENTRY DriverReinitListHead;
63 static KSPIN_LOCK DriverReinitListLock;
64 static PLIST_ENTRY DriverReinitTailEntry;
65
66 static PLIST_ENTRY DriverBootReinitTailEntry;
67 static LIST_ENTRY DriverBootReinitListHead;
68 static KSPIN_LOCK DriverBootReinitListLock;
69
70 static LIST_ENTRY GroupListHead = {NULL, NULL};
71 static LIST_ENTRY ServiceListHead = {NULL, NULL};
72
73 static UNICODE_STRING IopHardwareDatabaseKey =
74 ROS_STRING_INITIALIZER(L"\\REGISTRY\\MACHINE\\HARDWARE\\DESCRIPTION\\SYSTEM");
75
76 POBJECT_TYPE EXPORTED IoDriverObjectType = NULL;
77
78 #define TAG_DRIVER TAG('D', 'R', 'V', 'R')
79 #define TAG_DRIVER_EXTENSION TAG('D', 'R', 'V', 'E')
80
81 /* DECLARATIONS ***************************************************************/
82
83 NTSTATUS STDCALL
84 IopCreateDriver(
85 PVOID ObjectBody,
86 PVOID Parent,
87 PWSTR RemainingPath,
88 POBJECT_ATTRIBUTES ObjectAttributes);
89
90 VOID STDCALL
91 IopDeleteDriver(PVOID ObjectBody);
92
93 /* PRIVATE FUNCTIONS **********************************************************/
94
95 VOID INIT_FUNCTION
96 IopInitDriverImplementation(VOID)
97 {
98 /* Register the process object type */
99 IoDriverObjectType = ExAllocatePool(NonPagedPool, sizeof(OBJECT_TYPE));
100 IoDriverObjectType->Tag = TAG('D', 'R', 'V', 'R');
101 IoDriverObjectType->TotalObjects = 0;
102 IoDriverObjectType->TotalHandles = 0;
103 IoDriverObjectType->PeakObjects = 0;
104 IoDriverObjectType->PeakHandles = 0;
105 IoDriverObjectType->PagedPoolCharge = 0;
106 IoDriverObjectType->NonpagedPoolCharge = sizeof(DRIVER_OBJECT);
107 IoDriverObjectType->Dump = NULL;
108 IoDriverObjectType->Open = NULL;
109 IoDriverObjectType->Close = NULL;
110 IoDriverObjectType->Delete = IopDeleteDriver;
111 IoDriverObjectType->Parse = NULL;
112 IoDriverObjectType->Security = NULL;
113 IoDriverObjectType->QueryName = NULL;
114 IoDriverObjectType->OkayToClose = NULL;
115 IoDriverObjectType->Create = IopCreateDriver;
116 IoDriverObjectType->DuplicationNotify = NULL;
117 RtlInitUnicodeString(&IoDriverObjectType->TypeName, L"Driver");
118
119 ObpCreateTypeObject(IoDriverObjectType);
120
121 InitializeListHead(&DriverReinitListHead);
122 KeInitializeSpinLock(&DriverReinitListLock);
123 DriverReinitTailEntry = NULL;
124
125 InitializeListHead(&DriverBootReinitListHead);
126 KeInitializeSpinLock(&DriverBootReinitListLock);
127 DriverBootReinitTailEntry = NULL;
128 }
129
130 NTSTATUS STDCALL
131 IopInvalidDeviceRequest(
132 PDEVICE_OBJECT DeviceObject,
133 PIRP Irp)
134 {
135 Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
136 Irp->IoStatus.Information = 0;
137 IoCompleteRequest(Irp, IO_NO_INCREMENT);
138 return STATUS_INVALID_DEVICE_REQUEST;
139 }
140
141 NTSTATUS STDCALL
142 IopCreateDriver(
143 PVOID ObjectBody,
144 PVOID Parent,
145 PWSTR RemainingPath,
146 POBJECT_ATTRIBUTES ObjectAttributes)
147 {
148 PDRIVER_OBJECT Object = ObjectBody;
149 ULONG i;
150
151 DPRINT("IopCreateDriver(ObjectBody %x, Parent %x, RemainingPath %S)\n",
152 ObjectBody, Parent, RemainingPath);
153
154 if (RemainingPath != NULL && wcschr(RemainingPath + 1, '\\') != NULL)
155 return STATUS_UNSUCCESSFUL;
156
157 /* Create driver extension */
158 Object->DriverExtension = (PDRIVER_EXTENSION)
159 ExAllocatePoolWithTag(
160 NonPagedPool,
161 sizeof(DRIVER_EXTENSION),
162 TAG_DRIVER_EXTENSION);
163
164 if (Object->DriverExtension == NULL)
165 {
166 return STATUS_NO_MEMORY;
167 }
168
169 RtlZeroMemory(Object->DriverExtension, sizeof(DRIVER_EXTENSION));
170
171 Object->Type = IO_TYPE_DRIVER;
172
173 for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
174 Object->MajorFunction[i] = IopInvalidDeviceRequest;
175
176 Object->HardwareDatabase = &IopHardwareDatabaseKey;
177
178 return STATUS_SUCCESS;
179 }
180
181 VOID STDCALL
182 IopDeleteDriver(PVOID ObjectBody)
183 {
184 PDRIVER_OBJECT Object = ObjectBody;
185 KIRQL OldIrql;
186 PPRIVATE_DRIVER_EXTENSIONS DriverExtension, NextDriverExtension;
187
188 DPRINT("IopDeleteDriver(ObjectBody %x)\n", ObjectBody);
189
190 ExFreePool(Object->DriverExtension);
191 ExFreePool(Object->DriverName.Buffer);
192
193 OldIrql = KeRaiseIrqlToDpcLevel();
194
195 for (DriverExtension = Object->DriverSection;
196 DriverExtension != NULL;
197 DriverExtension = NextDriverExtension)
198 {
199 NextDriverExtension = DriverExtension->Link;
200 ExFreePoolWithTag(DriverExtension, TAG_DRIVER_EXTENSION);
201 }
202
203 KfLowerIrql(OldIrql);
204 }
205
206 NTSTATUS FASTCALL
207 IopCreateDriverObject(
208 PDRIVER_OBJECT *DriverObject,
209 PUNICODE_STRING ServiceName,
210 ULONG CreateAttributes,
211 BOOLEAN FileSystem,
212 PVOID DriverImageStart,
213 ULONG DriverImageSize)
214 {
215 PDRIVER_OBJECT Object;
216 WCHAR NameBuffer[MAX_PATH];
217 UNICODE_STRING DriverName;
218 OBJECT_ATTRIBUTES ObjectAttributes;
219 NTSTATUS Status;
220 PWSTR Buffer = NULL;
221
222 DPRINT("IopCreateDriverObject(%p '%wZ' %x %p %x)\n",
223 DriverObject, ServiceName, FileSystem, DriverImageStart, DriverImageSize);
224
225 *DriverObject = NULL;
226
227 /* Create ModuleName string */
228 if (ServiceName != NULL && ServiceName->Buffer != NULL)
229 {
230 if (FileSystem == TRUE)
231 wcscpy(NameBuffer, FILESYSTEM_ROOT_NAME);
232 else
233 wcscpy(NameBuffer, DRIVER_ROOT_NAME);
234 wcscat(NameBuffer, ServiceName->Buffer);
235
236 RtlInitUnicodeString(&DriverName, NameBuffer);
237 DPRINT("Driver name: '%wZ'\n", &DriverName);
238
239 Buffer = (PWSTR)ExAllocatePool(NonPagedPool, DriverName.Length);
240 /* If we don't success, it is not a problem. Our driver
241 * object will not have associated driver name... */
242 }
243 else
244 {
245 RtlInitUnicodeString(&DriverName, NULL);
246 }
247
248 /* Initialize ObjectAttributes for driver object */
249 InitializeObjectAttributes(
250 &ObjectAttributes,
251 &DriverName,
252 CreateAttributes | OBJ_PERMANENT,
253 NULL,
254 NULL);
255
256 /* Create driver object */
257 Status = ObCreateObject(
258 KernelMode,
259 IoDriverObjectType,
260 &ObjectAttributes,
261 KernelMode,
262 NULL,
263 sizeof(DRIVER_OBJECT),
264 0,
265 0,
266 (PVOID*)&Object);
267
268 if (!NT_SUCCESS(Status))
269 {
270 return Status;
271 }
272
273 Object->DriverStart = DriverImageStart;
274 Object->DriverSize = DriverImageSize;
275 if (Buffer)
276 {
277 if (!Object->DriverName.Buffer)
278 {
279 Object->DriverName.Buffer = Buffer;
280 Object->DriverName.Length = Object->DriverName.MaximumLength = DriverName.Length;
281 RtlCopyMemory(Object->DriverName.Buffer, DriverName.Buffer, DriverName.Length);
282 }
283 else
284 ExFreePool(Buffer);
285 }
286
287 *DriverObject = Object;
288
289 return STATUS_SUCCESS;
290 }
291
292 /*
293 * IopDisplayLoadingMessage
294 *
295 * Display 'Loading XXX...' message.
296 */
297
298 VOID FASTCALL
299 IopDisplayLoadingMessage(PWCHAR ServiceName)
300 {
301 CHAR TextBuffer[256];
302 sprintf(TextBuffer, "Loading %S...\n", ServiceName);
303 HalDisplayString(TextBuffer);
304 }
305
306 /*
307 * IopNormalizeImagePath
308 *
309 * Normalize an image path to contain complete path.
310 *
311 * Parameters
312 * ImagePath
313 * The input path and on exit the result path. ImagePath.Buffer
314 * must be allocated by ExAllocatePool on input. Caller is responsible
315 * for freeing the buffer when it's no longer needed.
316 *
317 * ServiceName
318 * Name of the service that ImagePath belongs to.
319 *
320 * Return Value
321 * Status
322 *
323 * Remarks
324 * The input image path isn't freed on error.
325 */
326
327 NTSTATUS FASTCALL
328 IopNormalizeImagePath(
329 IN OUT PUNICODE_STRING ImagePath,
330 IN PUNICODE_STRING ServiceName)
331 {
332 UNICODE_STRING InputImagePath;
333
334 RtlCopyMemory(
335 &InputImagePath,
336 ImagePath,
337 sizeof(UNICODE_STRING));
338
339 if (InputImagePath.Length == 0)
340 {
341 ImagePath->Length = (33 * sizeof(WCHAR)) + ServiceName->Length;
342 ImagePath->MaximumLength = ImagePath->Length + sizeof(UNICODE_NULL);
343 ImagePath->Buffer = ExAllocatePool(NonPagedPool, ImagePath->MaximumLength);
344 if (ImagePath->Buffer == NULL)
345 return STATUS_NO_MEMORY;
346
347 wcscpy(ImagePath->Buffer, L"\\SystemRoot\\system32\\drivers\\");
348 wcscat(ImagePath->Buffer, ServiceName->Buffer);
349 wcscat(ImagePath->Buffer, L".sys");
350 } else
351 if (InputImagePath.Buffer[0] != L'\\')
352 {
353 ImagePath->Length = (12 * sizeof(WCHAR)) + InputImagePath.Length;
354 ImagePath->MaximumLength = ImagePath->Length + sizeof(UNICODE_NULL);
355 ImagePath->Buffer = ExAllocatePool(NonPagedPool, ImagePath->MaximumLength);
356 if (ImagePath->Buffer == NULL)
357 return STATUS_NO_MEMORY;
358
359 wcscpy(ImagePath->Buffer, L"\\SystemRoot\\");
360 wcscat(ImagePath->Buffer, InputImagePath.Buffer);
361 ExFreePool(InputImagePath.Buffer);
362 }
363
364 return STATUS_SUCCESS;
365 }
366
367 /*
368 * IopLoadServiceModule
369 *
370 * Load a module specified by registry settings for service.
371 *
372 * Parameters
373 * ServiceName
374 * Name of the service to load.
375 *
376 * Return Value
377 * Status
378 */
379
380 NTSTATUS FASTCALL
381 IopLoadServiceModule(
382 IN PUNICODE_STRING ServiceName,
383 OUT PMODULE_OBJECT *ModuleObject)
384 {
385 RTL_QUERY_REGISTRY_TABLE QueryTable[3];
386 ULONG ServiceStart;
387 UNICODE_STRING ServiceImagePath;
388 NTSTATUS Status;
389
390 DPRINT("IopLoadServiceModule(%wZ, %x)\n", ServiceName, ModuleObject);
391
392 /*
393 * Get information about the service.
394 */
395
396 RtlZeroMemory(QueryTable, sizeof(QueryTable));
397
398 RtlInitUnicodeString(&ServiceImagePath, NULL);
399
400 QueryTable[0].Name = L"Start";
401 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
402 QueryTable[0].EntryContext = &ServiceStart;
403
404 QueryTable[1].Name = L"ImagePath";
405 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
406 QueryTable[1].EntryContext = &ServiceImagePath;
407
408 Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
409 ServiceName->Buffer, QueryTable, NULL, NULL);
410
411 if (!NT_SUCCESS(Status))
412 {
413 DPRINT("RtlQueryRegistryValues() failed (Status %x)\n", Status);
414 return Status;
415 }
416
417 IopDisplayLoadingMessage(ServiceName->Buffer);
418
419 /*
420 * Normalize the image path for all later processing.
421 */
422
423 Status = IopNormalizeImagePath(&ServiceImagePath, ServiceName);
424
425 if (!NT_SUCCESS(Status))
426 {
427 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status);
428 return Status;
429 }
430
431 /*
432 * Load the module.
433 */
434
435 *ModuleObject = LdrGetModuleObject(&ServiceImagePath);
436
437 if (*ModuleObject == NULL)
438 {
439 Status = STATUS_UNSUCCESSFUL;
440
441 /*
442 * Special case for boot modules that were loaded by boot loader.
443 */
444
445 if (ServiceStart == 0)
446 {
447 ULONG i;
448 CHAR SearchName[256];
449 PCHAR ModuleName;
450 PLOADER_MODULE KeLoaderModules =
451 (PLOADER_MODULE)KeLoaderBlock.ModsAddr;
452
453 /*
454 * FIXME:
455 * Improve this searching algorithm by using the image name
456 * stored in registry entry ImageName and use the whole path
457 * (requires change in FreeLoader).
458 */
459
460 _snprintf(SearchName, sizeof(SearchName), "%wZ.sys", ServiceName);
461 for (i = 1; i < KeLoaderBlock.ModsCount; i++)
462 {
463 ModuleName = (PCHAR)KeLoaderModules[i].String;
464 if (!_stricmp(ModuleName, SearchName))
465 {
466 DPRINT("Initializing boot module\n");
467
468 /* Tell, that the module is already loaded */
469 KeLoaderModules[i].Reserved = 1;
470
471 Status = LdrProcessModule(
472 (PVOID)KeLoaderModules[i].ModStart,
473 &ServiceImagePath,
474 ModuleObject);
475
476 KDB_SYMBOLFILE_HOOK(SearchName);
477
478 break;
479 }
480 }
481 }
482
483 /*
484 * Case for rest of the drivers (except disabled)
485 */
486
487 else if (ServiceStart < 4)
488 {
489 DPRINT("Loading module\n");
490 Status = LdrLoadModule(&ServiceImagePath, ModuleObject);
491 }
492 }
493 else
494 {
495 DPRINT("Module already loaded\n");
496 Status = STATUS_IMAGE_ALREADY_LOADED;
497 }
498
499 ExFreePool(ServiceImagePath.Buffer);
500
501 /*
502 * Now check if the module was loaded successfully.
503 */
504
505 if (!NT_SUCCESS(Status))
506 {
507 DPRINT("Module loading failed (Status %x)\n", Status);
508 }
509
510 DPRINT("Module loading (Status %x)\n", Status);
511
512 return Status;
513 }
514
515 /*
516 * IopInitializeDriverModule
517 *
518 * Initalize a loaded driver.
519 *
520 * Parameters
521 * DeviceNode
522 * Pointer to device node.
523 *
524 * ModuleObject
525 * Module object representing the driver. It can be retrieve by
526 * IopLoadServiceModule.
527 *
528 * ServiceName
529 * Name of the service (as in registry).
530 *
531 * FileSystemDriver
532 * Set to TRUE for file system drivers.
533 *
534 * DriverObject
535 * On successful return this contains the driver object representing
536 * the loaded driver.
537 */
538
539 NTSTATUS FASTCALL
540 IopInitializeDriverModule(
541 IN PDEVICE_NODE DeviceNode,
542 IN PMODULE_OBJECT ModuleObject,
543 IN PUNICODE_STRING ServiceName,
544 IN BOOLEAN FileSystemDriver,
545 OUT PDRIVER_OBJECT *DriverObject)
546 {
547 const WCHAR ServicesKeyName[] = L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
548 UNICODE_STRING RegistryKey;
549 PDRIVER_INITIALIZE DriverEntry;
550 NTSTATUS Status;
551
552 DriverEntry = ModuleObject->EntryPoint;
553
554 if (ServiceName != NULL && ServiceName->Length != 0)
555 {
556 RegistryKey.Length = 0;
557 RegistryKey.MaximumLength = sizeof(ServicesKeyName) + ServiceName->Length;
558 RegistryKey.Buffer = ExAllocatePool(PagedPool, RegistryKey.MaximumLength);
559 if (RegistryKey.Buffer == NULL)
560 {
561 return STATUS_INSUFFICIENT_RESOURCES;
562 }
563 RtlAppendUnicodeToString(&RegistryKey, ServicesKeyName);
564 RtlAppendUnicodeStringToString(&RegistryKey, ServiceName);
565 }
566 else
567 {
568 RtlInitUnicodeString(&RegistryKey, NULL);
569 }
570
571 Status = IopCreateDriverObject(
572 DriverObject,
573 ServiceName,
574 0,
575 FileSystemDriver,
576 ModuleObject->Base,
577 ModuleObject->Length);
578
579 if (!NT_SUCCESS(Status))
580 {
581 DPRINT("IopCreateDriverObject failed (Status %x)\n", Status);
582 return Status;
583 }
584
585 DPRINT("RegistryKey: %wZ\n", &RegistryKey);
586 DPRINT("Calling driver entrypoint at %08lx\n", DriverEntry);
587
588 IopMarkLastReinitializeDriver();
589
590 Status = DriverEntry(*DriverObject, &RegistryKey);
591
592 RtlFreeUnicodeString(&RegistryKey);
593
594 if (!NT_SUCCESS(Status))
595 {
596 ObMakeTemporaryObject(*DriverObject);
597 ObDereferenceObject(*DriverObject);
598 return Status;
599 }
600
601 IopReinitializeDrivers();
602
603 return STATUS_SUCCESS;
604 }
605
606 /*
607 * IopAttachFilterDriversCallback
608 *
609 * Internal routine used by IopAttachFilterDrivers.
610 */
611
612 NTSTATUS STDCALL
613 IopAttachFilterDriversCallback(
614 PWSTR ValueName,
615 ULONG ValueType,
616 PVOID ValueData,
617 ULONG ValueLength,
618 PVOID Context,
619 PVOID EntryContext)
620 {
621 PDEVICE_NODE DeviceNode = Context;
622 UNICODE_STRING ServiceName;
623 PWCHAR Filters;
624 PMODULE_OBJECT ModuleObject;
625 PDRIVER_OBJECT DriverObject;
626 NTSTATUS Status;
627
628 for (Filters = ValueData;
629 ((ULONG_PTR)Filters - (ULONG_PTR)ValueData) < ValueLength &&
630 *Filters != 0;
631 Filters += (ServiceName.Length / sizeof(WCHAR)) + 1)
632 {
633 DPRINT("Filter Driver: %S (%wZ)\n", Filters, &DeviceNode->InstancePath);
634 ServiceName.Buffer = Filters;
635 ServiceName.MaximumLength =
636 ServiceName.Length = wcslen(Filters) * sizeof(WCHAR);
637
638 /* Load and initialize the filter driver */
639 Status = IopLoadServiceModule(&ServiceName, &ModuleObject);
640 if (Status != STATUS_IMAGE_ALREADY_LOADED)
641 {
642 if (!NT_SUCCESS(Status))
643 continue;
644
645 Status = IopInitializeDriverModule(DeviceNode, ModuleObject, &ServiceName,
646 FALSE, &DriverObject);
647 if (!NT_SUCCESS(Status))
648 continue;
649 }
650 else
651 {
652 /* get existing DriverObject pointer */
653 Status = IopCreateDriverObject(
654 &DriverObject,
655 &ServiceName,
656 OBJ_OPENIF,
657 FALSE,
658 ModuleObject->Base,
659 ModuleObject->Length);
660 if (!NT_SUCCESS(Status))
661 continue;
662 }
663
664 Status = IopInitializeDevice(DeviceNode, DriverObject);
665 if (!NT_SUCCESS(Status))
666 continue;
667 }
668
669 return STATUS_SUCCESS;
670 }
671
672 /*
673 * IopAttachFilterDrivers
674 *
675 * Load filter drivers for specified device node.
676 *
677 * Parameters
678 * Lower
679 * Set to TRUE for loading lower level filters or FALSE for upper
680 * level filters.
681 */
682
683 NTSTATUS FASTCALL
684 IopAttachFilterDrivers(
685 PDEVICE_NODE DeviceNode,
686 BOOLEAN Lower)
687 {
688 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
689 PWCHAR KeyBuffer;
690 UNICODE_STRING Class;
691 WCHAR ClassBuffer[40];
692 NTSTATUS Status;
693
694 /*
695 * First load the device filters
696 */
697
698 QueryTable[0].QueryRoutine = IopAttachFilterDriversCallback;
699 if (Lower)
700 QueryTable[0].Name = L"LowerFilters";
701 else
702 QueryTable[0].Name = L"UpperFilters";
703 QueryTable[0].EntryContext = NULL;
704 QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
705 QueryTable[1].QueryRoutine = NULL;
706 QueryTable[1].Name = NULL;
707
708 KeyBuffer = ExAllocatePool(
709 PagedPool,
710 (49 * sizeof(WCHAR)) + DeviceNode->InstancePath.Length);
711 wcscpy(KeyBuffer, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
712 wcscat(KeyBuffer, DeviceNode->InstancePath.Buffer);
713
714 RtlQueryRegistryValues(
715 RTL_REGISTRY_ABSOLUTE,
716 KeyBuffer,
717 QueryTable,
718 DeviceNode,
719 NULL);
720
721 /*
722 * Now get the class GUID
723 */
724
725 Class.Length = 0;
726 Class.MaximumLength = 40 * sizeof(WCHAR);
727 Class.Buffer = ClassBuffer;
728 QueryTable[0].QueryRoutine = NULL;
729 QueryTable[0].Name = L"ClassGUID";
730 QueryTable[0].EntryContext = &Class;
731 QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_DIRECT;
732
733 Status = RtlQueryRegistryValues(
734 RTL_REGISTRY_ABSOLUTE,
735 KeyBuffer,
736 QueryTable,
737 DeviceNode,
738 NULL);
739
740 ExFreePool(KeyBuffer);
741
742 /*
743 * Load the class filter driver
744 */
745
746 if (NT_SUCCESS(Status))
747 {
748 QueryTable[0].QueryRoutine = IopAttachFilterDriversCallback;
749 if (Lower)
750 QueryTable[0].Name = L"LowerFilters";
751 else
752 QueryTable[0].Name = L"UpperFilters";
753 QueryTable[0].EntryContext = NULL;
754 QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
755
756 KeyBuffer = ExAllocatePool(PagedPool, (58 * sizeof(WCHAR)) + Class.Length);
757 wcscpy(KeyBuffer, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\");
758 wcscat(KeyBuffer, ClassBuffer);
759
760 RtlQueryRegistryValues(
761 RTL_REGISTRY_ABSOLUTE,
762 KeyBuffer,
763 QueryTable,
764 DeviceNode,
765 NULL);
766
767 ExFreePool(KeyBuffer);
768 }
769
770 return STATUS_SUCCESS;
771 }
772
773 static NTSTATUS STDCALL
774 IopGetGroupOrderList(PWSTR ValueName,
775 ULONG ValueType,
776 PVOID ValueData,
777 ULONG ValueLength,
778 PVOID Context,
779 PVOID EntryContext)
780 {
781 PSERVICE_GROUP Group;
782
783 DPRINT("IopGetGroupOrderList(%S, %x, %x, %x, %x, %x)\n",
784 ValueName, ValueType, ValueData, ValueLength, Context, EntryContext);
785
786 if (ValueType == REG_BINARY &&
787 ValueData != NULL &&
788 ValueLength >= sizeof(DWORD) &&
789 ValueLength >= (*(PULONG)ValueData + 1) * sizeof(DWORD))
790 {
791 Group = (PSERVICE_GROUP)Context;
792 Group->TagCount = ((PULONG)ValueData)[0];
793 if (Group->TagCount > 0)
794 {
795 if (ValueLength >= (Group->TagCount + 1) * sizeof(DWORD))
796 {
797 Group->TagArray = ExAllocatePool(NonPagedPool, Group->TagCount * sizeof(DWORD));
798 if (Group->TagArray == NULL)
799 {
800 Group->TagCount = 0;
801 return STATUS_INSUFFICIENT_RESOURCES;
802 }
803 memcpy(Group->TagArray, (PULONG)ValueData + 1, Group->TagCount * sizeof(DWORD));
804 }
805 else
806 {
807 Group->TagCount = 0;
808 return STATUS_UNSUCCESSFUL;
809 }
810 }
811 }
812 return STATUS_SUCCESS;
813 }
814
815 static NTSTATUS STDCALL
816 IopCreateGroupListEntry(PWSTR ValueName,
817 ULONG ValueType,
818 PVOID ValueData,
819 ULONG ValueLength,
820 PVOID Context,
821 PVOID EntryContext)
822 {
823 PSERVICE_GROUP Group;
824 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
825 NTSTATUS Status;
826
827
828 if (ValueType == REG_SZ)
829 {
830 DPRINT("GroupName: '%S'\n", (PWCHAR)ValueData);
831
832 Group = ExAllocatePool(NonPagedPool,
833 sizeof(SERVICE_GROUP));
834 if (Group == NULL)
835 {
836 return(STATUS_INSUFFICIENT_RESOURCES);
837 }
838
839 RtlZeroMemory(Group, sizeof(SERVICE_GROUP));
840
841 if (!RtlpCreateUnicodeString(&Group->GroupName, (PWSTR)ValueData, NonPagedPool))
842 {
843 ExFreePool(Group);
844 return(STATUS_INSUFFICIENT_RESOURCES);
845 }
846
847 RtlZeroMemory(&QueryTable, sizeof(QueryTable));
848 QueryTable[0].Name = (PWSTR)ValueData;
849 QueryTable[0].QueryRoutine = IopGetGroupOrderList;
850
851 Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL,
852 L"GroupOrderList",
853 QueryTable,
854 (PVOID)Group,
855 NULL);
856 DPRINT("%x %d %S\n", Status, Group->TagCount, (PWSTR)ValueData);
857
858 InsertTailList(&GroupListHead,
859 &Group->GroupListEntry);
860 }
861
862 return(STATUS_SUCCESS);
863 }
864
865
866 static NTSTATUS STDCALL
867 IopCreateServiceListEntry(PUNICODE_STRING ServiceName)
868 {
869 RTL_QUERY_REGISTRY_TABLE QueryTable[7];
870 PSERVICE Service;
871 NTSTATUS Status;
872
873 DPRINT("ServiceName: '%wZ'\n", ServiceName);
874
875 /* Allocate service entry */
876 Service = (PSERVICE)ExAllocatePool(NonPagedPool, sizeof(SERVICE));
877 if (Service == NULL)
878 {
879 DPRINT1("ExAllocatePool() failed\n");
880 return(STATUS_INSUFFICIENT_RESOURCES);
881 }
882 RtlZeroMemory(Service, sizeof(SERVICE));
883
884 /* Get service data */
885 RtlZeroMemory(&QueryTable,
886 sizeof(QueryTable));
887
888 QueryTable[0].Name = L"Start";
889 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
890 QueryTable[0].EntryContext = &Service->Start;
891
892 QueryTable[1].Name = L"Type";
893 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
894 QueryTable[1].EntryContext = &Service->Type;
895
896 QueryTable[2].Name = L"ErrorControl";
897 QueryTable[2].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
898 QueryTable[2].EntryContext = &Service->ErrorControl;
899
900 QueryTable[3].Name = L"Group";
901 QueryTable[3].Flags = RTL_QUERY_REGISTRY_DIRECT;
902 QueryTable[3].EntryContext = &Service->ServiceGroup;
903
904 QueryTable[4].Name = L"ImagePath";
905 QueryTable[4].Flags = RTL_QUERY_REGISTRY_DIRECT;
906 QueryTable[4].EntryContext = &Service->ImagePath;
907
908 QueryTable[5].Name = L"Tag";
909 QueryTable[5].Flags = RTL_QUERY_REGISTRY_DIRECT;
910 QueryTable[5].EntryContext = &Service->Tag;
911
912 Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
913 ServiceName->Buffer,
914 QueryTable,
915 NULL,
916 NULL);
917 if (!NT_SUCCESS(Status) || Service->Start > 1)
918 {
919 /*
920 * If something goes wrong during RtlQueryRegistryValues
921 * it'll just drop everything on the floor and return,
922 * so you have to check if the buffers were filled.
923 * Luckily we zerofilled the Service.
924 */
925 if (Service->ServiceGroup.Buffer)
926 {
927 ExFreePool(Service->ServiceGroup.Buffer);
928 }
929 if (Service->ImagePath.Buffer)
930 {
931 ExFreePool(Service->ImagePath.Buffer);
932 }
933 ExFreePool(Service);
934 return(Status);
935 }
936
937 /* Copy service name */
938 Service->ServiceName.Length = ServiceName->Length;
939 Service->ServiceName.MaximumLength = ServiceName->Length + sizeof(WCHAR);
940 Service->ServiceName.Buffer = ExAllocatePool(NonPagedPool,
941 Service->ServiceName.MaximumLength);
942 RtlCopyMemory(Service->ServiceName.Buffer,
943 ServiceName->Buffer,
944 ServiceName->Length);
945 Service->ServiceName.Buffer[ServiceName->Length / sizeof(WCHAR)] = 0;
946
947 /* Build registry path */
948 Service->RegistryPath.MaximumLength = MAX_PATH * sizeof(WCHAR);
949 Service->RegistryPath.Buffer = ExAllocatePool(NonPagedPool,
950 MAX_PATH * sizeof(WCHAR));
951 wcscpy(Service->RegistryPath.Buffer,
952 L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
953 wcscat(Service->RegistryPath.Buffer,
954 Service->ServiceName.Buffer);
955 Service->RegistryPath.Length = wcslen(Service->RegistryPath.Buffer) * sizeof(WCHAR);
956
957 DPRINT("ServiceName: '%wZ'\n", &Service->ServiceName);
958 DPRINT("RegistryPath: '%wZ'\n", &Service->RegistryPath);
959 DPRINT("ServiceGroup: '%wZ'\n", &Service->ServiceGroup);
960 DPRINT("ImagePath: '%wZ'\n", &Service->ImagePath);
961 DPRINT("Start %lx Type %lx Tag %lx ErrorControl %lx\n",
962 Service->Start, Service->Type, Service->Tag, Service->ErrorControl);
963
964 /* Append service entry */
965 InsertTailList(&ServiceListHead,
966 &Service->ServiceListEntry);
967
968 return(STATUS_SUCCESS);
969 }
970
971
972 NTSTATUS INIT_FUNCTION
973 IoCreateDriverList(VOID)
974 {
975 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
976 PKEY_BASIC_INFORMATION KeyInfo = NULL;
977 OBJECT_ATTRIBUTES ObjectAttributes;
978 UNICODE_STRING ServicesKeyName;
979 UNICODE_STRING SubKeyName;
980 HANDLE KeyHandle;
981 NTSTATUS Status;
982 ULONG Index;
983
984 ULONG KeyInfoLength = 0;
985 ULONG ReturnedLength;
986
987 DPRINT("IoCreateDriverList() called\n");
988
989 /* Initialize basic variables */
990 InitializeListHead(&GroupListHead);
991 InitializeListHead(&ServiceListHead);
992
993 /* Build group order list */
994 RtlZeroMemory(&QueryTable,
995 sizeof(QueryTable));
996
997 QueryTable[0].Name = L"List";
998 QueryTable[0].QueryRoutine = IopCreateGroupListEntry;
999
1000 Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL,
1001 L"ServiceGroupOrder",
1002 QueryTable,
1003 NULL,
1004 NULL);
1005 if (!NT_SUCCESS(Status))
1006 return(Status);
1007
1008 /* Enumerate services and create the service list */
1009 RtlRosInitUnicodeStringFromLiteral(&ServicesKeyName,
1010 L"\\Registry\\Machine\\System\\CurrentControlSet\\Services");
1011
1012 InitializeObjectAttributes(&ObjectAttributes,
1013 &ServicesKeyName,
1014 OBJ_CASE_INSENSITIVE,
1015 NULL,
1016 NULL);
1017
1018 Status = ZwOpenKey(&KeyHandle,
1019 KEY_ENUMERATE_SUB_KEYS,
1020 &ObjectAttributes);
1021 if (!NT_SUCCESS(Status))
1022 {
1023 return(Status);
1024 }
1025
1026 KeyInfoLength = sizeof(KEY_BASIC_INFORMATION) + MAX_PATH * sizeof(WCHAR);
1027 KeyInfo = ExAllocatePool(NonPagedPool, KeyInfoLength);
1028 if (KeyInfo == NULL)
1029 {
1030 ZwClose(KeyHandle);
1031 return(STATUS_INSUFFICIENT_RESOURCES);
1032 }
1033
1034 Index = 0;
1035 while (TRUE)
1036 {
1037 Status = ZwEnumerateKey(KeyHandle,
1038 Index,
1039 KeyBasicInformation,
1040 KeyInfo,
1041 KeyInfoLength,
1042 &ReturnedLength);
1043 if (NT_SUCCESS(Status))
1044 {
1045 if (KeyInfo->NameLength < MAX_PATH * sizeof(WCHAR))
1046 {
1047
1048 SubKeyName.Length = KeyInfo->NameLength;
1049 SubKeyName.MaximumLength = KeyInfo->NameLength + sizeof(WCHAR);
1050 SubKeyName.Buffer = KeyInfo->Name;
1051 SubKeyName.Buffer[SubKeyName.Length / sizeof(WCHAR)] = 0;
1052
1053 DPRINT("KeyName: '%wZ'\n", &SubKeyName);
1054 IopCreateServiceListEntry(&SubKeyName);
1055 }
1056 }
1057
1058 if (!NT_SUCCESS(Status))
1059 break;
1060
1061 Index++;
1062 }
1063
1064 ExFreePool(KeyInfo);
1065 ZwClose(KeyHandle);
1066
1067 DPRINT("IoCreateDriverList() done\n");
1068
1069 return(STATUS_SUCCESS);
1070 }
1071
1072 NTSTATUS INIT_FUNCTION
1073 IoDestroyDriverList(VOID)
1074 {
1075 PLIST_ENTRY GroupEntry;
1076 PLIST_ENTRY ServiceEntry;
1077 PSERVICE_GROUP CurrentGroup;
1078 PSERVICE CurrentService;
1079
1080 DPRINT("IoDestroyDriverList() called\n");
1081
1082 /* Destroy group list */
1083 GroupEntry = GroupListHead.Flink;
1084 while (GroupEntry != &GroupListHead)
1085 {
1086 CurrentGroup = CONTAINING_RECORD(GroupEntry, SERVICE_GROUP, GroupListEntry);
1087
1088 ExFreePool(CurrentGroup->GroupName.Buffer);
1089 RemoveEntryList(GroupEntry);
1090 if (CurrentGroup->TagArray)
1091 {
1092 ExFreePool(CurrentGroup->TagArray);
1093 }
1094 ExFreePool(CurrentGroup);
1095
1096 GroupEntry = GroupListHead.Flink;
1097 }
1098
1099 /* Destroy service list */
1100 ServiceEntry = ServiceListHead.Flink;
1101 while (ServiceEntry != &ServiceListHead)
1102 {
1103 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
1104
1105 ExFreePool(CurrentService->ServiceName.Buffer);
1106 ExFreePool(CurrentService->RegistryPath.Buffer);
1107 ExFreePool(CurrentService->ServiceGroup.Buffer);
1108 ExFreePool(CurrentService->ImagePath.Buffer);
1109 RemoveEntryList(ServiceEntry);
1110 ExFreePool(CurrentService);
1111
1112 ServiceEntry = ServiceListHead.Flink;
1113 }
1114
1115 DPRINT("IoDestroyDriverList() done\n");
1116
1117 return(STATUS_SUCCESS);
1118 }
1119
1120 VOID STATIC INIT_FUNCTION
1121 MiFreeBootDriverMemory(PVOID StartAddress, ULONG Length)
1122 {
1123 ULONG i;
1124
1125 for (i = 0; i < PAGE_ROUND_UP(Length) / PAGE_SIZE; i++)
1126 {
1127 MmDeleteVirtualMapping(NULL, (char*)StartAddress + i * PAGE_SIZE, TRUE, NULL, NULL);
1128 }
1129 }
1130
1131 /*
1132 * IopInitializeBuiltinDriver
1133 *
1134 * Initialize a driver that is already loaded in memory.
1135 */
1136
1137 NTSTATUS FASTCALL INIT_FUNCTION
1138 IopInitializeBuiltinDriver(
1139 PDEVICE_NODE ModuleDeviceNode,
1140 PVOID ModuleLoadBase,
1141 PCHAR FileName,
1142 ULONG ModuleLength)
1143 {
1144 PMODULE_OBJECT ModuleObject;
1145 PDEVICE_NODE DeviceNode;
1146 PDRIVER_OBJECT DriverObject;
1147 NTSTATUS Status;
1148 CHAR TextBuffer[256];
1149 PCHAR FileNameWithoutPath;
1150 LPWSTR FileExtension;
1151
1152 DPRINT("Initializing driver '%s' at %08lx, length 0x%08lx\n",
1153 FileName, ModuleLoadBase, ModuleLength);
1154
1155 /*
1156 * Display 'Initializing XXX...' message
1157 */
1158
1159 sprintf(TextBuffer, "Initializing %s...\n", FileName);
1160 HalDisplayString(TextBuffer);
1161
1162 /*
1163 * Determine the right device object
1164 */
1165
1166 if (ModuleDeviceNode == NULL)
1167 {
1168 /* Use IopRootDeviceNode for now */
1169 Status = IopCreateDeviceNode(IopRootDeviceNode, NULL, &DeviceNode);
1170 if (!NT_SUCCESS(Status))
1171 {
1172 CPRINT("Driver load failed, status (%x)\n", Status);
1173 return(Status);
1174 }
1175 } else
1176 {
1177 DeviceNode = ModuleDeviceNode;
1178 }
1179
1180 /*
1181 * Generate filename without path (not needed by freeldr)
1182 */
1183
1184 FileNameWithoutPath = strrchr(FileName, '\\');
1185 if (FileNameWithoutPath == NULL)
1186 {
1187 FileNameWithoutPath = FileName;
1188 }
1189
1190 /*
1191 * Load the module
1192 */
1193
1194 RtlCreateUnicodeStringFromAsciiz(&DeviceNode->ServiceName,
1195 FileNameWithoutPath);
1196 Status = LdrProcessModule(ModuleLoadBase, &DeviceNode->ServiceName,
1197 &ModuleObject);
1198 if (!NT_SUCCESS(Status))
1199 {
1200 if (ModuleDeviceNode == NULL)
1201 IopFreeDeviceNode(DeviceNode);
1202 CPRINT("Driver load failed, status (%x)\n", Status);
1203 return Status;
1204 }
1205
1206 /* Load symbols */
1207 KDB_SYMBOLFILE_HOOK(FileName);
1208
1209 /*
1210 * Strip the file extension from ServiceName
1211 */
1212
1213 FileExtension = wcsrchr(DeviceNode->ServiceName.Buffer, '.');
1214 if (FileExtension != NULL)
1215 {
1216 DeviceNode->ServiceName.Length -= wcslen(FileExtension) * sizeof(WCHAR);
1217 FileExtension[0] = 0;
1218 }
1219
1220 /*
1221 * Initialize the driver
1222 */
1223
1224 Status = IopInitializeDriverModule(DeviceNode, ModuleObject,
1225 &DeviceNode->ServiceName, FALSE, &DriverObject);
1226
1227 if (!NT_SUCCESS(Status))
1228 {
1229 if (ModuleDeviceNode == NULL)
1230 IopFreeDeviceNode(DeviceNode);
1231 CPRINT("Driver load failed, status (%x)\n", Status);
1232 return Status;
1233 }
1234
1235 Status = IopInitializeDevice(DeviceNode, DriverObject);
1236
1237 return Status;
1238 }
1239
1240 /*
1241 * IopInitializeBootDrivers
1242 *
1243 * Initialize boot drivers and free memory for boot files.
1244 *
1245 * Parameters
1246 * None
1247 *
1248 * Return Value
1249 * None
1250 */
1251
1252 VOID FASTCALL
1253 IopInitializeBootDrivers(VOID)
1254 {
1255 ULONG BootDriverCount;
1256 ULONG ModuleStart;
1257 ULONG ModuleSize;
1258 ULONG ModuleLoaded;
1259 PCHAR ModuleName;
1260 PCHAR Extension;
1261 PLOADER_MODULE KeLoaderModules = (PLOADER_MODULE)KeLoaderBlock.ModsAddr;
1262 ULONG i;
1263 UNICODE_STRING DriverName;
1264 NTSTATUS Status;
1265
1266 DPRINT("IopInitializeBootDrivers()\n");
1267
1268 BootDriverCount = 0;
1269 for (i = 0; i < KeLoaderBlock.ModsCount; i++)
1270 {
1271 ModuleStart = KeLoaderModules[i].ModStart;
1272 ModuleSize = KeLoaderModules[i].ModEnd - ModuleStart;
1273 ModuleName = (PCHAR)KeLoaderModules[i].String;
1274 ModuleLoaded = KeLoaderModules[i].Reserved;
1275 Extension = strrchr(ModuleName, '.');
1276 if (Extension == NULL)
1277 Extension = "";
1278
1279 if (!_stricmp(Extension, ".sym") || !_stricmp(Extension, ".dll"))
1280 {
1281 /* Process symbols for *.exe and *.dll */
1282 KDB_SYMBOLFILE_HOOK(ModuleName);
1283
1284 /* Log *.exe and *.dll files */
1285 RtlCreateUnicodeStringFromAsciiz(&DriverName, ModuleName);
1286 IopBootLog(&DriverName, TRUE);
1287 RtlFreeUnicodeString(&DriverName);
1288 }
1289 else if (!_stricmp(Extension, ".sys"))
1290 {
1291 /* Initialize and log boot start driver */
1292 if (!ModuleLoaded)
1293 {
1294 Status = IopInitializeBuiltinDriver(NULL,
1295 (PVOID)ModuleStart,
1296 ModuleName,
1297 ModuleSize);
1298 RtlCreateUnicodeStringFromAsciiz(&DriverName, ModuleName);
1299 IopBootLog(&DriverName, NT_SUCCESS(Status) ? TRUE : FALSE);
1300 RtlFreeUnicodeString(&DriverName);
1301 }
1302 BootDriverCount++;
1303 }
1304 }
1305
1306 /*
1307 * Free memory for all boot files, except ntoskrnl.exe.
1308 */
1309 for (i = 1; i < KeLoaderBlock.ModsCount; i++)
1310 {
1311 MiFreeBootDriverMemory((PVOID)KeLoaderModules[i].ModStart,
1312 KeLoaderModules[i].ModEnd - KeLoaderModules[i].ModStart);
1313 }
1314
1315 KeLoaderBlock.ModsCount = 0;
1316
1317 if (BootDriverCount == 0)
1318 {
1319 DbgPrint("No boot drivers available.\n");
1320 KEBUGCHECK(0);
1321 }
1322 }
1323
1324 static INIT_FUNCTION NTSTATUS
1325 IopLoadDriver(PSERVICE Service)
1326 {
1327 NTSTATUS Status = STATUS_UNSUCCESSFUL;
1328
1329 IopDisplayLoadingMessage(Service->ServiceName.Buffer);
1330 Status = ZwLoadDriver(&Service->RegistryPath);
1331 IopBootLog(&Service->ImagePath, NT_SUCCESS(Status) ? TRUE : FALSE);
1332 if (!NT_SUCCESS(Status))
1333 {
1334 DPRINT("IopLoadDriver() failed (Status %lx)\n", Status);
1335 #if 0
1336 if (Service->ErrorControl == 1)
1337 {
1338 /* Log error */
1339 }
1340 else if (Service->ErrorControl == 2)
1341 {
1342 if (IsLastKnownGood == FALSE)
1343 {
1344 /* Boot last known good configuration */
1345 }
1346 }
1347 else if (Service->ErrorControl == 3)
1348 {
1349 if (IsLastKnownGood == FALSE)
1350 {
1351 /* Boot last known good configuration */
1352 }
1353 else
1354 {
1355 /* BSOD! */
1356 }
1357 }
1358 #endif
1359 }
1360 return Status;
1361 }
1362
1363
1364 /*
1365 * IopInitializeSystemDrivers
1366 *
1367 * Load drivers marked as system start.
1368 *
1369 * Parameters
1370 * None
1371 *
1372 * Return Value
1373 * None
1374 */
1375
1376 VOID FASTCALL
1377 IopInitializeSystemDrivers(VOID)
1378 {
1379 PLIST_ENTRY GroupEntry;
1380 PLIST_ENTRY ServiceEntry;
1381 PSERVICE_GROUP CurrentGroup;
1382 PSERVICE CurrentService;
1383 NTSTATUS Status;
1384 ULONG i;
1385
1386 DPRINT("IopInitializeSystemDrivers()\n");
1387
1388 GroupEntry = GroupListHead.Flink;
1389 while (GroupEntry != &GroupListHead)
1390 {
1391 CurrentGroup = CONTAINING_RECORD(GroupEntry, SERVICE_GROUP, GroupListEntry);
1392
1393 DPRINT("Group: %wZ\n", &CurrentGroup->GroupName);
1394
1395 /* Load all drivers with a valid tag */
1396 for (i = 0; i < CurrentGroup->TagCount; i++)
1397 {
1398 ServiceEntry = ServiceListHead.Flink;
1399 while (ServiceEntry != &ServiceListHead)
1400 {
1401 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
1402
1403 if ((RtlCompareUnicodeString(&CurrentGroup->GroupName,
1404 &CurrentService->ServiceGroup, TRUE) == 0) &&
1405 (CurrentService->Start == 1 /*SERVICE_SYSTEM_START*/) &&
1406 (CurrentService->Tag == CurrentGroup->TagArray[i]))
1407 {
1408 DPRINT(" Path: %wZ\n", &CurrentService->RegistryPath);
1409 Status = IopLoadDriver(CurrentService);
1410 }
1411 ServiceEntry = ServiceEntry->Flink;
1412 }
1413 }
1414
1415 /* Load all drivers without a tag or with an invalid tag */
1416 ServiceEntry = ServiceListHead.Flink;
1417 while (ServiceEntry != &ServiceListHead)
1418 {
1419 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
1420 if ((RtlCompareUnicodeString(&CurrentGroup->GroupName,
1421 &CurrentService->ServiceGroup, TRUE) == 0) &&
1422 (CurrentService->Start == 1 /*SERVICE_SYSTEM_START*/))
1423 {
1424 for (i = 0; i < CurrentGroup->TagCount; i++)
1425 {
1426 if (CurrentGroup->TagArray[i] == CurrentService->Tag)
1427 {
1428 break;
1429 }
1430 }
1431 if (i >= CurrentGroup->TagCount)
1432 {
1433 DPRINT(" Path: %wZ\n", &CurrentService->RegistryPath);
1434 Status = IopLoadDriver(CurrentService);
1435 }
1436 }
1437 ServiceEntry = ServiceEntry->Flink;
1438 }
1439
1440 GroupEntry = GroupEntry->Flink;
1441 }
1442
1443 DPRINT("IopInitializeSystemDrivers() done\n");
1444 }
1445
1446 /*
1447 * IopUnloadDriver
1448 *
1449 * Unloads a device driver.
1450 *
1451 * Parameters
1452 * DriverServiceName
1453 * Name of the service to unload (registry key).
1454 *
1455 * UnloadPnpDrivers
1456 * Whether to unload Plug & Plug or only legacy drivers. If this
1457 * parameter is set to FALSE, the routine will unload only legacy
1458 * drivers.
1459 *
1460 * Return Value
1461 * Status
1462 *
1463 * To do
1464 * Guard the whole function by SEH.
1465 */
1466
1467 NTSTATUS STDCALL
1468 IopUnloadDriver(PUNICODE_STRING DriverServiceName, BOOLEAN UnloadPnpDrivers)
1469 {
1470 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
1471 UNICODE_STRING ImagePath;
1472 UNICODE_STRING ServiceName;
1473 UNICODE_STRING ObjectName;
1474 PDRIVER_OBJECT DriverObject;
1475 PMODULE_OBJECT ModuleObject;
1476 NTSTATUS Status;
1477 LPWSTR Start;
1478
1479 DPRINT("IopUnloadDriver('%wZ', %d)\n", DriverServiceName, UnloadPnpDrivers);
1480
1481 /*
1482 * Get the service name from the registry key name
1483 */
1484
1485 Start = wcsrchr(DriverServiceName->Buffer, L'\\');
1486 if (Start == NULL)
1487 Start = DriverServiceName->Buffer;
1488 else
1489 Start++;
1490
1491 RtlInitUnicodeString(&ServiceName, Start);
1492
1493 /*
1494 * Construct the driver object name
1495 */
1496
1497 ObjectName.Length = (wcslen(Start) + 8) * sizeof(WCHAR);
1498 ObjectName.MaximumLength = ObjectName.Length + sizeof(WCHAR);
1499 ObjectName.Buffer = ExAllocatePool(NonPagedPool, ObjectName.MaximumLength);
1500 wcscpy(ObjectName.Buffer, L"\\Driver\\");
1501 memcpy(ObjectName.Buffer + 8, Start, (ObjectName.Length - 8) * sizeof(WCHAR));
1502 ObjectName.Buffer[ObjectName.Length/sizeof(WCHAR)] = 0;
1503
1504 /*
1505 * Find the driver object
1506 */
1507
1508 Status = ObReferenceObjectByName(&ObjectName, 0, 0, 0, IoDriverObjectType,
1509 KernelMode, 0, (PVOID*)&DriverObject);
1510
1511 if (!NT_SUCCESS(Status))
1512 {
1513 DPRINT("Can't locate driver object for %wZ\n", ObjectName);
1514 return Status;
1515 }
1516
1517 /*
1518 * Free the buffer for driver object name
1519 */
1520
1521 ExFreePool(ObjectName.Buffer);
1522
1523 /*
1524 * Get path of service...
1525 */
1526
1527 RtlZeroMemory(QueryTable, sizeof(QueryTable));
1528
1529 RtlInitUnicodeString(&ImagePath, NULL);
1530
1531 QueryTable[0].Name = L"ImagePath";
1532 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
1533 QueryTable[0].EntryContext = &ImagePath;
1534
1535 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
1536 DriverServiceName->Buffer, QueryTable, NULL, NULL);
1537
1538 if (!NT_SUCCESS(Status))
1539 {
1540 DPRINT("RtlQueryRegistryValues() failed (Status %x)\n", Status);
1541 return Status;
1542 }
1543
1544 /*
1545 * Normalize the image path for all later processing.
1546 */
1547
1548 Status = IopNormalizeImagePath(&ImagePath, &ServiceName);
1549
1550 if (!NT_SUCCESS(Status))
1551 {
1552 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status);
1553 return Status;
1554 }
1555
1556 /*
1557 * ... and check if it's loaded
1558 */
1559
1560 ModuleObject = LdrGetModuleObject(&ImagePath);
1561 if (ModuleObject == NULL)
1562 {
1563 return STATUS_UNSUCCESSFUL;
1564 }
1565
1566 /*
1567 * Free the service path
1568 */
1569
1570 ExFreePool(ImagePath.Buffer);
1571
1572 /*
1573 * Unload the module and release the references to the device object
1574 */
1575
1576 if (DriverObject->DriverUnload)
1577 (*DriverObject->DriverUnload)(DriverObject);
1578 ObDereferenceObject(DriverObject);
1579 ObDereferenceObject(DriverObject);
1580 LdrUnloadModule(ModuleObject);
1581
1582 return STATUS_SUCCESS;
1583 }
1584
1585 VOID FASTCALL
1586 IopMarkLastReinitializeDriver(VOID)
1587 {
1588 KIRQL Irql;
1589
1590 KeAcquireSpinLock(&DriverReinitListLock,
1591 &Irql);
1592
1593 if (IsListEmpty(&DriverReinitListHead))
1594 {
1595 DriverReinitTailEntry = NULL;
1596 }
1597 else
1598 {
1599 DriverReinitTailEntry = DriverReinitListHead.Blink;
1600 }
1601
1602 KeReleaseSpinLock(&DriverReinitListLock,
1603 Irql);
1604 }
1605
1606
1607 VOID FASTCALL
1608 IopReinitializeDrivers(VOID)
1609 {
1610 PDRIVER_REINIT_ITEM ReinitItem;
1611 PLIST_ENTRY Entry;
1612 KIRQL Irql;
1613
1614 KeAcquireSpinLock(&DriverReinitListLock,
1615 &Irql);
1616
1617 if (DriverReinitTailEntry == NULL)
1618 {
1619 KeReleaseSpinLock(&DriverReinitListLock,
1620 Irql);
1621 return;
1622 }
1623
1624 KeReleaseSpinLock(&DriverReinitListLock,
1625 Irql);
1626
1627 for (;;)
1628 {
1629 Entry = ExInterlockedRemoveHeadList(&DriverReinitListHead,
1630 &DriverReinitListLock);
1631 if (Entry == NULL)
1632 return;
1633
1634 ReinitItem = (PDRIVER_REINIT_ITEM)CONTAINING_RECORD(Entry, DRIVER_REINIT_ITEM, ItemEntry);
1635
1636 /* Increment reinitialization counter */
1637 ReinitItem->DriverObject->DriverExtension->Count++;
1638
1639 ReinitItem->ReinitRoutine(ReinitItem->DriverObject,
1640 ReinitItem->Context,
1641 ReinitItem->DriverObject->DriverExtension->Count);
1642
1643 ExFreePool(Entry);
1644
1645 if (Entry == DriverReinitTailEntry)
1646 return;
1647 }
1648 }
1649
1650 /* PUBLIC FUNCTIONS ***********************************************************/
1651
1652
1653 /*
1654 * @implemented
1655 */
1656 NTSTATUS
1657 STDCALL
1658 IoCreateDriver (
1659 IN PUNICODE_STRING DriverName, OPTIONAL
1660 IN PDRIVER_INITIALIZE InitializationFunction
1661 )
1662 {
1663 WCHAR NameBuffer[100];
1664 USHORT NameLength;
1665 UNICODE_STRING LocalDriverName; /* To reduce code if no name given */
1666 NTSTATUS Status;
1667 OBJECT_ATTRIBUTES ObjectAttributes;
1668 ULONG ObjectSize;
1669 PDRIVER_OBJECT DriverObject;
1670 UNICODE_STRING ServiceKeyName;
1671 HANDLE hDriver;
1672 ULONG i;
1673
1674 /* First, create a unique name for the driver if we don't have one */
1675 if (!DriverName) {
1676
1677 /* Create a random name and set up the string*/
1678 NameLength = swprintf(NameBuffer, L"\\Driver\\%08u", KeTickCount);
1679 LocalDriverName.Length = NameLength * sizeof(WCHAR);
1680 LocalDriverName.MaximumLength = LocalDriverName.Length + sizeof(UNICODE_NULL);
1681 LocalDriverName.Buffer = NameBuffer;
1682
1683 } else {
1684
1685 /* So we can avoid another code path, use a local var */
1686 LocalDriverName = *DriverName;
1687 }
1688
1689 /* Initialize the Attributes */
1690 ObjectSize = sizeof(DRIVER_OBJECT) + sizeof(DRIVER_EXTENSION);
1691 InitializeObjectAttributes(&ObjectAttributes,
1692 &LocalDriverName,
1693 OBJ_PERMANENT | OBJ_CASE_INSENSITIVE,
1694 NULL,
1695 NULL);
1696
1697 /* Create the Object */
1698 Status = ObCreateObject(KernelMode,
1699 IoDriverObjectType,
1700 &ObjectAttributes,
1701 KernelMode,
1702 NULL,
1703 ObjectSize,
1704 0,
1705 0,
1706 (PVOID*)&DriverObject);
1707
1708 /* Return on failure */
1709 if (!NT_SUCCESS(Status)) return Status;
1710
1711 /* Set up the Object */
1712 RtlZeroMemory(DriverObject, ObjectSize);
1713 DriverObject->Type = IO_TYPE_DRIVER;
1714 DriverObject->Size = sizeof(DRIVER_OBJECT);
1715 DriverObject->Flags = DRVO_BUILTIN_DRIVER;
1716 DriverObject->DriverExtension = (PDRIVER_EXTENSION)(DriverObject + 1);
1717 DriverObject->DriverExtension->DriverObject = DriverObject;
1718 DriverObject->DriverInit = InitializationFunction;
1719
1720 /* Invalidate all Major Functions */
1721 for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
1722 {
1723 DriverObject->MajorFunction[i] = IopInvalidDeviceRequest;
1724 }
1725
1726 /* Set up the Service Key Name */
1727 ServiceKeyName.Buffer = ExAllocatePool(PagedPool, LocalDriverName.Length + sizeof(WCHAR));
1728 ServiceKeyName.Length = LocalDriverName.Length;
1729 ServiceKeyName.MaximumLength = LocalDriverName.MaximumLength;
1730 RtlMoveMemory(ServiceKeyName.Buffer, LocalDriverName.Buffer, LocalDriverName.Length);
1731 ServiceKeyName.Buffer[ServiceKeyName.Length / sizeof(WCHAR)] = L'\0';
1732 DriverObject->DriverExtension->ServiceKeyName = ServiceKeyName;
1733
1734 /* Also store it in the Driver Object. This is a bit of a hack. */
1735 RtlMoveMemory(&DriverObject->DriverName, &ServiceKeyName, sizeof(UNICODE_STRING));
1736
1737 /* Add the Object and get its handle */
1738 Status = ObInsertObject(DriverObject,
1739 NULL,
1740 FILE_READ_DATA,
1741 0,
1742 NULL,
1743 &hDriver);
1744
1745 /* Return on Failure */
1746 if (!NT_SUCCESS(Status)) return Status;
1747
1748 /* Now reference it */
1749 Status = ObReferenceObjectByHandle(hDriver,
1750 0,
1751 IoDriverObjectType,
1752 KernelMode,
1753 (PVOID*)&DriverObject,
1754 NULL);
1755 ZwClose(hDriver);
1756
1757 /* Finally, call its init function */
1758 Status = (*InitializationFunction)(DriverObject, NULL);
1759
1760 if (!NT_SUCCESS(Status)) {
1761 /* If it didn't work, then kill the object */
1762 ObMakeTemporaryObject(DriverObject);
1763 ObDereferenceObject(DriverObject);
1764 }
1765
1766 /* Return the Status */
1767 return Status;
1768 }
1769
1770 /*
1771 * @implemented
1772 */
1773 VOID
1774 STDCALL
1775 IoDeleteDriver (
1776 IN PDRIVER_OBJECT DriverObject
1777 )
1778 {
1779 /* Simply derefence the Object */
1780 ObDereferenceObject(DriverObject);
1781 }
1782
1783
1784 /*
1785 * NtLoadDriver
1786 *
1787 * Loads a device driver.
1788 *
1789 * Parameters
1790 * DriverServiceName
1791 * Name of the service to load (registry key).
1792 *
1793 * Return Value
1794 * Status
1795 *
1796 * Status
1797 * implemented
1798 */
1799
1800 NTSTATUS STDCALL
1801 NtLoadDriver(IN PUNICODE_STRING DriverServiceName)
1802 {
1803 RTL_QUERY_REGISTRY_TABLE QueryTable[3];
1804 UNICODE_STRING ImagePath;
1805 UNICODE_STRING ServiceName;
1806 UNICODE_STRING CapturedDriverServiceName;
1807 KPROCESSOR_MODE PreviousMode;
1808 NTSTATUS Status;
1809 ULONG Type;
1810 PDEVICE_NODE DeviceNode;
1811 PMODULE_OBJECT ModuleObject;
1812 PDRIVER_OBJECT DriverObject;
1813 WCHAR *cur;
1814
1815 PAGED_CODE();
1816
1817 PreviousMode = KeGetPreviousMode();
1818
1819 /*
1820 * Check security privileges
1821 */
1822
1823 /* FIXME: Uncomment when privileges will be correctly implemented. */
1824 #if 0
1825 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, PreviousMode))
1826 {
1827 DPRINT("Privilege not held\n");
1828 return STATUS_PRIVILEGE_NOT_HELD;
1829 }
1830 #endif
1831
1832 Status = RtlCaptureUnicodeString(&CapturedDriverServiceName,
1833 PreviousMode,
1834 PagedPool,
1835 FALSE,
1836 DriverServiceName);
1837 if (!NT_SUCCESS(Status))
1838 {
1839 return Status;
1840 }
1841
1842 DPRINT("NtLoadDriver('%wZ')\n", &CapturedDriverServiceName);
1843
1844 RtlInitUnicodeString(&ImagePath, NULL);
1845
1846 /*
1847 * Get the service name from the registry key name.
1848 */
1849 ASSERT(CapturedDriverServiceName.Length >= sizeof(WCHAR));
1850
1851 ServiceName = CapturedDriverServiceName;
1852 cur = CapturedDriverServiceName.Buffer + (CapturedDriverServiceName.Length / sizeof(WCHAR)) - 1;
1853 while (CapturedDriverServiceName.Buffer != cur)
1854 {
1855 if(*cur == L'\\')
1856 {
1857 ServiceName.Buffer = cur + 1;
1858 ServiceName.Length = CapturedDriverServiceName.Length -
1859 (USHORT)((ULONG_PTR)ServiceName.Buffer -
1860 (ULONG_PTR)CapturedDriverServiceName.Buffer);
1861 break;
1862 }
1863 cur--;
1864 }
1865
1866 /*
1867 * Get service type.
1868 */
1869
1870 RtlZeroMemory(&QueryTable, sizeof(QueryTable));
1871
1872 RtlInitUnicodeString(&ImagePath, NULL);
1873
1874 QueryTable[0].Name = L"Type";
1875 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
1876 QueryTable[0].EntryContext = &Type;
1877
1878 QueryTable[1].Name = L"ImagePath";
1879 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
1880 QueryTable[1].EntryContext = &ImagePath;
1881
1882 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
1883 CapturedDriverServiceName.Buffer, QueryTable, NULL, NULL);
1884
1885 if (!NT_SUCCESS(Status))
1886 {
1887 DPRINT("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
1888 ExFreePool(ImagePath.Buffer);
1889 goto ReleaseCapturedString;
1890 }
1891
1892 /*
1893 * Normalize the image path for all later processing.
1894 */
1895
1896 Status = IopNormalizeImagePath(&ImagePath, &ServiceName);
1897
1898 if (!NT_SUCCESS(Status))
1899 {
1900 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status);
1901 goto ReleaseCapturedString;
1902 }
1903
1904 DPRINT("FullImagePath: '%wZ'\n", &ImagePath);
1905 DPRINT("Type: %lx\n", Type);
1906
1907 /*
1908 * See, if the driver module isn't already loaded
1909 */
1910
1911 ModuleObject = LdrGetModuleObject(&ImagePath);
1912 if (ModuleObject != NULL)
1913 {
1914 DPRINT("Image already loaded\n");
1915 Status = STATUS_IMAGE_ALREADY_LOADED;
1916 goto ReleaseCapturedString;
1917 }
1918
1919 /*
1920 * Create device node
1921 */
1922
1923 /* Use IopRootDeviceNode for now */
1924 Status = IopCreateDeviceNode(IopRootDeviceNode, NULL, &DeviceNode);
1925
1926 if (!NT_SUCCESS(Status))
1927 {
1928 DPRINT("IopCreateDeviceNode() failed (Status %lx)\n", Status);
1929 goto ReleaseCapturedString;
1930 }
1931
1932 /*
1933 * Load the driver module
1934 */
1935
1936 Status = LdrLoadModule(&ImagePath, &ModuleObject);
1937
1938 if (!NT_SUCCESS(Status))
1939 {
1940 DPRINT("LdrLoadModule() failed (Status %lx)\n", Status);
1941 IopFreeDeviceNode(DeviceNode);
1942 goto ReleaseCapturedString;
1943 }
1944
1945 /*
1946 * Set a service name for the device node
1947 */
1948
1949 RtlpCreateUnicodeString(&DeviceNode->ServiceName, ServiceName.Buffer, NonPagedPool);
1950
1951 /*
1952 * Initialize the driver module
1953 */
1954
1955 Status = IopInitializeDriverModule(
1956 DeviceNode,
1957 ModuleObject,
1958 &DeviceNode->ServiceName,
1959 (Type == 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
1960 Type == 8 /* SERVICE_RECOGNIZER_DRIVER */),
1961 &DriverObject);
1962
1963 if (!NT_SUCCESS(Status))
1964 {
1965 DPRINT("IopInitializeDriver() failed (Status %lx)\n", Status);
1966 LdrUnloadModule(ModuleObject);
1967 IopFreeDeviceNode(DeviceNode);
1968 goto ReleaseCapturedString;
1969 }
1970
1971 IopInitializeDevice(DeviceNode, DriverObject);
1972
1973 ReleaseCapturedString:
1974 RtlReleaseCapturedUnicodeString(&CapturedDriverServiceName,
1975 PreviousMode,
1976 FALSE);
1977
1978 return Status;
1979 }
1980
1981 /*
1982 * NtUnloadDriver
1983 *
1984 * Unloads a legacy device driver.
1985 *
1986 * Parameters
1987 * DriverServiceName
1988 * Name of the service to unload (registry key).
1989 *
1990 * Return Value
1991 * Status
1992 *
1993 * Status
1994 * implemented
1995 */
1996
1997 NTSTATUS STDCALL
1998 NtUnloadDriver(IN PUNICODE_STRING DriverServiceName)
1999 {
2000 return IopUnloadDriver(DriverServiceName, FALSE);
2001 }
2002
2003 /*
2004 * IoRegisterDriverReinitialization
2005 *
2006 * Status
2007 * @implemented
2008 */
2009
2010 VOID STDCALL
2011 IoRegisterDriverReinitialization(
2012 PDRIVER_OBJECT DriverObject,
2013 PDRIVER_REINITIALIZE ReinitRoutine,
2014 PVOID Context)
2015 {
2016 PDRIVER_REINIT_ITEM ReinitItem;
2017
2018 ReinitItem = ExAllocatePool(NonPagedPool, sizeof(DRIVER_REINIT_ITEM));
2019 if (ReinitItem == NULL)
2020 return;
2021
2022 ReinitItem->DriverObject = DriverObject;
2023 ReinitItem->ReinitRoutine = ReinitRoutine;
2024 ReinitItem->Context = Context;
2025
2026 DriverObject->Flags |= DRVO_REINIT_REGISTERED;
2027
2028 ExInterlockedInsertTailList(
2029 &DriverReinitListHead,
2030 &ReinitItem->ItemEntry,
2031 &DriverReinitListLock);
2032 }
2033
2034 /*
2035 * @implemented
2036 */
2037 VOID
2038 STDCALL
2039 IoRegisterBootDriverReinitialization(
2040 IN PDRIVER_OBJECT DriverObject,
2041 IN PDRIVER_REINITIALIZE DriverReinitializationRoutine,
2042 IN PVOID Context
2043 )
2044 {
2045 PDRIVER_REINIT_ITEM ReinitItem;
2046
2047 ReinitItem = ExAllocatePool(NonPagedPool, sizeof(DRIVER_REINIT_ITEM));
2048 if (ReinitItem == NULL)
2049 return;
2050
2051 ReinitItem->DriverObject = DriverObject;
2052 ReinitItem->ReinitRoutine = DriverReinitializationRoutine;
2053 ReinitItem->Context = Context;
2054
2055 DriverObject->Flags |= DRVO_BOOTREINIT_REGISTERED;
2056
2057 ExInterlockedInsertTailList(
2058 &DriverBootReinitListHead,
2059 &ReinitItem->ItemEntry,
2060 &DriverReinitListLock);
2061 }
2062
2063 /*
2064 * IoAllocateDriverObjectExtension
2065 *
2066 * Status
2067 * @implemented
2068 */
2069
2070 NTSTATUS STDCALL
2071 IoAllocateDriverObjectExtension(
2072 PDRIVER_OBJECT DriverObject,
2073 PVOID ClientIdentificationAddress,
2074 ULONG DriverObjectExtensionSize,
2075 PVOID *DriverObjectExtension)
2076 {
2077 KIRQL OldIrql;
2078 PPRIVATE_DRIVER_EXTENSIONS DriverExtensions;
2079 PPRIVATE_DRIVER_EXTENSIONS NewDriverExtension;
2080
2081 NewDriverExtension = ExAllocatePoolWithTag(
2082 NonPagedPool,
2083 sizeof(PRIVATE_DRIVER_EXTENSIONS) - sizeof(CHAR) +
2084 DriverObjectExtensionSize,
2085 TAG_DRIVER_EXTENSION);
2086
2087 if (NewDriverExtension == NULL)
2088 {
2089 return STATUS_INSUFFICIENT_RESOURCES;
2090 }
2091
2092 OldIrql = KeRaiseIrqlToDpcLevel();
2093
2094 NewDriverExtension->Link = DriverObject->DriverSection;
2095 NewDriverExtension->ClientIdentificationAddress = ClientIdentificationAddress;
2096
2097 for (DriverExtensions = DriverObject->DriverSection;
2098 DriverExtensions != NULL;
2099 DriverExtensions = DriverExtensions->Link)
2100 {
2101 if (DriverExtensions->ClientIdentificationAddress ==
2102 ClientIdentificationAddress)
2103 {
2104 KfLowerIrql(OldIrql);
2105 return STATUS_OBJECT_NAME_COLLISION;
2106 }
2107 }
2108
2109 DriverObject->DriverSection = NewDriverExtension;
2110
2111 KfLowerIrql(OldIrql);
2112
2113 *DriverObjectExtension = &NewDriverExtension->Extension;
2114
2115 return STATUS_SUCCESS;
2116 }
2117
2118 /*
2119 * IoGetDriverObjectExtension
2120 *
2121 * Status
2122 * @implemented
2123 */
2124
2125 PVOID STDCALL
2126 IoGetDriverObjectExtension(
2127 PDRIVER_OBJECT DriverObject,
2128 PVOID ClientIdentificationAddress)
2129 {
2130 KIRQL OldIrql;
2131 PPRIVATE_DRIVER_EXTENSIONS DriverExtensions;
2132
2133 OldIrql = KeRaiseIrqlToDpcLevel();
2134
2135 for (DriverExtensions = DriverObject->DriverSection;
2136 DriverExtensions != NULL &&
2137 DriverExtensions->ClientIdentificationAddress !=
2138 ClientIdentificationAddress;
2139 DriverExtensions = DriverExtensions->Link)
2140 ;
2141
2142 KfLowerIrql(OldIrql);
2143
2144 if (DriverExtensions == NULL)
2145 return NULL;
2146
2147 return &DriverExtensions->Extension;
2148 }
2149
2150 /* EOF */