7cab4e639112866a1a38fcc4db705492d2c2dce2
[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 = InternalDriverType;
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 0x10001,
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
1256 MiFreeBootDriverMemory((PVOID)KeLoaderModules[i].ModStart,
1257 KeLoaderModules[i].ModEnd - KeLoaderModules[i].ModStart);
1258 }
1259
1260 if (BootDriverCount == 0)
1261 {
1262 DbgPrint("No boot drivers available.\n");
1263 KEBUGCHECK(0);
1264 }
1265 }
1266
1267 static INIT_FUNCTION NTSTATUS
1268 IopLoadDriver(PSERVICE Service)
1269 {
1270 NTSTATUS Status = STATUS_UNSUCCESSFUL;
1271
1272 IopDisplayLoadingMessage(Service->ServiceName.Buffer);
1273 Status = ZwLoadDriver(&Service->RegistryPath);
1274 IopBootLog(&Service->ImagePath, NT_SUCCESS(Status) ? TRUE : FALSE);
1275 if (!NT_SUCCESS(Status))
1276 {
1277 DPRINT("NtLoadDriver() failed (Status %lx)\n", Status);
1278 #if 0
1279 if (Service->ErrorControl == 1)
1280 {
1281 /* Log error */
1282 }
1283 else if (Service->ErrorControl == 2)
1284 {
1285 if (IsLastKnownGood == FALSE)
1286 {
1287 /* Boot last known good configuration */
1288 }
1289 }
1290 else if (Service->ErrorControl == 3)
1291 {
1292 if (IsLastKnownGood == FALSE)
1293 {
1294 /* Boot last known good configuration */
1295 }
1296 else
1297 {
1298 /* BSOD! */
1299 }
1300 }
1301 #endif
1302 }
1303 return Status;
1304 }
1305
1306
1307 /*
1308 * IopInitializeSystemDrivers
1309 *
1310 * Load drivers marked as system start.
1311 *
1312 * Parameters
1313 * None
1314 *
1315 * Return Value
1316 * None
1317 */
1318
1319 VOID FASTCALL
1320 IopInitializeSystemDrivers(VOID)
1321 {
1322 PLIST_ENTRY GroupEntry;
1323 PLIST_ENTRY ServiceEntry;
1324 PSERVICE_GROUP CurrentGroup;
1325 PSERVICE CurrentService;
1326 NTSTATUS Status;
1327 ULONG i;
1328
1329 DPRINT("IopInitializeSystemDrivers()\n");
1330
1331 GroupEntry = GroupListHead.Flink;
1332 while (GroupEntry != &GroupListHead)
1333 {
1334 CurrentGroup = CONTAINING_RECORD(GroupEntry, SERVICE_GROUP, GroupListEntry);
1335
1336 DPRINT("Group: %wZ\n", &CurrentGroup->GroupName);
1337
1338 /* Load all drivers with a valid tag */
1339 for (i = 0; i < CurrentGroup->TagCount; i++)
1340 {
1341 ServiceEntry = ServiceListHead.Flink;
1342 while (ServiceEntry != &ServiceListHead)
1343 {
1344 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
1345
1346 if ((RtlCompareUnicodeString(&CurrentGroup->GroupName,
1347 &CurrentService->ServiceGroup, TRUE) == 0) &&
1348 (CurrentService->Start == 1 /*SERVICE_SYSTEM_START*/) &&
1349 (CurrentService->Tag == CurrentGroup->TagArray[i]))
1350 {
1351 DPRINT(" Path: %wZ\n", &CurrentService->RegistryPath);
1352 Status = IopLoadDriver(CurrentService);
1353 }
1354 ServiceEntry = ServiceEntry->Flink;
1355 }
1356 }
1357
1358 /* Load all drivers without a tag or with an invalid tag */
1359 ServiceEntry = ServiceListHead.Flink;
1360 while (ServiceEntry != &ServiceListHead)
1361 {
1362 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
1363 if ((RtlCompareUnicodeString(&CurrentGroup->GroupName,
1364 &CurrentService->ServiceGroup, TRUE) == 0) &&
1365 (CurrentService->Start == 1 /*SERVICE_SYSTEM_START*/))
1366 {
1367 for (i = 0; i < CurrentGroup->TagCount; i++)
1368 {
1369 if (CurrentGroup->TagArray[i] == CurrentService->Tag)
1370 {
1371 break;
1372 }
1373 }
1374 if (i >= CurrentGroup->TagCount)
1375 {
1376 DPRINT(" Path: %wZ\n", &CurrentService->RegistryPath);
1377 Status = IopLoadDriver(CurrentService);
1378 }
1379 }
1380 ServiceEntry = ServiceEntry->Flink;
1381 }
1382
1383 GroupEntry = GroupEntry->Flink;
1384 }
1385
1386 DPRINT("IopInitializeSystemDrivers() done\n");
1387 }
1388
1389 /*
1390 * IopUnloadDriver
1391 *
1392 * Unloads a device driver.
1393 *
1394 * Parameters
1395 * DriverServiceName
1396 * Name of the service to unload (registry key).
1397 *
1398 * UnloadPnpDrivers
1399 * Whether to unload Plug & Plug or only legacy drivers. If this
1400 * parameter is set to FALSE, the routine will unload only legacy
1401 * drivers.
1402 *
1403 * Return Value
1404 * Status
1405 *
1406 * To do
1407 * Guard the whole function by SEH.
1408 */
1409
1410 NTSTATUS STDCALL
1411 IopUnloadDriver(PUNICODE_STRING DriverServiceName, BOOLEAN UnloadPnpDrivers)
1412 {
1413 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
1414 UNICODE_STRING ImagePath;
1415 UNICODE_STRING ServiceName;
1416 UNICODE_STRING ObjectName;
1417 PDRIVER_OBJECT DriverObject;
1418 PMODULE_OBJECT ModuleObject;
1419 NTSTATUS Status;
1420 LPWSTR Start;
1421
1422 DPRINT("IopUnloadDriver('%wZ', %d)\n", DriverServiceName, UnloadPnpDrivers);
1423
1424 /*
1425 * Get the service name from the registry key name
1426 */
1427
1428 Start = wcsrchr(DriverServiceName->Buffer, L'\\');
1429 if (Start == NULL)
1430 Start = DriverServiceName->Buffer;
1431 else
1432 Start++;
1433
1434 RtlInitUnicodeString(&ServiceName, Start);
1435
1436 /*
1437 * Construct the driver object name
1438 */
1439
1440 ObjectName.Length = (wcslen(Start) + 8) * sizeof(WCHAR);
1441 ObjectName.MaximumLength = ObjectName.Length + sizeof(WCHAR);
1442 ObjectName.Buffer = ExAllocatePool(NonPagedPool, ObjectName.MaximumLength);
1443 wcscpy(ObjectName.Buffer, L"\\Driver\\");
1444 memcpy(ObjectName.Buffer + 8, Start, (ObjectName.Length - 8) * sizeof(WCHAR));
1445 ObjectName.Buffer[ObjectName.Length/sizeof(WCHAR)] = 0;
1446
1447 /*
1448 * Find the driver object
1449 */
1450
1451 Status = ObReferenceObjectByName(&ObjectName, 0, 0, 0, IoDriverObjectType,
1452 KernelMode, 0, (PVOID*)&DriverObject);
1453
1454 if (!NT_SUCCESS(Status))
1455 {
1456 DPRINT("Can't locate driver object for %wZ\n", ObjectName);
1457 return Status;
1458 }
1459
1460 /*
1461 * Free the buffer for driver object name
1462 */
1463
1464 ExFreePool(ObjectName.Buffer);
1465
1466 /*
1467 * Get path of service...
1468 */
1469
1470 RtlZeroMemory(QueryTable, sizeof(QueryTable));
1471
1472 RtlInitUnicodeString(&ImagePath, NULL);
1473
1474 QueryTable[0].Name = L"ImagePath";
1475 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
1476 QueryTable[0].EntryContext = &ImagePath;
1477
1478 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
1479 DriverServiceName->Buffer, QueryTable, NULL, NULL);
1480
1481 if (!NT_SUCCESS(Status))
1482 {
1483 DPRINT("RtlQueryRegistryValues() failed (Status %x)\n", Status);
1484 return Status;
1485 }
1486
1487 /*
1488 * Normalize the image path for all later processing.
1489 */
1490
1491 Status = IopNormalizeImagePath(&ImagePath, &ServiceName);
1492
1493 if (!NT_SUCCESS(Status))
1494 {
1495 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status);
1496 return Status;
1497 }
1498
1499 /*
1500 * ... and check if it's loaded
1501 */
1502
1503 ModuleObject = LdrGetModuleObject(&ImagePath);
1504 if (ModuleObject == NULL)
1505 {
1506 return STATUS_UNSUCCESSFUL;
1507 }
1508
1509 /*
1510 * Free the service path
1511 */
1512
1513 RtlFreeUnicodeString(&ImagePath);
1514
1515 /*
1516 * Unload the module and release the references to the device object
1517 */
1518
1519 if (DriverObject->DriverUnload)
1520 (*DriverObject->DriverUnload)(DriverObject);
1521 ObDereferenceObject(DriverObject);
1522 ObDereferenceObject(DriverObject);
1523 LdrUnloadModule(ModuleObject);
1524
1525 return STATUS_SUCCESS;
1526 }
1527
1528 VOID FASTCALL
1529 IopMarkLastReinitializeDriver(VOID)
1530 {
1531 KIRQL Irql;
1532
1533 KeAcquireSpinLock(&DriverReinitListLock,
1534 &Irql);
1535
1536 if (IsListEmpty(&DriverReinitListHead))
1537 {
1538 DriverReinitTailEntry = NULL;
1539 }
1540 else
1541 {
1542 DriverReinitTailEntry = DriverReinitListHead.Blink;
1543 }
1544
1545 KeReleaseSpinLock(&DriverReinitListLock,
1546 Irql);
1547 }
1548
1549
1550 VOID FASTCALL
1551 IopReinitializeDrivers(VOID)
1552 {
1553 PDRIVER_REINIT_ITEM ReinitItem;
1554 PLIST_ENTRY Entry;
1555 KIRQL Irql;
1556
1557 KeAcquireSpinLock(&DriverReinitListLock,
1558 &Irql);
1559
1560 if (DriverReinitTailEntry == NULL)
1561 {
1562 KeReleaseSpinLock(&DriverReinitListLock,
1563 Irql);
1564 return;
1565 }
1566
1567 KeReleaseSpinLock(&DriverReinitListLock,
1568 Irql);
1569
1570 for (;;)
1571 {
1572 Entry = ExInterlockedRemoveHeadList(&DriverReinitListHead,
1573 &DriverReinitListLock);
1574 if (Entry == NULL)
1575 return;
1576
1577 ReinitItem = (PDRIVER_REINIT_ITEM)CONTAINING_RECORD(Entry, DRIVER_REINIT_ITEM, ItemEntry);
1578
1579 /* Increment reinitialization counter */
1580 ReinitItem->DriverObject->DriverExtension->Count++;
1581
1582 ReinitItem->ReinitRoutine(ReinitItem->DriverObject,
1583 ReinitItem->Context,
1584 ReinitItem->DriverObject->DriverExtension->Count);
1585
1586 ExFreePool(Entry);
1587
1588 if (Entry == DriverReinitTailEntry)
1589 return;
1590 }
1591 }
1592
1593 /* PUBLIC FUNCTIONS ***********************************************************/
1594
1595
1596 /*
1597 * @implemented
1598 */
1599 NTSTATUS
1600 STDCALL
1601 IoCreateDriver (
1602 IN PUNICODE_STRING DriverName, OPTIONAL
1603 IN PDRIVER_INITIALIZE InitializationFunction
1604 )
1605 {
1606 WCHAR NameBuffer[100];
1607 USHORT NameLength;
1608 UNICODE_STRING LocalDriverName; /* To reduce code if no name given */
1609 NTSTATUS Status;
1610 OBJECT_ATTRIBUTES ObjectAttributes;
1611 ULONG ObjectSize;
1612 PDRIVER_OBJECT DriverObject;
1613 UNICODE_STRING ServiceKeyName;
1614 HANDLE hDriver;
1615
1616 /* First, create a unique name for the driver if we don't have one */
1617 if (!DriverName) {
1618
1619 /* Create a random name and set up the string*/
1620 NameLength = swprintf(NameBuffer, L"\\Driver\\%08u", KeTickCount);
1621 LocalDriverName.Length = NameLength * sizeof(WCHAR);
1622 LocalDriverName.MaximumLength = LocalDriverName.Length + sizeof(UNICODE_NULL);
1623 LocalDriverName.Buffer = NameBuffer;
1624
1625 } else {
1626
1627 /* So we can avoid another code path, use a local var */
1628 LocalDriverName = *DriverName;
1629 }
1630
1631 /* Initialize the Attributes */
1632 ObjectSize = sizeof(DRIVER_OBJECT) + sizeof(DRIVER_EXTENSION);
1633 InitializeObjectAttributes(&ObjectAttributes,
1634 &LocalDriverName,
1635 OBJ_PERMANENT | OBJ_CASE_INSENSITIVE,
1636 NULL,
1637 NULL);
1638
1639 /* Create the Object */
1640 Status = ObCreateObject(KernelMode,
1641 IoDriverObjectType,
1642 &ObjectAttributes,
1643 KernelMode,
1644 NULL,
1645 ObjectSize,
1646 0,
1647 0,
1648 (PVOID*)&DriverObject);
1649
1650 /* Return on failure */
1651 if (!NT_SUCCESS(Status)) return Status;
1652
1653 /* Set up the Object */
1654 RtlZeroMemory(DriverObject, ObjectSize);
1655 DriverObject->Type = IO_TYPE_DRIVER;
1656 DriverObject->Size = sizeof(DRIVER_OBJECT);
1657 DriverObject->Flags = DRVO_BUILTIN_DRIVER;
1658 DriverObject->DriverExtension = (PDRIVER_EXTENSION)(DriverObject + 1);
1659 DriverObject->DriverExtension->DriverObject = DriverObject;
1660 DriverObject->DriverInit = InitializationFunction;
1661 /* FIXME: Invalidate all Major Functions b/c now they are NULL and might crash */
1662
1663 /* Set up the Service Key Name */
1664 ServiceKeyName.Buffer = ExAllocatePool(PagedPool, LocalDriverName.Length + sizeof(WCHAR));
1665 ServiceKeyName.Length = LocalDriverName.Length;
1666 ServiceKeyName.MaximumLength = LocalDriverName.MaximumLength;
1667 RtlMoveMemory(ServiceKeyName.Buffer, LocalDriverName.Buffer, LocalDriverName.Length);
1668 ServiceKeyName.Buffer[ServiceKeyName.Length / sizeof(WCHAR)] = L'\0';
1669 DriverObject->DriverExtension->ServiceKeyName = ServiceKeyName;
1670
1671 /* Also store it in the Driver Object. This is a bit of a hack. */
1672 RtlMoveMemory(&DriverObject->DriverName, &ServiceKeyName, sizeof(UNICODE_STRING));
1673
1674 /* Add the Object and get its handle */
1675 Status = ObInsertObject(DriverObject,
1676 NULL,
1677 FILE_READ_DATA,
1678 0,
1679 NULL,
1680 &hDriver);
1681
1682 /* Return on Failure */
1683 if (!NT_SUCCESS(Status)) return Status;
1684
1685 /* Now reference it */
1686 Status = ObReferenceObjectByHandle(hDriver,
1687 0,
1688 IoDriverObjectType,
1689 KernelMode,
1690 (PVOID*)&DriverObject,
1691 NULL);
1692 ZwClose(hDriver);
1693
1694 /* Finally, call its init function */
1695 Status = (*InitializationFunction)(DriverObject, NULL);
1696
1697 if (!NT_SUCCESS(Status)) {
1698 /* If it didn't work, then kill the object */
1699 ObMakeTemporaryObject(DriverObject);
1700 ObDereferenceObject(DriverObject);
1701 }
1702
1703 /* Return the Status */
1704 return Status;
1705 }
1706
1707 /*
1708 * @implemented
1709 */
1710 VOID
1711 STDCALL
1712 IoDeleteDriver (
1713 IN PDRIVER_OBJECT DriverObject
1714 )
1715 {
1716 /* Simply derefence the Object */
1717 ObDereferenceObject(DriverObject);
1718 }
1719
1720
1721 /*
1722 * NtLoadDriver
1723 *
1724 * Loads a device driver.
1725 *
1726 * Parameters
1727 * DriverServiceName
1728 * Name of the service to load (registry key).
1729 *
1730 * Return Value
1731 * Status
1732 *
1733 * Status
1734 * implemented
1735 */
1736
1737 NTSTATUS STDCALL
1738 NtLoadDriver(IN PUNICODE_STRING DriverServiceName)
1739 {
1740 RTL_QUERY_REGISTRY_TABLE QueryTable[3];
1741 UNICODE_STRING ImagePath;
1742 UNICODE_STRING ServiceName;
1743 NTSTATUS Status;
1744 ULONG Type;
1745 PDEVICE_NODE DeviceNode;
1746 PMODULE_OBJECT ModuleObject;
1747 PDRIVER_OBJECT DriverObject;
1748 LPWSTR Start;
1749
1750 DPRINT("NtLoadDriver('%wZ')\n", DriverServiceName);
1751
1752 /*
1753 * Check security privileges
1754 */
1755
1756 /* FIXME: Uncomment when privileges will be correctly implemented. */
1757 #if 0
1758 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, KeGetPreviousMode()))
1759 {
1760 DPRINT("Privilege not held\n");
1761 return STATUS_PRIVILEGE_NOT_HELD;
1762 }
1763 #endif
1764
1765 RtlInitUnicodeString(&ImagePath, NULL);
1766
1767 /*
1768 * Get the service name from the registry key name.
1769 */
1770
1771 Start = wcsrchr(DriverServiceName->Buffer, L'\\');
1772 if (Start == NULL)
1773 Start = DriverServiceName->Buffer;
1774 else
1775 Start++;
1776
1777 RtlInitUnicodeString(&ServiceName, Start);
1778
1779 /*
1780 * Get service type.
1781 */
1782
1783 RtlZeroMemory(&QueryTable, sizeof(QueryTable));
1784
1785 RtlInitUnicodeString(&ImagePath, NULL);
1786
1787 QueryTable[0].Name = L"Type";
1788 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
1789 QueryTable[0].EntryContext = &Type;
1790
1791 QueryTable[1].Name = L"ImagePath";
1792 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
1793 QueryTable[1].EntryContext = &ImagePath;
1794
1795 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
1796 DriverServiceName->Buffer, QueryTable, NULL, NULL);
1797
1798 if (!NT_SUCCESS(Status))
1799 {
1800 DPRINT("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
1801 RtlFreeUnicodeString(&ImagePath);
1802 return Status;
1803 }
1804
1805 /*
1806 * Normalize the image path for all later processing.
1807 */
1808
1809 Status = IopNormalizeImagePath(&ImagePath, &ServiceName);
1810
1811 if (!NT_SUCCESS(Status))
1812 {
1813 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status);
1814 return Status;
1815 }
1816
1817 DPRINT("FullImagePath: '%S'\n", ImagePath.Buffer);
1818 DPRINT("Type: %lx\n", Type);
1819
1820 /*
1821 * See, if the driver module isn't already loaded
1822 */
1823
1824 ModuleObject = LdrGetModuleObject(&ImagePath);
1825 if (ModuleObject != NULL)
1826 {
1827 DPRINT("Image already loaded\n");
1828 return STATUS_IMAGE_ALREADY_LOADED;
1829 }
1830
1831 /*
1832 * Create device node
1833 */
1834
1835 /* Use IopRootDeviceNode for now */
1836 Status = IopCreateDeviceNode(IopRootDeviceNode, NULL, &DeviceNode);
1837
1838 if (!NT_SUCCESS(Status))
1839 {
1840 DPRINT("IopCreateDeviceNode() failed (Status %lx)\n", Status);
1841 return Status;
1842 }
1843
1844 /*
1845 * Load the driver module
1846 */
1847
1848 Status = LdrLoadModule(&ImagePath, &ModuleObject);
1849
1850 if (!NT_SUCCESS(Status))
1851 {
1852 DPRINT("LdrLoadModule() failed (Status %lx)\n", Status);
1853 IopFreeDeviceNode(DeviceNode);
1854 return Status;
1855 }
1856
1857 /*
1858 * Set a service name for the device node
1859 */
1860
1861 Start = wcsrchr(DriverServiceName->Buffer, L'\\');
1862 if (Start == NULL)
1863 Start = DriverServiceName->Buffer;
1864 else
1865 Start++;
1866 RtlpCreateUnicodeString(&DeviceNode->ServiceName, Start, NonPagedPool);
1867
1868 /*
1869 * Initialize the driver module
1870 */
1871
1872 Status = IopInitializeDriverModule(
1873 DeviceNode,
1874 ModuleObject,
1875 (Type == 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
1876 Type == 8 /* SERVICE_RECOGNIZER_DRIVER */),
1877 &DriverObject);
1878
1879 if (!NT_SUCCESS(Status))
1880 {
1881 DPRINT("IopInitializeDriver() failed (Status %lx)\n", Status);
1882 LdrUnloadModule(ModuleObject);
1883 IopFreeDeviceNode(DeviceNode);
1884 return Status;
1885 }
1886
1887 IopInitializeDevice(DeviceNode, DriverObject);
1888
1889 return Status;
1890 }
1891
1892 /*
1893 * NtUnloadDriver
1894 *
1895 * Unloads a legacy device driver.
1896 *
1897 * Parameters
1898 * DriverServiceName
1899 * Name of the service to unload (registry key).
1900 *
1901 * Return Value
1902 * Status
1903 *
1904 * Status
1905 * implemented
1906 */
1907
1908 NTSTATUS STDCALL
1909 NtUnloadDriver(IN PUNICODE_STRING DriverServiceName)
1910 {
1911 return IopUnloadDriver(DriverServiceName, FALSE);
1912 }
1913
1914 /*
1915 * IoRegisterDriverReinitialization
1916 *
1917 * Status
1918 * @implemented
1919 */
1920
1921 VOID STDCALL
1922 IoRegisterDriverReinitialization(
1923 PDRIVER_OBJECT DriverObject,
1924 PDRIVER_REINITIALIZE ReinitRoutine,
1925 PVOID Context)
1926 {
1927 PDRIVER_REINIT_ITEM ReinitItem;
1928
1929 ReinitItem = ExAllocatePool(NonPagedPool, sizeof(DRIVER_REINIT_ITEM));
1930 if (ReinitItem == NULL)
1931 return;
1932
1933 ReinitItem->DriverObject = DriverObject;
1934 ReinitItem->ReinitRoutine = ReinitRoutine;
1935 ReinitItem->Context = Context;
1936
1937 ExInterlockedInsertTailList(
1938 &DriverReinitListHead,
1939 &ReinitItem->ItemEntry,
1940 &DriverReinitListLock);
1941 }
1942
1943 /*
1944 * IoAllocateDriverObjectExtension
1945 *
1946 * Status
1947 * @implemented
1948 */
1949
1950 NTSTATUS STDCALL
1951 IoAllocateDriverObjectExtension(
1952 PDRIVER_OBJECT DriverObject,
1953 PVOID ClientIdentificationAddress,
1954 ULONG DriverObjectExtensionSize,
1955 PVOID *DriverObjectExtension)
1956 {
1957 KIRQL OldIrql;
1958 PPRIVATE_DRIVER_EXTENSIONS DriverExtensions;
1959 PPRIVATE_DRIVER_EXTENSIONS NewDriverExtension;
1960
1961 NewDriverExtension = ExAllocatePoolWithTag(
1962 NonPagedPool,
1963 sizeof(PRIVATE_DRIVER_EXTENSIONS) - sizeof(CHAR) +
1964 DriverObjectExtensionSize,
1965 TAG_DRIVER_EXTENSION);
1966
1967 if (NewDriverExtension == NULL)
1968 {
1969 return STATUS_INSUFFICIENT_RESOURCES;
1970 }
1971
1972 OldIrql = KeRaiseIrqlToDpcLevel();
1973
1974 NewDriverExtension->Link = DriverObject->DriverSection;
1975 NewDriverExtension->ClientIdentificationAddress = ClientIdentificationAddress;
1976
1977 for (DriverExtensions = DriverObject->DriverSection;
1978 DriverExtensions != NULL;
1979 DriverExtensions = DriverExtensions->Link)
1980 {
1981 if (DriverExtensions->ClientIdentificationAddress ==
1982 ClientIdentificationAddress)
1983 {
1984 KfLowerIrql(OldIrql);
1985 return STATUS_OBJECT_NAME_COLLISION;
1986 }
1987 }
1988
1989 DriverObject->DriverSection = NewDriverExtension;
1990
1991 KfLowerIrql(OldIrql);
1992
1993 *DriverObjectExtension = &NewDriverExtension->Extension;
1994
1995 return STATUS_SUCCESS;
1996 }
1997
1998 /*
1999 * IoGetDriverObjectExtension
2000 *
2001 * Status
2002 * @implemented
2003 */
2004
2005 PVOID STDCALL
2006 IoGetDriverObjectExtension(
2007 PDRIVER_OBJECT DriverObject,
2008 PVOID ClientIdentificationAddress)
2009 {
2010 KIRQL OldIrql;
2011 PPRIVATE_DRIVER_EXTENSIONS DriverExtensions;
2012
2013 OldIrql = KeRaiseIrqlToDpcLevel();
2014
2015 for (DriverExtensions = DriverObject->DriverSection;
2016 DriverExtensions != NULL &&
2017 DriverExtensions->ClientIdentificationAddress !=
2018 ClientIdentificationAddress;
2019 DriverExtensions = DriverExtensions->Link)
2020 ;
2021
2022 KfLowerIrql(OldIrql);
2023
2024 if (DriverExtensions == NULL)
2025 return NULL;
2026
2027 return &DriverExtensions->Extension;
2028 }
2029
2030 /* EOF */