2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/iomgr/drvrlist.c
5 * PURPOSE: Driver List support for Grouping, Tagging, Sorting, etc.
6 * PROGRAMMERS: <UNKNOWN>
9 /* INCLUDES *******************************************************************/
15 typedef struct _SERVICE_GROUP
17 LIST_ENTRY GroupListEntry
;
18 UNICODE_STRING GroupName
;
19 BOOLEAN ServicesRunning
;
22 } SERVICE_GROUP
, *PSERVICE_GROUP
;
24 typedef struct _SERVICE
26 LIST_ENTRY ServiceListEntry
;
27 UNICODE_STRING ServiceName
;
28 UNICODE_STRING RegistryPath
;
29 UNICODE_STRING ServiceGroup
;
30 UNICODE_STRING ImagePath
;
37 /* BOOLEAN ServiceRunning;*/ // needed ??
40 #define TAG_RTLREGISTRY 'vrqR'
42 /* GLOBALS ********************************************************************/
44 LIST_ENTRY GroupListHead
= {NULL
, NULL
};
45 LIST_ENTRY ServiceListHead
= {NULL
, NULL
};
46 extern BOOLEAN NoGuiBoot
;
51 IopDisplayLoadingMessage(PUNICODE_STRING ServiceName
);
53 /* PRIVATE FUNCTIONS **********************************************************/
56 IopGetGroupOrderList(PWSTR ValueName
,
65 DPRINT("IopGetGroupOrderList(%S, %x, 0x%p, %x, 0x%p, 0x%p)\n",
66 ValueName
, ValueType
, ValueData
, ValueLength
, Context
, EntryContext
);
68 if (ValueType
== REG_BINARY
&&
70 ValueLength
>= sizeof(ULONG
) &&
71 ValueLength
>= (*(PULONG
)ValueData
+ 1) * sizeof(ULONG
))
73 Group
= (PSERVICE_GROUP
)Context
;
74 Group
->TagCount
= ((PULONG
)ValueData
)[0];
75 if (Group
->TagCount
> 0)
77 if (ValueLength
>= (Group
->TagCount
+ 1) * sizeof(ULONG
))
79 Group
->TagArray
= ExAllocatePool(NonPagedPool
, Group
->TagCount
* sizeof(ULONG
));
80 if (Group
->TagArray
== NULL
)
83 return STATUS_INSUFFICIENT_RESOURCES
;
85 memcpy(Group
->TagArray
, (PULONG
)ValueData
+ 1, Group
->TagCount
* sizeof(ULONG
));
90 return STATUS_UNSUCCESSFUL
;
94 return STATUS_SUCCESS
;
98 IopCreateGroupListEntry(PWSTR ValueName
,
105 PSERVICE_GROUP Group
;
106 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
110 if (ValueType
== REG_SZ
)
112 DPRINT("GroupName: '%S'\n", (PWCHAR
)ValueData
);
114 Group
= ExAllocatePool(NonPagedPool
,
115 sizeof(SERVICE_GROUP
));
118 return(STATUS_INSUFFICIENT_RESOURCES
);
121 RtlZeroMemory(Group
, sizeof(SERVICE_GROUP
));
123 if (!RtlCreateUnicodeString(&Group
->GroupName
, (PWSTR
)ValueData
))
126 return(STATUS_INSUFFICIENT_RESOURCES
);
129 RtlZeroMemory(&QueryTable
, sizeof(QueryTable
));
130 QueryTable
[0].Name
= (PWSTR
)ValueData
;
131 QueryTable
[0].QueryRoutine
= IopGetGroupOrderList
;
133 Status
= RtlQueryRegistryValues(RTL_REGISTRY_CONTROL
,
138 DPRINT("%x %d %S\n", Status
, Group
->TagCount
, (PWSTR
)ValueData
);
140 InsertTailList(&GroupListHead
,
141 &Group
->GroupListEntry
);
144 return(STATUS_SUCCESS
);
148 static NTSTATUS NTAPI
149 IopCreateServiceListEntry(PUNICODE_STRING ServiceName
)
151 RTL_QUERY_REGISTRY_TABLE QueryTable
[7];
154 ULONG DefaultTag
= MAXULONG
;
156 DPRINT("ServiceName: '%wZ'\n", ServiceName
);
158 /* Allocate service entry */
159 Service
= (PSERVICE
)ExAllocatePool(NonPagedPool
, sizeof(SERVICE
));
162 DPRINT1("ExAllocatePool() failed\n");
163 return(STATUS_INSUFFICIENT_RESOURCES
);
165 RtlZeroMemory(Service
, sizeof(SERVICE
));
167 /* Get service data */
168 RtlZeroMemory(&QueryTable
,
171 QueryTable
[0].Name
= L
"Start";
172 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
173 QueryTable
[0].EntryContext
= &Service
->Start
;
175 QueryTable
[1].Name
= L
"Type";
176 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
177 QueryTable
[1].EntryContext
= &Service
->Type
;
179 QueryTable
[2].Name
= L
"ErrorControl";
180 QueryTable
[2].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
181 QueryTable
[2].EntryContext
= &Service
->ErrorControl
;
183 QueryTable
[3].Name
= L
"Group";
184 QueryTable
[3].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
185 QueryTable
[3].EntryContext
= &Service
->ServiceGroup
;
187 QueryTable
[4].Name
= L
"ImagePath";
188 QueryTable
[4].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
189 QueryTable
[4].EntryContext
= &Service
->ImagePath
;
191 QueryTable
[5].Name
= L
"Tag";
192 QueryTable
[5].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
193 QueryTable
[5].EntryContext
= &Service
->Tag
;
194 QueryTable
[5].DefaultData
= &DefaultTag
;
195 QueryTable
[5].DefaultType
= REG_DWORD
;
196 QueryTable
[5].DefaultLength
= sizeof(DefaultTag
);
198 Status
= RtlQueryRegistryValues(RTL_REGISTRY_SERVICES
,
203 if (!NT_SUCCESS(Status
) || Service
->Start
> 1)
206 * If something goes wrong during RtlQueryRegistryValues
207 * it'll just drop everything on the floor and return,
208 * so you have to check if the buffers were filled.
209 * Luckily we zerofilled the Service.
211 if (Service
->ServiceGroup
.Buffer
)
213 ExFreePoolWithTag(Service
->ServiceGroup
.Buffer
, TAG_RTLREGISTRY
);
215 if (Service
->ImagePath
.Buffer
)
217 ExFreePoolWithTag(Service
->ImagePath
.Buffer
, TAG_RTLREGISTRY
);
223 /* Copy service name */
224 Service
->ServiceName
.Length
= ServiceName
->Length
;
225 Service
->ServiceName
.MaximumLength
= ServiceName
->Length
+ sizeof(WCHAR
);
226 Service
->ServiceName
.Buffer
= ExAllocatePool(NonPagedPool
,
227 Service
->ServiceName
.MaximumLength
);
228 RtlCopyMemory(Service
->ServiceName
.Buffer
,
230 ServiceName
->Length
);
231 Service
->ServiceName
.Buffer
[ServiceName
->Length
/ sizeof(WCHAR
)] = 0;
233 /* Build registry path */
234 Service
->RegistryPath
.MaximumLength
= MAX_PATH
* sizeof(WCHAR
);
235 Service
->RegistryPath
.Buffer
= ExAllocatePool(NonPagedPool
,
236 MAX_PATH
* sizeof(WCHAR
));
237 wcscpy(Service
->RegistryPath
.Buffer
,
238 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
239 wcscat(Service
->RegistryPath
.Buffer
,
240 Service
->ServiceName
.Buffer
);
241 Service
->RegistryPath
.Length
= wcslen(Service
->RegistryPath
.Buffer
) * sizeof(WCHAR
);
243 DPRINT("ServiceName: '%wZ'\n", &Service
->ServiceName
);
244 DPRINT("RegistryPath: '%wZ'\n", &Service
->RegistryPath
);
245 DPRINT("ServiceGroup: '%wZ'\n", &Service
->ServiceGroup
);
246 DPRINT("ImagePath: '%wZ'\n", &Service
->ImagePath
);
247 DPRINT("Start %lx Type %lx Tag %lx ErrorControl %lx\n",
248 Service
->Start
, Service
->Type
, Service
->Tag
, Service
->ErrorControl
);
250 /* Append service entry */
251 InsertTailList(&ServiceListHead
,
252 &Service
->ServiceListEntry
);
254 return(STATUS_SUCCESS
);
258 NTSTATUS INIT_FUNCTION
259 IoCreateDriverList(VOID
)
261 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
262 PKEY_BASIC_INFORMATION KeyInfo
= NULL
;
263 OBJECT_ATTRIBUTES ObjectAttributes
;
264 UNICODE_STRING ServicesKeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services");
265 UNICODE_STRING SubKeyName
;
270 ULONG KeyInfoLength
= 0;
271 ULONG ReturnedLength
;
273 DPRINT("IoCreateDriverList() called\n");
275 /* Initialize basic variables */
276 InitializeListHead(&GroupListHead
);
277 InitializeListHead(&ServiceListHead
);
279 /* Build group order list */
280 RtlZeroMemory(&QueryTable
,
283 QueryTable
[0].Name
= L
"List";
284 QueryTable
[0].QueryRoutine
= IopCreateGroupListEntry
;
286 Status
= RtlQueryRegistryValues(RTL_REGISTRY_CONTROL
,
287 L
"ServiceGroupOrder",
291 if (!NT_SUCCESS(Status
))
294 /* Enumerate services and create the service list */
295 InitializeObjectAttributes(&ObjectAttributes
,
297 OBJ_CASE_INSENSITIVE
,
301 Status
= ZwOpenKey(&KeyHandle
,
302 KEY_ENUMERATE_SUB_KEYS
,
304 if (!NT_SUCCESS(Status
))
309 KeyInfoLength
= sizeof(KEY_BASIC_INFORMATION
) + MAX_PATH
* sizeof(WCHAR
);
310 KeyInfo
= ExAllocatePool(NonPagedPool
, KeyInfoLength
);
314 return(STATUS_INSUFFICIENT_RESOURCES
);
320 Status
= ZwEnumerateKey(KeyHandle
,
326 if (NT_SUCCESS(Status
))
328 if (KeyInfo
->NameLength
< MAX_PATH
* sizeof(WCHAR
))
331 SubKeyName
.Length
= (USHORT
)KeyInfo
->NameLength
;
332 SubKeyName
.MaximumLength
= (USHORT
)KeyInfo
->NameLength
+ sizeof(WCHAR
);
333 SubKeyName
.Buffer
= KeyInfo
->Name
;
334 SubKeyName
.Buffer
[SubKeyName
.Length
/ sizeof(WCHAR
)] = 0;
336 DPRINT("KeyName: '%wZ'\n", &SubKeyName
);
337 IopCreateServiceListEntry(&SubKeyName
);
341 if (!NT_SUCCESS(Status
))
350 DPRINT("IoCreateDriverList() done\n");
352 return(STATUS_SUCCESS
);
355 NTSTATUS INIT_FUNCTION
356 IoDestroyDriverList(VOID
)
358 PSERVICE_GROUP CurrentGroup
;
359 PSERVICE CurrentService
;
360 PLIST_ENTRY NextEntry
, TempEntry
;
362 DPRINT("IoDestroyDriverList() called\n");
364 /* Destroy the Group List */
365 for (NextEntry
= GroupListHead
.Flink
, TempEntry
= NextEntry
->Flink
;
366 NextEntry
!= &GroupListHead
;
367 NextEntry
= TempEntry
, TempEntry
= NextEntry
->Flink
)
370 CurrentGroup
= CONTAINING_RECORD(NextEntry
,
374 /* Remove it from the list */
375 RemoveEntryList(&CurrentGroup
->GroupListEntry
);
378 ExFreePool(CurrentGroup
->GroupName
.Buffer
);
379 if (CurrentGroup
->TagArray
)
380 ExFreePool(CurrentGroup
->TagArray
);
381 ExFreePool(CurrentGroup
);
384 /* Destroy the Service List */
385 for (NextEntry
= ServiceListHead
.Flink
, TempEntry
= NextEntry
->Flink
;
386 NextEntry
!= &ServiceListHead
;
387 NextEntry
= TempEntry
, TempEntry
= NextEntry
->Flink
)
390 CurrentService
= CONTAINING_RECORD(NextEntry
,
394 /* Remove it from the list */
395 RemoveEntryList(&CurrentService
->ServiceListEntry
);
398 ExFreePool(CurrentService
->ServiceName
.Buffer
);
399 ExFreePool(CurrentService
->RegistryPath
.Buffer
);
400 if (CurrentService
->ServiceGroup
.Buffer
)
401 ExFreePool(CurrentService
->ServiceGroup
.Buffer
);
402 if (CurrentService
->ImagePath
.Buffer
)
403 ExFreePool(CurrentService
->ImagePath
.Buffer
);
404 ExFreePool(CurrentService
);
407 DPRINT("IoDestroyDriverList() done\n");
410 return STATUS_SUCCESS
;
413 static INIT_FUNCTION NTSTATUS
414 IopLoadDriver(PSERVICE Service
)
416 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
417 PUNICODE_STRING ImagePath
= &Service
->ImagePath
;
419 UNICODE_STRING ImageNameU
;
421 ImageName
= wcsrchr(ImagePath
->Buffer
, L
'\\');
423 ImageName
= ImagePath
->Buffer
;
427 RtlInitUnicodeString(&ImageNameU
, ImageName
);
429 IopDisplayLoadingMessage(&ImageNameU
);
431 Status
= ZwLoadDriver(&Service
->RegistryPath
);
432 IopBootLog(&Service
->ImagePath
, NT_SUCCESS(Status
) ? TRUE
: FALSE
);
433 if (!NT_SUCCESS(Status
))
435 DPRINT("IopLoadDriver() failed (Status %lx)\n", Status
);
437 if (Service
->ErrorControl
== 1)
441 else if (Service
->ErrorControl
== 2)
443 if (IsLastKnownGood
== FALSE
)
445 /* Boot last known good configuration */
448 else if (Service
->ErrorControl
== 3)
450 if (IsLastKnownGood
== FALSE
)
452 /* Boot last known good configuration */
465 * IopInitializeSystemDrivers
467 * Load drivers marked as system start.
477 IopInitializeSystemDrivers(VOID
)
479 PSERVICE_GROUP CurrentGroup
;
480 PSERVICE CurrentService
;
483 PLIST_ENTRY NextGroupEntry
, NextServiceEntry
;
485 DPRINT("IopInitializeSystemDrivers()\n");
488 for (NextGroupEntry
= GroupListHead
.Flink
;
489 NextGroupEntry
!= &GroupListHead
;
490 NextGroupEntry
= NextGroupEntry
->Flink
)
493 CurrentGroup
= CONTAINING_RECORD(NextGroupEntry
,
497 DPRINT("Group: %wZ\n", &CurrentGroup
->GroupName
);
499 /* Load all drivers with a valid tag */
500 for (i
= 0; i
< CurrentGroup
->TagCount
; i
++)
503 for (NextServiceEntry
= ServiceListHead
.Flink
;
504 NextServiceEntry
!= &ServiceListHead
;
505 NextServiceEntry
= NextServiceEntry
->Flink
)
508 CurrentService
= CONTAINING_RECORD(NextServiceEntry
,
512 if ((!RtlCompareUnicodeString(&CurrentGroup
->GroupName
,
513 &CurrentService
->ServiceGroup
,
515 (CurrentService
->Start
== SERVICE_SYSTEM_START
) &&
516 (CurrentService
->Tag
== CurrentGroup
->TagArray
[i
]))
519 DPRINT(" Path: %wZ\n", &CurrentService
->RegistryPath
);
520 Status
= IopLoadDriver(CurrentService
);
521 InbvIndicateProgress();
526 /* Load all drivers without a tag or with an invalid tag */
527 for (NextServiceEntry
= ServiceListHead
.Flink
;
528 NextServiceEntry
!= &ServiceListHead
;
529 NextServiceEntry
= NextServiceEntry
->Flink
)
532 CurrentService
= CONTAINING_RECORD(NextServiceEntry
,
536 if ((!RtlCompareUnicodeString(&CurrentGroup
->GroupName
,
537 &CurrentService
->ServiceGroup
,
539 (CurrentService
->Start
== SERVICE_SYSTEM_START
))
541 for (i
= 0; i
< CurrentGroup
->TagCount
; i
++)
543 if (CurrentGroup
->TagArray
[i
] == CurrentService
->Tag
)
549 if (i
>= CurrentGroup
->TagCount
)
551 DPRINT(" Path: %wZ\n", &CurrentService
->RegistryPath
);
552 Status
= IopLoadDriver(CurrentService
);
553 InbvIndicateProgress();
560 DPRINT("IopInitializeSystemDrivers() done\n");