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