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