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