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