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