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