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