[NTOS]: Rewrite boot driver loading code (not the driver code itself) to use the...
[reactos.git] / reactos / ntoskrnl / io / iomgr / driver.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/iomgr/driver.c
5 * PURPOSE: Driver Object Management
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Filip Navara (navaraf@reactos.org)
8 * Hervé Poussineau (hpoussin@reactos.org)
9 */
10
11 /* INCLUDES *******************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <debug.h>
16
17 /* GLOBALS ********************************************************************/
18
19 LIST_ENTRY DriverReinitListHead;
20 KSPIN_LOCK DriverReinitListLock;
21 PLIST_ENTRY DriverReinitTailEntry;
22
23 PLIST_ENTRY DriverBootReinitTailEntry;
24 LIST_ENTRY DriverBootReinitListHead;
25 KSPIN_LOCK DriverBootReinitListLock;
26
27 UNICODE_STRING IopHardwareDatabaseKey =
28 RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\HARDWARE\\DESCRIPTION\\SYSTEM");
29
30 POBJECT_TYPE IoDriverObjectType = NULL;
31
32 #define TAG_RTLREGISTRY 'vrqR'
33
34 extern BOOLEAN ExpInTextModeSetup;
35 extern BOOLEAN PnpSystemInit;
36
37 USHORT IopGroupIndex;
38 PLIST_ENTRY IopGroupTable;
39
40 /* PRIVATE FUNCTIONS **********************************************************/
41
42 NTSTATUS NTAPI
43 IopInvalidDeviceRequest(
44 PDEVICE_OBJECT DeviceObject,
45 PIRP Irp)
46 {
47 Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
48 Irp->IoStatus.Information = 0;
49 IoCompleteRequest(Irp, IO_NO_INCREMENT);
50 return STATUS_INVALID_DEVICE_REQUEST;
51 }
52
53 VOID
54 NTAPI
55 IopDeleteDriver(IN PVOID ObjectBody)
56 {
57 PDRIVER_OBJECT DriverObject = ObjectBody;
58 PIO_CLIENT_EXTENSION DriverExtension, NextDriverExtension;
59 PAGED_CODE();
60
61 /* Get the extension and loop them */
62 DriverExtension = IoGetDrvObjExtension(DriverObject)->
63 ClientDriverExtension;
64 while (DriverExtension)
65 {
66 /* Get the next one */
67 NextDriverExtension = DriverExtension->NextExtension;
68 ExFreePoolWithTag(DriverExtension, TAG_DRIVER_EXTENSION);
69
70 /* Move on */
71 DriverExtension = NextDriverExtension;
72 }
73
74 /* Check if the driver image is still loaded */
75 if (DriverObject->DriverSection)
76 {
77 /* Unload it */
78 MmUnloadSystemImage(DriverObject->DriverSection);
79 }
80
81 /* Check if it has a name */
82 if (DriverObject->DriverName.Buffer)
83 {
84 /* Free it */
85 ExFreePool(DriverObject->DriverName.Buffer);
86 }
87
88 #if 0 /* See a bit of hack in IopCreateDriver */
89 /* Check if it has a service key name */
90 if (DriverObject->DriverExtension->ServiceKeyName.Buffer)
91 {
92 /* Free it */
93 ExFreePool(DriverObject->DriverExtension->ServiceKeyName.Buffer);
94 }
95 #endif
96 }
97
98 NTSTATUS FASTCALL
99 IopGetDriverObject(
100 PDRIVER_OBJECT *DriverObject,
101 PUNICODE_STRING ServiceName,
102 BOOLEAN FileSystem)
103 {
104 PDRIVER_OBJECT Object;
105 WCHAR NameBuffer[MAX_PATH];
106 UNICODE_STRING DriverName;
107 NTSTATUS Status;
108
109 DPRINT("IopGetDriverObject(%p '%wZ' %x)\n",
110 DriverObject, ServiceName, FileSystem);
111
112 *DriverObject = NULL;
113
114 /* Create ModuleName string */
115 if (ServiceName == NULL || ServiceName->Buffer == NULL)
116 /* We don't know which DriverObject we have to open */
117 return STATUS_INVALID_PARAMETER_2;
118
119 DriverName.Buffer = NameBuffer;
120 DriverName.Length = 0;
121 DriverName.MaximumLength = sizeof(NameBuffer);
122
123 if (FileSystem == TRUE)
124 RtlAppendUnicodeToString(&DriverName, FILESYSTEM_ROOT_NAME);
125 else
126 RtlAppendUnicodeToString(&DriverName, DRIVER_ROOT_NAME);
127 RtlAppendUnicodeStringToString(&DriverName, ServiceName);
128
129 DPRINT("Driver name: '%wZ'\n", &DriverName);
130
131 /* Open driver object */
132 Status = ObReferenceObjectByName(
133 &DriverName,
134 OBJ_OPENIF | OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, /* Attributes */
135 NULL, /* PassedAccessState */
136 0, /* DesiredAccess */
137 IoDriverObjectType,
138 KernelMode,
139 NULL, /* ParseContext */
140 (PVOID*)&Object);
141
142 if (!NT_SUCCESS(Status))
143 {
144 DPRINT("Failed to reference driver object, status=0x%08x\n", Status);
145 return Status;
146 }
147
148 *DriverObject = Object;
149
150 DPRINT("Driver Object: %p\n", Object);
151
152 return STATUS_SUCCESS;
153 }
154
155 /*
156 * RETURNS
157 * TRUE if String2 contains String1 as a suffix.
158 */
159 BOOLEAN
160 NTAPI
161 IopSuffixUnicodeString(
162 IN PCUNICODE_STRING String1,
163 IN PCUNICODE_STRING String2)
164 {
165 PWCHAR pc1;
166 PWCHAR pc2;
167 ULONG Length;
168
169 if (String2->Length < String1->Length)
170 return FALSE;
171
172 Length = String1->Length / 2;
173 pc1 = String1->Buffer;
174 pc2 = &String2->Buffer[String2->Length / sizeof(WCHAR) - Length];
175
176 if (pc1 && pc2)
177 {
178 while (Length--)
179 {
180 if( *pc1++ != *pc2++ )
181 return FALSE;
182 }
183 return TRUE;
184 }
185 return FALSE;
186 }
187
188 /*
189 * IopDisplayLoadingMessage
190 *
191 * Display 'Loading XXX...' message.
192 */
193
194 VOID
195 FASTCALL
196 INIT_FUNCTION
197 IopDisplayLoadingMessage(PUNICODE_STRING ServiceName)
198 {
199 CHAR TextBuffer[256];
200 UNICODE_STRING DotSys = RTL_CONSTANT_STRING(L".SYS");
201
202 if (ExpInTextModeSetup) return;
203 RtlUpcaseUnicodeString(ServiceName, ServiceName, FALSE);
204 snprintf(TextBuffer, sizeof(TextBuffer),
205 "%s%sSystem32\\Drivers\\%wZ%s\n",
206 KeLoaderBlock->ArcBootDeviceName,
207 KeLoaderBlock->NtBootPathName,
208 ServiceName,
209 IopSuffixUnicodeString(&DotSys, ServiceName) ? "" : ".SYS");
210 HalDisplayString(TextBuffer);
211 }
212
213 /*
214 * IopNormalizeImagePath
215 *
216 * Normalize an image path to contain complete path.
217 *
218 * Parameters
219 * ImagePath
220 * The input path and on exit the result path. ImagePath.Buffer
221 * must be allocated by ExAllocatePool on input. Caller is responsible
222 * for freeing the buffer when it's no longer needed.
223 *
224 * ServiceName
225 * Name of the service that ImagePath belongs to.
226 *
227 * Return Value
228 * Status
229 *
230 * Remarks
231 * The input image path isn't freed on error.
232 */
233
234 NTSTATUS FASTCALL
235 IopNormalizeImagePath(
236 IN OUT PUNICODE_STRING ImagePath,
237 IN PUNICODE_STRING ServiceName)
238 {
239 UNICODE_STRING InputImagePath;
240
241 RtlCopyMemory(
242 &InputImagePath,
243 ImagePath,
244 sizeof(UNICODE_STRING));
245
246 if (InputImagePath.Length == 0)
247 {
248 ImagePath->Length = 0;
249 ImagePath->MaximumLength =
250 (33 * sizeof(WCHAR)) + ServiceName->Length + sizeof(UNICODE_NULL);
251 ImagePath->Buffer = ExAllocatePool(NonPagedPool, ImagePath->MaximumLength);
252 if (ImagePath->Buffer == NULL)
253 return STATUS_NO_MEMORY;
254
255 RtlAppendUnicodeToString(ImagePath, L"\\SystemRoot\\system32\\drivers\\");
256 RtlAppendUnicodeStringToString(ImagePath, ServiceName);
257 RtlAppendUnicodeToString(ImagePath, L".sys");
258 } else
259 if (InputImagePath.Buffer[0] != L'\\')
260 {
261 ImagePath->Length = 0;
262 ImagePath->MaximumLength =
263 12 * sizeof(WCHAR) + InputImagePath.Length + sizeof(UNICODE_NULL);
264 ImagePath->Buffer = ExAllocatePool(NonPagedPool, ImagePath->MaximumLength);
265 if (ImagePath->Buffer == NULL)
266 return STATUS_NO_MEMORY;
267
268 RtlAppendUnicodeToString(ImagePath, L"\\SystemRoot\\");
269 RtlAppendUnicodeStringToString(ImagePath, &InputImagePath);
270
271 /* Free caller's string */
272 ExFreePoolWithTag(InputImagePath.Buffer, TAG_RTLREGISTRY);
273 }
274
275 return STATUS_SUCCESS;
276 }
277
278 /*
279 * IopLoadServiceModule
280 *
281 * Load a module specified by registry settings for service.
282 *
283 * Parameters
284 * ServiceName
285 * Name of the service to load.
286 *
287 * Return Value
288 * Status
289 */
290
291 NTSTATUS FASTCALL
292 IopLoadServiceModule(
293 IN PUNICODE_STRING ServiceName,
294 OUT PLDR_DATA_TABLE_ENTRY *ModuleObject)
295 {
296 RTL_QUERY_REGISTRY_TABLE QueryTable[3];
297 ULONG ServiceStart;
298 UNICODE_STRING ServiceImagePath, CCSName;
299 NTSTATUS Status;
300 HANDLE CCSKey, ServiceKey;
301 PVOID BaseAddress;
302
303 DPRINT("IopLoadServiceModule(%wZ, 0x%p)\n", ServiceName, ModuleObject);
304
305 /* FIXME: This check may be removed once the bug is fixed */
306 if (ServiceName->Buffer == NULL)
307 {
308 DPRINT1("If you see this, please report to Fireball or hpoussin!\n");
309 return STATUS_UNSUCCESSFUL;
310 }
311
312 /* Open CurrentControlSet */
313 RtlInitUnicodeString(&CCSName,
314 L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services");
315 Status = IopOpenRegistryKeyEx(&CCSKey, NULL, &CCSName, KEY_READ);
316 if (!NT_SUCCESS(Status))
317 {
318 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status);
319 return Status;
320 }
321
322 /* Open service key */
323 Status = IopOpenRegistryKeyEx(&ServiceKey, CCSKey, ServiceName, KEY_READ);
324 if (!NT_SUCCESS(Status))
325 {
326 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status);
327 ZwClose(CCSKey);
328 return Status;
329 }
330
331 /*
332 * Get information about the service.
333 */
334
335 RtlZeroMemory(QueryTable, sizeof(QueryTable));
336
337 RtlInitUnicodeString(&ServiceImagePath, NULL);
338
339 QueryTable[0].Name = L"Start";
340 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
341 QueryTable[0].EntryContext = &ServiceStart;
342
343 QueryTable[1].Name = L"ImagePath";
344 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
345 QueryTable[1].EntryContext = &ServiceImagePath;
346
347 Status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
348 (PWSTR)ServiceKey, QueryTable, NULL, NULL);
349
350 ZwClose(ServiceKey);
351 ZwClose(CCSKey);
352
353 if (!NT_SUCCESS(Status))
354 {
355 DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status);
356 return Status;
357 }
358
359 /*
360 * Normalize the image path for all later processing.
361 */
362
363 Status = IopNormalizeImagePath(&ServiceImagePath, ServiceName);
364
365 if (!NT_SUCCESS(Status))
366 {
367 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status);
368 return Status;
369 }
370
371 /*
372 * Case for disabled drivers
373 */
374
375 if (ServiceStart >= 4)
376 {
377 /* FIXME: Check if it is the right status code */
378 Status = STATUS_PLUGPLAY_NO_DEVICE;
379 }
380 else
381 {
382 DPRINT("Loading module\n");
383 Status = MmLoadSystemImage(&ServiceImagePath, NULL, NULL, 0, (PVOID)ModuleObject, &BaseAddress);
384 }
385
386 ExFreePool(ServiceImagePath.Buffer);
387
388 /*
389 * Now check if the module was loaded successfully.
390 */
391
392 if (!NT_SUCCESS(Status))
393 {
394 DPRINT("Module loading failed (Status %x)\n", Status);
395 }
396
397 DPRINT("Module loading (Status %x)\n", Status);
398
399 return Status;
400 }
401
402 /*
403 * IopInitializeDriverModule
404 *
405 * Initalize a loaded driver.
406 *
407 * Parameters
408 * DeviceNode
409 * Pointer to device node.
410 *
411 * ModuleObject
412 * Module object representing the driver. It can be retrieve by
413 * IopLoadServiceModule.
414 *
415 * ServiceName
416 * Name of the service (as in registry).
417 *
418 * FileSystemDriver
419 * Set to TRUE for file system drivers.
420 *
421 * DriverObject
422 * On successful return this contains the driver object representing
423 * the loaded driver.
424 */
425
426 NTSTATUS FASTCALL
427 IopInitializeDriverModule(
428 IN PDEVICE_NODE DeviceNode,
429 IN PLDR_DATA_TABLE_ENTRY ModuleObject,
430 IN PUNICODE_STRING ServiceName,
431 IN BOOLEAN FileSystemDriver,
432 OUT PDRIVER_OBJECT *DriverObject)
433 {
434 const WCHAR ServicesKeyName[] = L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
435 WCHAR NameBuffer[MAX_PATH];
436 UNICODE_STRING DriverName;
437 UNICODE_STRING RegistryKey;
438 PDRIVER_INITIALIZE DriverEntry;
439 PDRIVER_OBJECT Driver;
440 PDEVICE_OBJECT DeviceObject;
441 NTSTATUS Status;
442
443 DriverEntry = ModuleObject->EntryPoint;
444
445 if (ServiceName != NULL && ServiceName->Length != 0)
446 {
447 RegistryKey.Length = 0;
448 RegistryKey.MaximumLength = sizeof(ServicesKeyName) + ServiceName->Length;
449 RegistryKey.Buffer = ExAllocatePool(PagedPool, RegistryKey.MaximumLength);
450 if (RegistryKey.Buffer == NULL)
451 {
452 return STATUS_INSUFFICIENT_RESOURCES;
453 }
454 RtlAppendUnicodeToString(&RegistryKey, ServicesKeyName);
455 RtlAppendUnicodeStringToString(&RegistryKey, ServiceName);
456 }
457 else
458 {
459 RtlInitUnicodeString(&RegistryKey, NULL);
460 }
461
462 /* Create ModuleName string */
463 if (ServiceName && ServiceName->Length > 0)
464 {
465 if (FileSystemDriver == TRUE)
466 wcscpy(NameBuffer, FILESYSTEM_ROOT_NAME);
467 else
468 wcscpy(NameBuffer, DRIVER_ROOT_NAME);
469
470 RtlInitUnicodeString(&DriverName, NameBuffer);
471 DriverName.MaximumLength = sizeof(NameBuffer);
472
473 RtlAppendUnicodeStringToString(&DriverName, ServiceName);
474
475 DPRINT("Driver name: '%wZ'\n", &DriverName);
476 }
477 else
478 DriverName.Length = 0;
479
480 Status = IopCreateDriver(
481 DriverName.Length > 0 ? &DriverName : NULL,
482 DriverEntry,
483 &RegistryKey,
484 ModuleObject->DllBase,
485 ModuleObject->SizeOfImage,
486 &Driver);
487 RtlFreeUnicodeString(&RegistryKey);
488
489 *DriverObject = Driver;
490 if (!NT_SUCCESS(Status))
491 {
492 DPRINT("IopCreateDriver() failed (Status 0x%08lx)\n", Status);
493 return Status;
494 }
495
496 /* Set the driver as initialized */
497 Driver->Flags |= DRVO_INITIALIZED;
498 DeviceObject = Driver->DeviceObject;
499 while (DeviceObject)
500 {
501 /* Set every device as initialized too */
502 DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
503 DeviceObject = DeviceObject->NextDevice;
504 }
505
506 if (PnpSystemInit) IopReinitializeDrivers();
507
508 return STATUS_SUCCESS;
509 }
510
511 /*
512 * IopAttachFilterDriversCallback
513 *
514 * Internal routine used by IopAttachFilterDrivers.
515 */
516
517 NTSTATUS NTAPI
518 IopAttachFilterDriversCallback(
519 PWSTR ValueName,
520 ULONG ValueType,
521 PVOID ValueData,
522 ULONG ValueLength,
523 PVOID Context,
524 PVOID EntryContext)
525 {
526 PDEVICE_NODE DeviceNode = Context;
527 UNICODE_STRING ServiceName;
528 PWCHAR Filters;
529 PLDR_DATA_TABLE_ENTRY ModuleObject;
530 PDRIVER_OBJECT DriverObject;
531 NTSTATUS Status;
532
533 for (Filters = ValueData;
534 ((ULONG_PTR)Filters - (ULONG_PTR)ValueData) < ValueLength &&
535 *Filters != 0;
536 Filters += (ServiceName.Length / sizeof(WCHAR)) + 1)
537 {
538 DPRINT("Filter Driver: %S (%wZ)\n", Filters, &DeviceNode->InstancePath);
539 ServiceName.Buffer = Filters;
540 ServiceName.MaximumLength =
541 ServiceName.Length = wcslen(Filters) * sizeof(WCHAR);
542
543 /* Load and initialize the filter driver */
544 Status = IopLoadServiceModule(&ServiceName, &ModuleObject);
545 if (Status != STATUS_IMAGE_ALREADY_LOADED)
546 {
547 if (!NT_SUCCESS(Status))
548 continue;
549
550 Status = IopInitializeDriverModule(DeviceNode, ModuleObject, &ServiceName,
551 FALSE, &DriverObject);
552 if (!NT_SUCCESS(Status))
553 continue;
554 }
555 else
556 {
557 /* get existing DriverObject pointer */
558 Status = IopGetDriverObject(
559 &DriverObject,
560 &ServiceName,
561 FALSE);
562 if (!NT_SUCCESS(Status))
563 {
564 DPRINT1("IopGetDriverObject() returned status 0x%08x!\n", Status);
565 continue;
566 }
567 }
568
569 Status = IopInitializeDevice(DeviceNode, DriverObject);
570 if (!NT_SUCCESS(Status))
571 continue;
572 }
573
574 return STATUS_SUCCESS;
575 }
576
577 /*
578 * IopAttachFilterDrivers
579 *
580 * Load filter drivers for specified device node.
581 *
582 * Parameters
583 * Lower
584 * Set to TRUE for loading lower level filters or FALSE for upper
585 * level filters.
586 */
587
588 NTSTATUS FASTCALL
589 IopAttachFilterDrivers(
590 PDEVICE_NODE DeviceNode,
591 BOOLEAN Lower)
592 {
593 RTL_QUERY_REGISTRY_TABLE QueryTable[2] = { { NULL, 0, NULL, NULL, 0, NULL, 0 }, };
594 UNICODE_STRING Class;
595 WCHAR ClassBuffer[40];
596 UNICODE_STRING EnumRoot = RTL_CONSTANT_STRING(ENUM_ROOT);
597 HANDLE EnumRootKey, SubKey;
598 NTSTATUS Status;
599
600 /* Open enumeration root key */
601 Status = IopOpenRegistryKeyEx(&EnumRootKey, NULL,
602 &EnumRoot, KEY_READ);
603 if (!NT_SUCCESS(Status))
604 {
605 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status);
606 return Status;
607 }
608
609 /* Open subkey */
610 Status = IopOpenRegistryKeyEx(&SubKey, EnumRootKey,
611 &DeviceNode->InstancePath, KEY_READ);
612 if (!NT_SUCCESS(Status))
613 {
614 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status);
615 ZwClose(EnumRootKey);
616 return Status;
617 }
618
619 /*
620 * First load the device filters
621 */
622 QueryTable[0].QueryRoutine = IopAttachFilterDriversCallback;
623 if (Lower)
624 QueryTable[0].Name = L"LowerFilters";
625 else
626 QueryTable[0].Name = L"UpperFilters";
627 QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
628
629 RtlQueryRegistryValues(
630 RTL_REGISTRY_HANDLE,
631 (PWSTR)SubKey,
632 QueryTable,
633 DeviceNode,
634 NULL);
635
636 /*
637 * Now get the class GUID
638 */
639 Class.Length = 0;
640 Class.MaximumLength = 40 * sizeof(WCHAR);
641 Class.Buffer = ClassBuffer;
642 QueryTable[0].QueryRoutine = NULL;
643 QueryTable[0].Name = L"ClassGUID";
644 QueryTable[0].EntryContext = &Class;
645 QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_DIRECT;
646
647 Status = RtlQueryRegistryValues(
648 RTL_REGISTRY_HANDLE,
649 (PWSTR)SubKey,
650 QueryTable,
651 DeviceNode,
652 NULL);
653
654 /* Close handles */
655 ZwClose(SubKey);
656 ZwClose(EnumRootKey);
657
658 /*
659 * Load the class filter driver
660 */
661 if (NT_SUCCESS(Status))
662 {
663 UNICODE_STRING ControlClass = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class");
664
665 Status = IopOpenRegistryKeyEx(&EnumRootKey, NULL,
666 &ControlClass, KEY_READ);
667 if (!NT_SUCCESS(Status))
668 {
669 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status);
670 return Status;
671 }
672
673 /* Open subkey */
674 Status = IopOpenRegistryKeyEx(&SubKey, EnumRootKey,
675 &Class, KEY_READ);
676 if (!NT_SUCCESS(Status))
677 {
678 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status);
679 ZwClose(EnumRootKey);
680 return Status;
681 }
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 RtlQueryRegistryValues(
692 RTL_REGISTRY_HANDLE,
693 (PWSTR)SubKey,
694 QueryTable,
695 DeviceNode,
696 NULL);
697
698 /* Clean up */
699 ZwClose(SubKey);
700 ZwClose(EnumRootKey);
701 }
702
703 return STATUS_SUCCESS;
704 }
705
706 NTSTATUS
707 NTAPI
708 MiResolveImageReferences(IN PVOID ImageBase,
709 IN PUNICODE_STRING ImageFileDirectory,
710 IN PUNICODE_STRING NamePrefix OPTIONAL,
711 OUT PCHAR *MissingApi,
712 OUT PWCHAR *MissingDriver,
713 OUT PLOAD_IMPORTS *LoadImports);
714
715 //
716 // Used for images already loaded (boot drivers)
717 //
718 NTSTATUS
719 NTAPI
720 LdrProcessDriverModule(PLDR_DATA_TABLE_ENTRY LdrEntry,
721 PUNICODE_STRING FileName,
722 PLDR_DATA_TABLE_ENTRY *ModuleObject)
723 {
724 NTSTATUS Status;
725 PLDR_DATA_TABLE_ENTRY NewEntry;
726 UNICODE_STRING BaseName, BaseDirectory;
727 PLOAD_IMPORTS LoadedImports = (PVOID)-2;
728 PCHAR MissingApiName, Buffer;
729 PWCHAR MissingDriverName;
730 PVOID DriverBase = LdrEntry->DllBase;
731
732 /* Allocate a buffer we'll use for names */
733 Buffer = ExAllocatePoolWithTag(NonPagedPool, MAX_PATH, TAG_LDR_WSTR);
734 if (!Buffer)
735 {
736 /* Fail */
737 return STATUS_INSUFFICIENT_RESOURCES;
738 }
739
740 /* Check for a separator */
741 if (FileName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR)
742 {
743 PWCHAR p;
744 ULONG BaseLength;
745
746 /* Loop the path until we get to the base name */
747 p = &FileName->Buffer[FileName->Length / sizeof(WCHAR)];
748 while (*(p - 1) != OBJ_NAME_PATH_SEPARATOR) p--;
749
750 /* Get the length */
751 BaseLength = (ULONG)(&FileName->Buffer[FileName->Length / sizeof(WCHAR)] - p);
752 BaseLength *= sizeof(WCHAR);
753
754 /* Setup the string */
755 BaseName.Length = (USHORT)BaseLength;
756 BaseName.Buffer = p;
757 }
758 else
759 {
760 /* Otherwise, we already have a base name */
761 BaseName.Length = FileName->Length;
762 BaseName.Buffer = FileName->Buffer;
763 }
764
765 /* Setup the maximum length */
766 BaseName.MaximumLength = BaseName.Length;
767
768 /* Now compute the base directory */
769 BaseDirectory = *FileName;
770 BaseDirectory.Length -= BaseName.Length;
771 BaseDirectory.MaximumLength = BaseDirectory.Length;
772
773 NewEntry = LdrEntry;
774
775 /* Resolve imports */
776 MissingApiName = Buffer;
777 Status = MiResolveImageReferences(DriverBase,
778 &BaseDirectory,
779 NULL,
780 &MissingApiName,
781 &MissingDriverName,
782 &LoadedImports);
783 if (!NT_SUCCESS(Status)) return Status;
784
785 /* Return */
786 *ModuleObject = LdrEntry;
787 return STATUS_SUCCESS;
788 }
789
790 /*
791 * IopInitializeBuiltinDriver
792 *
793 * Initialize a driver that is already loaded in memory.
794 */
795
796 NTSTATUS
797 NTAPI
798 IopInitializeBuiltinDriver(IN PLDR_DATA_TABLE_ENTRY LdrEntry)
799 {
800 PDEVICE_NODE DeviceNode;
801 PDRIVER_OBJECT DriverObject;
802 NTSTATUS Status;
803 PWCHAR FileNameWithoutPath;
804 LPWSTR FileExtension;
805 PUNICODE_STRING ModuleName = &LdrEntry->BaseDllName;
806 UNICODE_STRING ServiceName;
807
808 /*
809 * Display 'Loading XXX...' message
810 */
811 IopDisplayLoadingMessage(ModuleName);
812 InbvIndicateProgress();
813
814 /*
815 * Generate filename without path (not needed by freeldr)
816 */
817 FileNameWithoutPath = wcsrchr(ModuleName->Buffer, L'\\');
818 if (FileNameWithoutPath == NULL)
819 {
820 FileNameWithoutPath = ModuleName->Buffer;
821 }
822 else
823 {
824 FileNameWithoutPath++;
825 }
826
827 /*
828 * Strip the file extension from ServiceName
829 */
830 RtlCreateUnicodeString(&ServiceName, FileNameWithoutPath);
831 FileExtension = wcsrchr(ServiceName.Buffer, '.');
832 if (FileExtension != NULL)
833 {
834 ServiceName.Length -= wcslen(FileExtension) * sizeof(WCHAR);
835 FileExtension[0] = 0;
836 }
837
838 /*
839 * Determine the right device object
840 */
841 /* Use IopRootDeviceNode for now */
842 Status = IopCreateDeviceNode(IopRootDeviceNode, NULL, &ServiceName, &DeviceNode);
843 if (!NT_SUCCESS(Status))
844 {
845 DPRINT1("Driver '%wZ' load failed, status (%x)\n", ModuleName, Status);
846 return(Status);
847 }
848 DeviceNode->ServiceName = ServiceName;
849
850 /*
851 * Initialize the driver
852 */
853 Status = IopInitializeDriverModule(DeviceNode, LdrEntry,
854 &DeviceNode->ServiceName, FALSE, &DriverObject);
855
856 if (!NT_SUCCESS(Status))
857 {
858 IopFreeDeviceNode(DeviceNode);
859 return Status;
860 }
861
862 Status = IopInitializeDevice(DeviceNode, DriverObject);
863 if (NT_SUCCESS(Status))
864 {
865 Status = IopStartDevice(DeviceNode);
866 }
867
868 return Status;
869 }
870
871 /*
872 * IopInitializeBootDrivers
873 *
874 * Initialize boot drivers and free memory for boot files.
875 *
876 * Parameters
877 * None
878 *
879 * Return Value
880 * None
881 */
882 VOID
883 FASTCALL
884 IopInitializeBootDrivers(VOID)
885 {
886 PLIST_ENTRY ListHead, NextEntry, NextEntry2;
887 PLDR_DATA_TABLE_ENTRY LdrEntry;
888 PDEVICE_NODE DeviceNode;
889 PDRIVER_OBJECT DriverObject;
890 LDR_DATA_TABLE_ENTRY ModuleObject;
891 NTSTATUS Status;
892 UNICODE_STRING DriverName;
893 ULONG i, Index;
894 PDRIVER_INFORMATION DriverInfo, DriverInfoTag;
895 HANDLE KeyHandle;
896 PBOOT_DRIVER_LIST_ENTRY BootEntry;
897 DPRINT("IopInitializeBootDrivers()\n");
898
899 /* Use IopRootDeviceNode for now */
900 Status = IopCreateDeviceNode(IopRootDeviceNode, NULL, NULL, &DeviceNode);
901 if (!NT_SUCCESS(Status)) return;
902
903 /* Setup the module object for the RAW FS Driver */
904 ModuleObject.DllBase = NULL;
905 ModuleObject.SizeOfImage = 0;
906 ModuleObject.EntryPoint = RawFsDriverEntry;
907 RtlInitUnicodeString(&DriverName, L"RAW");
908
909 /* Initialize it */
910 Status = IopInitializeDriverModule(DeviceNode,
911 &ModuleObject,
912 &DriverName,
913 TRUE,
914 &DriverObject);
915 if (!NT_SUCCESS(Status))
916 {
917 /* Fail */
918 IopFreeDeviceNode(DeviceNode);
919 return;
920 }
921
922 /* Now initialize the associated device */
923 Status = IopInitializeDevice(DeviceNode, DriverObject);
924 if (!NT_SUCCESS(Status))
925 {
926 /* Fail */
927 IopFreeDeviceNode(DeviceNode);
928 return;
929 }
930
931 /* Start it up */
932 Status = IopStartDevice(DeviceNode);
933 if (!NT_SUCCESS(Status))
934 {
935 /* Fail */
936 IopFreeDeviceNode(DeviceNode);
937 return;
938 }
939
940 /* Get highest group order index */
941 IopGroupIndex = PpInitGetGroupOrderIndex(NULL);
942 if (IopGroupIndex == 0xFFFF) ASSERT(FALSE);
943
944 /* Allocate the group table */
945 IopGroupTable = ExAllocatePoolWithTag(PagedPool,
946 IopGroupIndex * sizeof(LIST_ENTRY),
947 TAG_IO);
948 if (IopGroupTable == NULL) ASSERT(FALSE);
949
950 /* Initialize the group table lists */
951 for (i = 0; i < IopGroupIndex; i++) InitializeListHead(&IopGroupTable[i]);
952
953 /* Loop the boot modules */
954 ListHead = &KeLoaderBlock->LoadOrderListHead;
955 NextEntry = ListHead->Flink;
956 while (ListHead != NextEntry)
957 {
958 /* Get the entry */
959 LdrEntry = CONTAINING_RECORD(NextEntry,
960 LDR_DATA_TABLE_ENTRY,
961 InLoadOrderLinks);
962
963 /* Check if the DLL needs to be initialized */
964 if (LdrEntry->Flags & LDRP_DRIVER_DEPENDENT_DLL)
965 {
966 /* Call its entrypoint */
967 MmCallDllInitialize(LdrEntry, NULL);
968 }
969
970 /* Go to the next driver */
971 NextEntry = NextEntry->Flink;
972 }
973
974 /* Loop the boot drivers */
975 ListHead = &KeLoaderBlock->BootDriverListHead;
976 NextEntry = ListHead->Flink;
977 while (ListHead != NextEntry)
978 {
979 /* Get the entry */
980 BootEntry = CONTAINING_RECORD(NextEntry,
981 BOOT_DRIVER_LIST_ENTRY,
982 Link);
983
984 /* Get the driver loader entry */
985 LdrEntry = BootEntry->LdrEntry;
986
987 /* Allocate our internal accounting structure */
988 DriverInfo = ExAllocatePoolWithTag(PagedPool,
989 sizeof(DRIVER_INFORMATION),
990 TAG_IO);
991 if (DriverInfo)
992 {
993 /* Zero it and initialize it */
994 RtlZeroMemory(DriverInfo, sizeof(DRIVER_INFORMATION));
995 InitializeListHead(&DriverInfo->Link);
996 DriverInfo->DataTableEntry = BootEntry;
997
998 /* Open the registry key */
999 Status = IopOpenRegistryKeyEx(&KeyHandle,
1000 NULL,
1001 &BootEntry->RegistryPath,
1002 KEY_READ);
1003 if ((NT_SUCCESS(Status)) || /* ReactOS HACK for SETUPLDR */
1004 ((KeLoaderBlock->SetupLdrBlock) && (KeyHandle = (PVOID)1)))
1005 {
1006 /* Save the handle */
1007 DriverInfo->ServiceHandle = KeyHandle;
1008
1009 /* Get the group oder index */
1010 Index = PpInitGetGroupOrderIndex(KeyHandle);
1011
1012 /* Get the tag position */
1013 DriverInfo->TagPosition = PipGetDriverTagPriority(KeyHandle);
1014
1015 /* Insert it into the list, at the right place */
1016 ASSERT(Index < IopGroupIndex);
1017 NextEntry2 = IopGroupTable[Index].Flink;
1018 while (NextEntry2 != &IopGroupTable[Index])
1019 {
1020 /* Get the driver info */
1021 DriverInfoTag = CONTAINING_RECORD(NextEntry2,
1022 DRIVER_INFORMATION,
1023 Link);
1024
1025 /* Check if we found the right tag position */
1026 if (DriverInfoTag->TagPosition > DriverInfo->TagPosition)
1027 {
1028 /* We're done */
1029 break;
1030 }
1031
1032 /* Next entry */
1033 NextEntry2 = NextEntry2->Flink;
1034 }
1035
1036 /* Insert us right before the next entry */
1037 NextEntry2 = NextEntry2->Blink;
1038 InsertHeadList(NextEntry2, &DriverInfo->Link);
1039 }
1040 }
1041
1042 /* Go to the next driver */
1043 NextEntry = NextEntry->Flink;
1044 }
1045
1046 /* Loop each group index */
1047 for (i = 0; i < IopGroupIndex; i++)
1048 {
1049 /* Loop each group table */
1050 NextEntry = IopGroupTable[i].Flink;
1051 while (NextEntry != &IopGroupTable[i])
1052 {
1053 /* Get the entry */
1054 DriverInfo = CONTAINING_RECORD(NextEntry,
1055 DRIVER_INFORMATION,
1056 Link);
1057
1058 /* Get the driver loader entry */
1059 LdrEntry = DriverInfo->DataTableEntry->LdrEntry;
1060
1061 /* Initialize it */
1062 IopInitializeBuiltinDriver(LdrEntry);
1063
1064 /* Next entry */
1065 NextEntry = NextEntry->Flink;
1066 }
1067 }
1068
1069 /* In old ROS, the loader list became empty after this point. Simulate. */
1070 InitializeListHead(&KeLoaderBlock->LoadOrderListHead);
1071 }
1072
1073 /*
1074 * IopUnloadDriver
1075 *
1076 * Unloads a device driver.
1077 *
1078 * Parameters
1079 * DriverServiceName
1080 * Name of the service to unload (registry key).
1081 *
1082 * UnloadPnpDrivers
1083 * Whether to unload Plug & Plug or only legacy drivers. If this
1084 * parameter is set to FALSE, the routine will unload only legacy
1085 * drivers.
1086 *
1087 * Return Value
1088 * Status
1089 *
1090 * To do
1091 * Guard the whole function by SEH.
1092 */
1093
1094 NTSTATUS NTAPI
1095 IopUnloadDriver(PUNICODE_STRING DriverServiceName, BOOLEAN UnloadPnpDrivers)
1096 {
1097 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
1098 UNICODE_STRING ImagePath;
1099 UNICODE_STRING ServiceName;
1100 UNICODE_STRING ObjectName;
1101 PDRIVER_OBJECT DriverObject;
1102 PDEVICE_OBJECT DeviceObject;
1103 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension;
1104 LOAD_UNLOAD_PARAMS LoadParams;
1105 NTSTATUS Status;
1106 LPWSTR Start;
1107 BOOLEAN SafeToUnload = TRUE;
1108
1109 DPRINT("IopUnloadDriver('%wZ', %d)\n", DriverServiceName, UnloadPnpDrivers);
1110
1111 PAGED_CODE();
1112
1113 /*
1114 * Get the service name from the registry key name
1115 */
1116
1117 Start = wcsrchr(DriverServiceName->Buffer, L'\\');
1118 if (Start == NULL)
1119 Start = DriverServiceName->Buffer;
1120 else
1121 Start++;
1122
1123 RtlInitUnicodeString(&ServiceName, Start);
1124
1125 /*
1126 * Construct the driver object name
1127 */
1128
1129 ObjectName.Length = (wcslen(Start) + 8) * sizeof(WCHAR);
1130 ObjectName.MaximumLength = ObjectName.Length + sizeof(WCHAR);
1131 ObjectName.Buffer = ExAllocatePool(PagedPool, ObjectName.MaximumLength);
1132 if (!ObjectName.Buffer) return STATUS_INSUFFICIENT_RESOURCES;
1133 wcscpy(ObjectName.Buffer, L"\\Driver\\");
1134 memcpy(ObjectName.Buffer + 8, Start, ObjectName.Length - 8 * sizeof(WCHAR));
1135 ObjectName.Buffer[ObjectName.Length/sizeof(WCHAR)] = 0;
1136
1137 /*
1138 * Find the driver object
1139 */
1140 Status = ObReferenceObjectByName(&ObjectName,
1141 0,
1142 0,
1143 0,
1144 IoDriverObjectType,
1145 KernelMode,
1146 0,
1147 (PVOID*)&DriverObject);
1148
1149 /*
1150 * Free the buffer for driver object name
1151 */
1152 ExFreePool(ObjectName.Buffer);
1153
1154 if (!NT_SUCCESS(Status))
1155 {
1156 DPRINT1("Can't locate driver object for %wZ\n", &ObjectName);
1157 return Status;
1158 }
1159
1160 /* Check that driver is not already unloading */
1161 if (DriverObject->Flags & DRVO_UNLOAD_INVOKED)
1162 {
1163 DPRINT1("Driver deletion pending\n");
1164 ObDereferenceObject(DriverObject);
1165 return STATUS_DELETE_PENDING;
1166 }
1167
1168 /*
1169 * Get path of service...
1170 */
1171
1172 RtlZeroMemory(QueryTable, sizeof(QueryTable));
1173
1174 RtlInitUnicodeString(&ImagePath, NULL);
1175
1176 QueryTable[0].Name = L"ImagePath";
1177 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
1178 QueryTable[0].EntryContext = &ImagePath;
1179
1180 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
1181 DriverServiceName->Buffer, QueryTable, NULL, NULL);
1182
1183 if (!NT_SUCCESS(Status))
1184 {
1185 DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status);
1186 ObDereferenceObject(DriverObject);
1187 return Status;
1188 }
1189
1190 /*
1191 * Normalize the image path for all later processing.
1192 */
1193
1194 Status = IopNormalizeImagePath(&ImagePath, &ServiceName);
1195
1196 if (!NT_SUCCESS(Status))
1197 {
1198 DPRINT1("IopNormalizeImagePath() failed (Status %x)\n", Status);
1199 ObDereferenceObject(DriverObject);
1200 return Status;
1201 }
1202
1203 /*
1204 * Free the service path
1205 */
1206
1207 ExFreePool(ImagePath.Buffer);
1208
1209 /*
1210 * Unload the module and release the references to the device object
1211 */
1212
1213 /* Call the load/unload routine, depending on current process */
1214 if (DriverObject->DriverUnload && DriverObject->DriverSection)
1215 {
1216 /* Loop through each device object of the driver
1217 and set DOE_UNLOAD_PENDING flag */
1218 DeviceObject = DriverObject->DeviceObject;
1219 while (DeviceObject)
1220 {
1221 /* Set the unload pending flag for the device */
1222 DeviceExtension = IoGetDevObjExtension(DeviceObject);
1223 DeviceExtension->ExtensionFlags |= DOE_UNLOAD_PENDING;
1224
1225 /* Make sure there are no attached devices or no reference counts */
1226 if ((DeviceObject->ReferenceCount) || (DeviceObject->AttachedDevice))
1227 {
1228 /* Not safe to unload */
1229 DPRINT1("Drivers device object is referenced or has attached devices\n");
1230
1231 SafeToUnload = FALSE;
1232 }
1233
1234 DeviceObject = DeviceObject->NextDevice;
1235 }
1236
1237 /* If not safe to unload, then return success */
1238 if (!SafeToUnload)
1239 {
1240 ObDereferenceObject(DriverObject);
1241 return STATUS_SUCCESS;
1242 }
1243
1244 /* Set the unload invoked flag */
1245 DriverObject->Flags |= DRVO_UNLOAD_INVOKED;
1246
1247 if (PsGetCurrentProcess() == PsInitialSystemProcess)
1248 {
1249 /* Just call right away */
1250 (*DriverObject->DriverUnload)(DriverObject);
1251 }
1252 else
1253 {
1254 /* Load/Unload must be called from system process */
1255
1256 /* Prepare parameters block */
1257 LoadParams.DriverObject = DriverObject;
1258 KeInitializeEvent(&LoadParams.Event, NotificationEvent, FALSE);
1259
1260 ExInitializeWorkItem(&LoadParams.WorkItem,
1261 (PWORKER_THREAD_ROUTINE)IopLoadUnloadDriver,
1262 (PVOID)&LoadParams);
1263
1264 /* Queue it */
1265 ExQueueWorkItem(&LoadParams.WorkItem, DelayedWorkQueue);
1266
1267 /* And wait when it completes */
1268 KeWaitForSingleObject(&LoadParams.Event, UserRequest, KernelMode,
1269 FALSE, NULL);
1270 }
1271
1272 /* Mark the driver object temporary, so it could be deleted later */
1273 ObMakeTemporaryObject(DriverObject);
1274
1275 /* Dereference it 2 times */
1276 ObDereferenceObject(DriverObject);
1277 ObDereferenceObject(DriverObject);
1278
1279 return STATUS_SUCCESS;
1280 }
1281 else
1282 {
1283 /* Dereference one time (refd inside this function) */
1284 ObDereferenceObject(DriverObject);
1285
1286 /* Return unloading failure */
1287 return STATUS_INVALID_DEVICE_REQUEST;
1288 }
1289 }
1290
1291 VOID
1292 NTAPI
1293 IopReinitializeDrivers(VOID)
1294 {
1295 PDRIVER_REINIT_ITEM ReinitItem;
1296 PLIST_ENTRY Entry;
1297
1298 /* Get the first entry and start looping */
1299 Entry = ExInterlockedRemoveHeadList(&DriverReinitListHead,
1300 &DriverReinitListLock);
1301 while (Entry)
1302 {
1303 /* Get the item*/
1304 ReinitItem = CONTAINING_RECORD(Entry, DRIVER_REINIT_ITEM, ItemEntry);
1305
1306 /* Increment reinitialization counter */
1307 ReinitItem->DriverObject->DriverExtension->Count++;
1308
1309 /* Remove the device object flag */
1310 ReinitItem->DriverObject->Flags &= ~DRVO_REINIT_REGISTERED;
1311
1312 /* Call the routine */
1313 ReinitItem->ReinitRoutine(ReinitItem->DriverObject,
1314 ReinitItem->Context,
1315 ReinitItem->DriverObject->
1316 DriverExtension->Count);
1317
1318 /* Free the entry */
1319 ExFreePool(Entry);
1320
1321 /* Move to the next one */
1322 Entry = ExInterlockedRemoveHeadList(&DriverReinitListHead,
1323 &DriverReinitListLock);
1324 }
1325 }
1326
1327 VOID
1328 NTAPI
1329 IopReinitializeBootDrivers(VOID)
1330 {
1331 PDRIVER_REINIT_ITEM ReinitItem;
1332 PLIST_ENTRY Entry;
1333
1334 /* Get the first entry and start looping */
1335 Entry = ExInterlockedRemoveHeadList(&DriverBootReinitListHead,
1336 &DriverBootReinitListLock);
1337 while (Entry)
1338 {
1339 /* Get the item*/
1340 ReinitItem = CONTAINING_RECORD(Entry, DRIVER_REINIT_ITEM, ItemEntry);
1341
1342 /* Increment reinitialization counter */
1343 ReinitItem->DriverObject->DriverExtension->Count++;
1344
1345 /* Remove the device object flag */
1346 ReinitItem->DriverObject->Flags &= ~DRVO_BOOTREINIT_REGISTERED;
1347
1348 /* Call the routine */
1349 ReinitItem->ReinitRoutine(ReinitItem->DriverObject,
1350 ReinitItem->Context,
1351 ReinitItem->DriverObject->
1352 DriverExtension->Count);
1353
1354 /* Free the entry */
1355 ExFreePool(Entry);
1356
1357 /* Move to the next one */
1358 Entry = ExInterlockedRemoveHeadList(&DriverBootReinitListHead,
1359 &DriverBootReinitListLock);
1360 }
1361 }
1362
1363 NTSTATUS
1364 NTAPI
1365 IopCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL,
1366 IN PDRIVER_INITIALIZE InitializationFunction,
1367 IN PUNICODE_STRING RegistryPath,
1368 IN PVOID DllBase,
1369 IN ULONG SizeOfImage,
1370 OUT PDRIVER_OBJECT *pDriverObject)
1371 {
1372 WCHAR NameBuffer[100];
1373 USHORT NameLength;
1374 UNICODE_STRING LocalDriverName;
1375 NTSTATUS Status;
1376 OBJECT_ATTRIBUTES ObjectAttributes;
1377 ULONG ObjectSize;
1378 PDRIVER_OBJECT DriverObject;
1379 UNICODE_STRING ServiceKeyName;
1380 HANDLE hDriver;
1381 ULONG i, RetryCount = 0;
1382
1383 try_again:
1384 /* First, create a unique name for the driver if we don't have one */
1385 if (!DriverName)
1386 {
1387 /* Create a random name and set up the string*/
1388 NameLength = (USHORT)swprintf(NameBuffer,
1389 L"\\Driver\\%08u",
1390 KeTickCount);
1391 LocalDriverName.Length = NameLength * sizeof(WCHAR);
1392 LocalDriverName.MaximumLength = LocalDriverName.Length + sizeof(UNICODE_NULL);
1393 LocalDriverName.Buffer = NameBuffer;
1394 }
1395 else
1396 {
1397 /* So we can avoid another code path, use a local var */
1398 LocalDriverName = *DriverName;
1399 }
1400
1401 /* Initialize the Attributes */
1402 ObjectSize = sizeof(DRIVER_OBJECT) + sizeof(EXTENDED_DRIVER_EXTENSION);
1403 InitializeObjectAttributes(&ObjectAttributes,
1404 &LocalDriverName,
1405 OBJ_PERMANENT | OBJ_CASE_INSENSITIVE,
1406 NULL,
1407 NULL);
1408
1409 /* Create the Object */
1410 Status = ObCreateObject(KernelMode,
1411 IoDriverObjectType,
1412 &ObjectAttributes,
1413 KernelMode,
1414 NULL,
1415 ObjectSize,
1416 0,
1417 0,
1418 (PVOID*)&DriverObject);
1419 if (!NT_SUCCESS(Status)) return Status;
1420
1421 DPRINT("IopCreateDriver(): created DO %p\n", DriverObject);
1422
1423 /* Set up the Object */
1424 RtlZeroMemory(DriverObject, ObjectSize);
1425 DriverObject->Type = IO_TYPE_DRIVER;
1426 DriverObject->Size = sizeof(DRIVER_OBJECT);
1427 DriverObject->Flags = DRVO_LEGACY_DRIVER;//DRVO_BUILTIN_DRIVER;
1428 DriverObject->DriverExtension = (PDRIVER_EXTENSION)(DriverObject + 1);
1429 DriverObject->DriverExtension->DriverObject = DriverObject;
1430 DriverObject->DriverInit = InitializationFunction;
1431
1432 /* Loop all Major Functions */
1433 for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
1434 {
1435 /* Invalidate each function */
1436 DriverObject->MajorFunction[i] = IopInvalidDeviceRequest;
1437 }
1438
1439 /* Set up the service key name buffer */
1440 ServiceKeyName.Buffer = ExAllocatePoolWithTag(PagedPool,
1441 LocalDriverName.Length +
1442 sizeof(WCHAR),
1443 TAG_IO);
1444 if (!ServiceKeyName.Buffer)
1445 {
1446 /* Fail */
1447 ObMakeTemporaryObject(DriverObject);
1448 ObDereferenceObject(DriverObject);
1449 return STATUS_INSUFFICIENT_RESOURCES;
1450 }
1451
1452 /* Fill out the key data and copy the buffer */
1453 ServiceKeyName.Length = LocalDriverName.Length;
1454 ServiceKeyName.MaximumLength = LocalDriverName.MaximumLength;
1455 RtlCopyMemory(ServiceKeyName.Buffer,
1456 LocalDriverName.Buffer,
1457 LocalDriverName.Length);
1458
1459 /* Null-terminate it and set it */
1460 ServiceKeyName.Buffer[ServiceKeyName.Length / sizeof(WCHAR)] = UNICODE_NULL;
1461 DriverObject->DriverExtension->ServiceKeyName = ServiceKeyName;
1462
1463 /* Also store it in the Driver Object. This is a bit of a hack. */
1464 RtlCopyMemory(&DriverObject->DriverName,
1465 &ServiceKeyName,
1466 sizeof(UNICODE_STRING));
1467
1468 /* Add the Object and get its handle */
1469 Status = ObInsertObject(DriverObject,
1470 NULL,
1471 FILE_READ_DATA,
1472 0,
1473 NULL,
1474 &hDriver);
1475
1476 /* Eliminate small possibility when this function is called more than
1477 once in a row, and KeTickCount doesn't get enough time to change */
1478 if (!DriverName && (Status == STATUS_OBJECT_NAME_COLLISION) && (RetryCount < 100))
1479 {
1480 RetryCount++;
1481 goto try_again;
1482 }
1483
1484 if (!NT_SUCCESS(Status)) return Status;
1485
1486 /* Now reference it */
1487 Status = ObReferenceObjectByHandle(hDriver,
1488 0,
1489 IoDriverObjectType,
1490 KernelMode,
1491 (PVOID*)&DriverObject,
1492 NULL);
1493 if (!NT_SUCCESS(Status))
1494 {
1495 /* Fail */
1496 ObMakeTemporaryObject(DriverObject);
1497 ObDereferenceObject(DriverObject);
1498 return Status;
1499 }
1500
1501 /* Close the extra handle */
1502 ZwClose(hDriver);
1503
1504 DriverObject->HardwareDatabase = &IopHardwareDatabaseKey;
1505 DriverObject->DriverStart = DllBase;
1506 DriverObject->DriverSize = SizeOfImage;
1507
1508 /* Finally, call its init function */
1509 DPRINT("RegistryKey: %wZ\n", RegistryPath);
1510 DPRINT("Calling driver entrypoint at %p\n", InitializationFunction);
1511 Status = (*InitializationFunction)(DriverObject, RegistryPath);
1512 if (!NT_SUCCESS(Status))
1513 {
1514 /* If it didn't work, then kill the object */
1515 DPRINT1("'%wZ' initialization failed, status (0x%08lx)\n", DriverName, Status);
1516 ObMakeTemporaryObject(DriverObject);
1517 ObDereferenceObject(DriverObject);
1518 }
1519 else
1520 {
1521 /* Returns to caller the object */
1522 *pDriverObject = DriverObject;
1523 }
1524
1525 /* Loop all Major Functions */
1526 for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
1527 {
1528 /*
1529 * Make sure the driver didn't set any dispatch entry point to NULL!
1530 * Doing so is illegal; drivers shouldn't touch entry points they
1531 * do not implement.
1532 */
1533 ASSERT(DriverObject->MajorFunction[i] != NULL);
1534
1535 /* Check if it did so anyway */
1536 if (!DriverObject->MajorFunction[i])
1537 {
1538 /* Fix it up */
1539 DriverObject->MajorFunction[i] = IopInvalidDeviceRequest;
1540 }
1541 }
1542
1543 /* Return the Status */
1544 return Status;
1545 }
1546
1547 /* PUBLIC FUNCTIONS ***********************************************************/
1548
1549 /*
1550 * @implemented
1551 */
1552 NTSTATUS
1553 NTAPI
1554 IoCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL,
1555 IN PDRIVER_INITIALIZE InitializationFunction)
1556 {
1557 PDRIVER_OBJECT DriverObject;
1558 return IopCreateDriver(DriverName, InitializationFunction, NULL, 0, 0, &DriverObject);
1559 }
1560
1561 /*
1562 * @implemented
1563 */
1564 VOID
1565 NTAPI
1566 IoDeleteDriver(IN PDRIVER_OBJECT DriverObject)
1567 {
1568 /* Simply dereference the Object */
1569 ObDereferenceObject(DriverObject);
1570 }
1571
1572 /*
1573 * @implemented
1574 */
1575 VOID
1576 NTAPI
1577 IoRegisterBootDriverReinitialization(IN PDRIVER_OBJECT DriverObject,
1578 IN PDRIVER_REINITIALIZE ReinitRoutine,
1579 IN PVOID Context)
1580 {
1581 PDRIVER_REINIT_ITEM ReinitItem;
1582
1583 /* Allocate the entry */
1584 ReinitItem = ExAllocatePoolWithTag(NonPagedPool,
1585 sizeof(DRIVER_REINIT_ITEM),
1586 TAG_REINIT);
1587 if (!ReinitItem) return;
1588
1589 /* Fill it out */
1590 ReinitItem->DriverObject = DriverObject;
1591 ReinitItem->ReinitRoutine = ReinitRoutine;
1592 ReinitItem->Context = Context;
1593
1594 /* Set the Driver Object flag and insert the entry into the list */
1595 DriverObject->Flags |= DRVO_BOOTREINIT_REGISTERED;
1596 ExInterlockedInsertTailList(&DriverBootReinitListHead,
1597 &ReinitItem->ItemEntry,
1598 &DriverBootReinitListLock);
1599 }
1600
1601 /*
1602 * @implemented
1603 */
1604 VOID
1605 NTAPI
1606 IoRegisterDriverReinitialization(IN PDRIVER_OBJECT DriverObject,
1607 IN PDRIVER_REINITIALIZE ReinitRoutine,
1608 IN PVOID Context)
1609 {
1610 PDRIVER_REINIT_ITEM ReinitItem;
1611
1612 /* Allocate the entry */
1613 ReinitItem = ExAllocatePoolWithTag(NonPagedPool,
1614 sizeof(DRIVER_REINIT_ITEM),
1615 TAG_REINIT);
1616 if (!ReinitItem) return;
1617
1618 /* Fill it out */
1619 ReinitItem->DriverObject = DriverObject;
1620 ReinitItem->ReinitRoutine = ReinitRoutine;
1621 ReinitItem->Context = Context;
1622
1623 /* Set the Driver Object flag and insert the entry into the list */
1624 DriverObject->Flags |= DRVO_REINIT_REGISTERED;
1625 ExInterlockedInsertTailList(&DriverReinitListHead,
1626 &ReinitItem->ItemEntry,
1627 &DriverReinitListLock);
1628 }
1629
1630 /*
1631 * @implemented
1632 */
1633 NTSTATUS
1634 NTAPI
1635 IoAllocateDriverObjectExtension(IN PDRIVER_OBJECT DriverObject,
1636 IN PVOID ClientIdentificationAddress,
1637 IN ULONG DriverObjectExtensionSize,
1638 OUT PVOID *DriverObjectExtension)
1639 {
1640 KIRQL OldIrql;
1641 PIO_CLIENT_EXTENSION DriverExtensions, NewDriverExtension;
1642 BOOLEAN Inserted = FALSE;
1643
1644 /* Assume failure */
1645 *DriverObjectExtension = NULL;
1646
1647 /* Allocate the extension */
1648 NewDriverExtension = ExAllocatePoolWithTag(NonPagedPool,
1649 sizeof(IO_CLIENT_EXTENSION) +
1650 DriverObjectExtensionSize,
1651 TAG_DRIVER_EXTENSION);
1652 if (!NewDriverExtension) return STATUS_INSUFFICIENT_RESOURCES;
1653
1654 /* Clear the extension for teh caller */
1655 RtlZeroMemory(NewDriverExtension,
1656 sizeof(IO_CLIENT_EXTENSION) + DriverObjectExtensionSize);
1657
1658 /* Acqure lock */
1659 OldIrql = KeRaiseIrqlToDpcLevel();
1660
1661 /* Fill out the extension */
1662 NewDriverExtension->ClientIdentificationAddress = ClientIdentificationAddress;
1663
1664 /* Loop the current extensions */
1665 DriverExtensions = IoGetDrvObjExtension(DriverObject)->
1666 ClientDriverExtension;
1667 while (DriverExtensions)
1668 {
1669 /* Check if the identifier matches */
1670 if (DriverExtensions->ClientIdentificationAddress ==
1671 ClientIdentificationAddress)
1672 {
1673 /* We have a collision, break out */
1674 break;
1675 }
1676
1677 /* Go to the next one */
1678 DriverExtensions = DriverExtensions->NextExtension;
1679 }
1680
1681 /* Check if we didn't collide */
1682 if (!DriverExtensions)
1683 {
1684 /* Link this one in */
1685 NewDriverExtension->NextExtension =
1686 IoGetDrvObjExtension(DriverObject)->ClientDriverExtension;
1687 IoGetDrvObjExtension(DriverObject)->ClientDriverExtension =
1688 NewDriverExtension;
1689 Inserted = TRUE;
1690 }
1691
1692 /* Release the lock */
1693 KeLowerIrql(OldIrql);
1694
1695 /* Check if insertion failed */
1696 if (!Inserted)
1697 {
1698 /* Free the entry and fail */
1699 ExFreePool(NewDriverExtension);
1700 return STATUS_OBJECT_NAME_COLLISION;
1701 }
1702
1703 /* Otherwise, return the pointer */
1704 *DriverObjectExtension = NewDriverExtension + 1;
1705 return STATUS_SUCCESS;
1706 }
1707
1708 /*
1709 * @implemented
1710 */
1711 PVOID
1712 NTAPI
1713 IoGetDriverObjectExtension(IN PDRIVER_OBJECT DriverObject,
1714 IN PVOID ClientIdentificationAddress)
1715 {
1716 KIRQL OldIrql;
1717 PIO_CLIENT_EXTENSION DriverExtensions;
1718
1719 /* Acquire lock */
1720 OldIrql = KeRaiseIrqlToDpcLevel();
1721
1722 /* Loop the list until we find the right one */
1723 DriverExtensions = IoGetDrvObjExtension(DriverObject)->ClientDriverExtension;
1724 while (DriverExtensions)
1725 {
1726 /* Check for a match */
1727 if (DriverExtensions->ClientIdentificationAddress ==
1728 ClientIdentificationAddress)
1729 {
1730 /* Break out */
1731 break;
1732 }
1733
1734 /* Keep looping */
1735 DriverExtensions = DriverExtensions->NextExtension;
1736 }
1737
1738 /* Release lock */
1739 KeLowerIrql(OldIrql);
1740
1741 /* Return nothing or the extension */
1742 if (!DriverExtensions) return NULL;
1743 return DriverExtensions + 1;
1744 }
1745
1746 VOID NTAPI
1747 IopLoadUnloadDriver(PLOAD_UNLOAD_PARAMS LoadParams)
1748 {
1749 RTL_QUERY_REGISTRY_TABLE QueryTable[3];
1750 UNICODE_STRING ImagePath;
1751 UNICODE_STRING ServiceName;
1752 NTSTATUS Status;
1753 ULONG Type;
1754 PDEVICE_NODE DeviceNode;
1755 PDRIVER_OBJECT DriverObject;
1756 PLDR_DATA_TABLE_ENTRY ModuleObject;
1757 PVOID BaseAddress;
1758 WCHAR *cur;
1759
1760 /* Check if it's an unload request */
1761 if (LoadParams->DriverObject)
1762 {
1763 (*LoadParams->DriverObject->DriverUnload)(LoadParams->DriverObject);
1764
1765 /* Return success and signal the event */
1766 LoadParams->Status = STATUS_SUCCESS;
1767 (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
1768 return;
1769 }
1770
1771 RtlInitUnicodeString(&ImagePath, NULL);
1772
1773 /*
1774 * Get the service name from the registry key name.
1775 */
1776 ASSERT(LoadParams->ServiceName->Length >= sizeof(WCHAR));
1777
1778 ServiceName = *LoadParams->ServiceName;
1779 cur = LoadParams->ServiceName->Buffer +
1780 (LoadParams->ServiceName->Length / sizeof(WCHAR)) - 1;
1781 while (LoadParams->ServiceName->Buffer != cur)
1782 {
1783 if(*cur == L'\\')
1784 {
1785 ServiceName.Buffer = cur + 1;
1786 ServiceName.Length = LoadParams->ServiceName->Length -
1787 (USHORT)((ULONG_PTR)ServiceName.Buffer -
1788 (ULONG_PTR)LoadParams->ServiceName->Buffer);
1789 break;
1790 }
1791 cur--;
1792 }
1793
1794 /*
1795 * Get service type.
1796 */
1797
1798 RtlZeroMemory(&QueryTable, sizeof(QueryTable));
1799
1800 RtlInitUnicodeString(&ImagePath, NULL);
1801
1802 QueryTable[0].Name = L"Type";
1803 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
1804 QueryTable[0].EntryContext = &Type;
1805
1806 QueryTable[1].Name = L"ImagePath";
1807 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
1808 QueryTable[1].EntryContext = &ImagePath;
1809
1810 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
1811 LoadParams->ServiceName->Buffer, QueryTable, NULL, NULL);
1812
1813 if (!NT_SUCCESS(Status))
1814 {
1815 DPRINT("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
1816 if (ImagePath.Buffer)
1817 ExFreePool(ImagePath.Buffer);
1818 LoadParams->Status = Status;
1819 (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
1820 return;
1821 }
1822
1823 /*
1824 * Normalize the image path for all later processing.
1825 */
1826
1827 Status = IopNormalizeImagePath(&ImagePath, &ServiceName);
1828
1829 if (!NT_SUCCESS(Status))
1830 {
1831 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status);
1832 LoadParams->Status = Status;
1833 (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
1834 return;
1835 }
1836
1837 DPRINT("FullImagePath: '%wZ'\n", &ImagePath);
1838 DPRINT("Type: %lx\n", Type);
1839
1840 /*
1841 * Create device node
1842 */
1843
1844 /* Use IopRootDeviceNode for now */
1845 Status = IopCreateDeviceNode(IopRootDeviceNode, NULL, &ServiceName, &DeviceNode);
1846
1847 if (!NT_SUCCESS(Status))
1848 {
1849 DPRINT("IopCreateDeviceNode() failed (Status %lx)\n", Status);
1850 LoadParams->Status = Status;
1851 (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
1852 return;
1853 }
1854
1855 /* Get existing DriverObject pointer (in case the driver has
1856 already been loaded and initialized) */
1857 Status = IopGetDriverObject(
1858 &DriverObject,
1859 &ServiceName,
1860 (Type == 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
1861 Type == 8 /* SERVICE_RECOGNIZER_DRIVER */));
1862
1863 if (!NT_SUCCESS(Status))
1864 {
1865 /*
1866 * Load the driver module
1867 */
1868
1869 Status = MmLoadSystemImage(&ImagePath, NULL, NULL, 0, (PVOID)&ModuleObject, &BaseAddress);
1870 if (!NT_SUCCESS(Status) && Status != STATUS_IMAGE_ALREADY_LOADED)
1871 {
1872 DPRINT("MmLoadSystemImage() failed (Status %lx)\n", Status);
1873 IopFreeDeviceNode(DeviceNode);
1874 LoadParams->Status = Status;
1875 (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
1876 return;
1877 }
1878
1879 /*
1880 * Set a service name for the device node
1881 */
1882
1883 RtlCreateUnicodeString(&DeviceNode->ServiceName, ServiceName.Buffer);
1884
1885 /*
1886 * Initialize the driver module if it's loaded for the first time
1887 */
1888 if (Status != STATUS_IMAGE_ALREADY_LOADED)
1889 {
1890 Status = IopInitializeDriverModule(
1891 DeviceNode,
1892 ModuleObject,
1893 &DeviceNode->ServiceName,
1894 (Type == 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
1895 Type == 8 /* SERVICE_RECOGNIZER_DRIVER */),
1896 &DriverObject);
1897
1898 if (!NT_SUCCESS(Status))
1899 {
1900 DPRINT("IopInitializeDriver() failed (Status %lx)\n", Status);
1901 MmUnloadSystemImage(ModuleObject);
1902 IopFreeDeviceNode(DeviceNode);
1903 LoadParams->Status = Status;
1904 (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
1905 return;
1906 }
1907 }
1908
1909 /* Store its DriverSection, so that it could be unloaded */
1910 DriverObject->DriverSection = ModuleObject;
1911
1912 /* Initialize and start device */
1913 IopInitializeDevice(DeviceNode, DriverObject);
1914 Status = IopStartDevice(DeviceNode);
1915 }
1916 else
1917 {
1918 DPRINT("DriverObject already exist in ObjectManager\n");
1919
1920 /* IopGetDriverObject references the DriverObject, so dereference it */
1921 ObDereferenceObject(DriverObject);
1922
1923 /* Free device node since driver loading failed */
1924 IopFreeDeviceNode(DeviceNode);
1925 }
1926
1927 /* Pass status to the caller and signal the event */
1928 LoadParams->Status = Status;
1929 (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
1930 }
1931
1932 /*
1933 * NtLoadDriver
1934 *
1935 * Loads a device driver.
1936 *
1937 * Parameters
1938 * DriverServiceName
1939 * Name of the service to load (registry key).
1940 *
1941 * Return Value
1942 * Status
1943 *
1944 * Status
1945 * implemented
1946 */
1947 NTSTATUS NTAPI
1948 NtLoadDriver(IN PUNICODE_STRING DriverServiceName)
1949 {
1950 UNICODE_STRING CapturedDriverServiceName = { 0, 0, NULL };
1951 KPROCESSOR_MODE PreviousMode;
1952 LOAD_UNLOAD_PARAMS LoadParams;
1953 NTSTATUS Status;
1954
1955 PAGED_CODE();
1956
1957 PreviousMode = KeGetPreviousMode();
1958
1959 /*
1960 * Check security privileges
1961 */
1962
1963 /* FIXME: Uncomment when privileges will be correctly implemented. */
1964 #if 0
1965 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, PreviousMode))
1966 {
1967 DPRINT("Privilege not held\n");
1968 return STATUS_PRIVILEGE_NOT_HELD;
1969 }
1970 #endif
1971
1972 Status = ProbeAndCaptureUnicodeString(&CapturedDriverServiceName,
1973 PreviousMode,
1974 DriverServiceName);
1975 if (!NT_SUCCESS(Status))
1976 {
1977 return Status;
1978 }
1979
1980 DPRINT("NtLoadDriver('%wZ')\n", &CapturedDriverServiceName);
1981
1982 LoadParams.ServiceName = &CapturedDriverServiceName;
1983 LoadParams.DriverObject = NULL;
1984 KeInitializeEvent(&LoadParams.Event, NotificationEvent, FALSE);
1985
1986 /* Call the load/unload routine, depending on current process */
1987 if (PsGetCurrentProcess() == PsInitialSystemProcess)
1988 {
1989 /* Just call right away */
1990 IopLoadUnloadDriver(&LoadParams);
1991 }
1992 else
1993 {
1994 /* Load/Unload must be called from system process */
1995 ExInitializeWorkItem(&LoadParams.WorkItem,
1996 (PWORKER_THREAD_ROUTINE)IopLoadUnloadDriver,
1997 (PVOID)&LoadParams);
1998
1999 /* Queue it */
2000 ExQueueWorkItem(&LoadParams.WorkItem, DelayedWorkQueue);
2001
2002 /* And wait when it completes */
2003 KeWaitForSingleObject(&LoadParams.Event, UserRequest, KernelMode,
2004 FALSE, NULL);
2005 }
2006
2007 ReleaseCapturedUnicodeString(&CapturedDriverServiceName,
2008 PreviousMode);
2009
2010 return LoadParams.Status;
2011 }
2012
2013 /*
2014 * NtUnloadDriver
2015 *
2016 * Unloads a legacy device driver.
2017 *
2018 * Parameters
2019 * DriverServiceName
2020 * Name of the service to unload (registry key).
2021 *
2022 * Return Value
2023 * Status
2024 *
2025 * Status
2026 * implemented
2027 */
2028
2029 NTSTATUS NTAPI
2030 NtUnloadDriver(IN PUNICODE_STRING DriverServiceName)
2031 {
2032 return IopUnloadDriver(DriverServiceName, FALSE);
2033 }
2034
2035 /* EOF */