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(PVOID ServiceName
,
54 /* PRIVATE FUNCTIONS **********************************************************/
57 IopGetGroupOrderList(PWSTR ValueName
,
66 DPRINT("IopGetGroupOrderList(%S, %x, 0x%p, %x, 0x%p, 0x%p)\n",
67 ValueName
, ValueType
, ValueData
, ValueLength
, Context
, EntryContext
);
69 if (ValueType
== REG_BINARY
&&
71 ValueLength
>= sizeof(ULONG
) &&
72 ValueLength
>= (*(PULONG
)ValueData
+ 1) * sizeof(ULONG
))
74 Group
= (PSERVICE_GROUP
)Context
;
75 Group
->TagCount
= ((PULONG
)ValueData
)[0];
76 if (Group
->TagCount
> 0)
78 if (ValueLength
>= (Group
->TagCount
+ 1) * sizeof(ULONG
))
80 Group
->TagArray
= ExAllocatePool(NonPagedPool
, Group
->TagCount
* sizeof(ULONG
));
81 if (Group
->TagArray
== NULL
)
84 return STATUS_INSUFFICIENT_RESOURCES
;
86 memcpy(Group
->TagArray
, (PULONG
)ValueData
+ 1, Group
->TagCount
* sizeof(ULONG
));
91 return STATUS_UNSUCCESSFUL
;
95 return STATUS_SUCCESS
;
99 IopCreateGroupListEntry(PWSTR ValueName
,
106 PSERVICE_GROUP Group
;
107 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
111 if (ValueType
== REG_SZ
)
113 DPRINT("GroupName: '%S'\n", (PWCHAR
)ValueData
);
115 Group
= ExAllocatePool(NonPagedPool
,
116 sizeof(SERVICE_GROUP
));
119 return(STATUS_INSUFFICIENT_RESOURCES
);
122 RtlZeroMemory(Group
, sizeof(SERVICE_GROUP
));
124 if (!RtlCreateUnicodeString(&Group
->GroupName
, (PWSTR
)ValueData
))
127 return(STATUS_INSUFFICIENT_RESOURCES
);
130 RtlZeroMemory(&QueryTable
, sizeof(QueryTable
));
131 QueryTable
[0].Name
= (PWSTR
)ValueData
;
132 QueryTable
[0].QueryRoutine
= IopGetGroupOrderList
;
134 Status
= RtlQueryRegistryValues(RTL_REGISTRY_CONTROL
,
139 DPRINT("%x %d %S\n", Status
, Group
->TagCount
, (PWSTR
)ValueData
);
141 InsertTailList(&GroupListHead
,
142 &Group
->GroupListEntry
);
145 return(STATUS_SUCCESS
);
149 static NTSTATUS NTAPI
150 IopCreateServiceListEntry(PUNICODE_STRING ServiceName
)
152 RTL_QUERY_REGISTRY_TABLE QueryTable
[7];
155 ULONG DefaultTag
= MAXULONG
;
157 DPRINT("ServiceName: '%wZ'\n", ServiceName
);
159 /* Allocate service entry */
160 Service
= (PSERVICE
)ExAllocatePool(NonPagedPool
, sizeof(SERVICE
));
163 DPRINT1("ExAllocatePool() failed\n");
164 return(STATUS_INSUFFICIENT_RESOURCES
);
166 RtlZeroMemory(Service
, sizeof(SERVICE
));
168 /* Get service data */
169 RtlZeroMemory(&QueryTable
,
172 QueryTable
[0].Name
= L
"Start";
173 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
174 QueryTable
[0].EntryContext
= &Service
->Start
;
176 QueryTable
[1].Name
= L
"Type";
177 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
178 QueryTable
[1].EntryContext
= &Service
->Type
;
180 QueryTable
[2].Name
= L
"ErrorControl";
181 QueryTable
[2].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
182 QueryTable
[2].EntryContext
= &Service
->ErrorControl
;
184 QueryTable
[3].Name
= L
"Group";
185 QueryTable
[3].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
186 QueryTable
[3].EntryContext
= &Service
->ServiceGroup
;
188 QueryTable
[4].Name
= L
"ImagePath";
189 QueryTable
[4].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
190 QueryTable
[4].EntryContext
= &Service
->ImagePath
;
192 QueryTable
[5].Name
= L
"Tag";
193 QueryTable
[5].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
194 QueryTable
[5].EntryContext
= &Service
->Tag
;
195 QueryTable
[5].DefaultData
= &DefaultTag
;
196 QueryTable
[5].DefaultType
= REG_DWORD
;
197 QueryTable
[5].DefaultLength
= sizeof(DefaultTag
);
199 Status
= RtlQueryRegistryValues(RTL_REGISTRY_SERVICES
,
204 if (!NT_SUCCESS(Status
) || Service
->Start
> 1)
207 * If something goes wrong during RtlQueryRegistryValues
208 * it'll just drop everything on the floor and return,
209 * so you have to check if the buffers were filled.
210 * Luckily we zerofilled the Service.
212 if (Service
->ServiceGroup
.Buffer
)
214 ExFreePoolWithTag(Service
->ServiceGroup
.Buffer
, TAG_RTLREGISTRY
);
216 if (Service
->ImagePath
.Buffer
)
218 ExFreePoolWithTag(Service
->ImagePath
.Buffer
, TAG_RTLREGISTRY
);
224 /* Copy service name */
225 Service
->ServiceName
.Length
= ServiceName
->Length
;
226 Service
->ServiceName
.MaximumLength
= ServiceName
->Length
+ sizeof(WCHAR
);
227 Service
->ServiceName
.Buffer
= ExAllocatePool(NonPagedPool
,
228 Service
->ServiceName
.MaximumLength
);
229 RtlCopyMemory(Service
->ServiceName
.Buffer
,
231 ServiceName
->Length
);
232 Service
->ServiceName
.Buffer
[ServiceName
->Length
/ sizeof(WCHAR
)] = 0;
234 /* Build registry path */
235 Service
->RegistryPath
.MaximumLength
= MAX_PATH
* sizeof(WCHAR
);
236 Service
->RegistryPath
.Buffer
= ExAllocatePool(NonPagedPool
,
237 MAX_PATH
* sizeof(WCHAR
));
238 wcscpy(Service
->RegistryPath
.Buffer
,
239 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
240 wcscat(Service
->RegistryPath
.Buffer
,
241 Service
->ServiceName
.Buffer
);
242 Service
->RegistryPath
.Length
= wcslen(Service
->RegistryPath
.Buffer
) * sizeof(WCHAR
);
244 DPRINT("ServiceName: '%wZ'\n", &Service
->ServiceName
);
245 DPRINT("RegistryPath: '%wZ'\n", &Service
->RegistryPath
);
246 DPRINT("ServiceGroup: '%wZ'\n", &Service
->ServiceGroup
);
247 DPRINT("ImagePath: '%wZ'\n", &Service
->ImagePath
);
248 DPRINT("Start %lx Type %lx Tag %lx ErrorControl %lx\n",
249 Service
->Start
, Service
->Type
, Service
->Tag
, Service
->ErrorControl
);
251 /* Append service entry */
252 InsertTailList(&ServiceListHead
,
253 &Service
->ServiceListEntry
);
255 return(STATUS_SUCCESS
);
259 NTSTATUS INIT_FUNCTION
260 IoCreateDriverList(VOID
)
262 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
263 PKEY_BASIC_INFORMATION KeyInfo
= NULL
;
264 OBJECT_ATTRIBUTES ObjectAttributes
;
265 UNICODE_STRING ServicesKeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services");
266 UNICODE_STRING SubKeyName
;
271 ULONG KeyInfoLength
= 0;
272 ULONG ReturnedLength
;
274 DPRINT("IoCreateDriverList() called\n");
276 /* Initialize basic variables */
277 InitializeListHead(&GroupListHead
);
278 InitializeListHead(&ServiceListHead
);
280 /* Build group order list */
281 RtlZeroMemory(&QueryTable
,
284 QueryTable
[0].Name
= L
"List";
285 QueryTable
[0].QueryRoutine
= IopCreateGroupListEntry
;
287 Status
= RtlQueryRegistryValues(RTL_REGISTRY_CONTROL
,
288 L
"ServiceGroupOrder",
292 if (!NT_SUCCESS(Status
))
295 /* Enumerate services and create the service list */
296 InitializeObjectAttributes(&ObjectAttributes
,
298 OBJ_CASE_INSENSITIVE
,
302 Status
= ZwOpenKey(&KeyHandle
,
303 KEY_ENUMERATE_SUB_KEYS
,
305 if (!NT_SUCCESS(Status
))
310 KeyInfoLength
= sizeof(KEY_BASIC_INFORMATION
) + MAX_PATH
* sizeof(WCHAR
);
311 KeyInfo
= ExAllocatePool(NonPagedPool
, KeyInfoLength
);
315 return(STATUS_INSUFFICIENT_RESOURCES
);
321 Status
= ZwEnumerateKey(KeyHandle
,
327 if (NT_SUCCESS(Status
))
329 if (KeyInfo
->NameLength
< MAX_PATH
* sizeof(WCHAR
))
332 SubKeyName
.Length
= (USHORT
)KeyInfo
->NameLength
;
333 SubKeyName
.MaximumLength
= (USHORT
)KeyInfo
->NameLength
+ sizeof(WCHAR
);
334 SubKeyName
.Buffer
= KeyInfo
->Name
;
335 SubKeyName
.Buffer
[SubKeyName
.Length
/ sizeof(WCHAR
)] = 0;
337 DPRINT("KeyName: '%wZ'\n", &SubKeyName
);
338 IopCreateServiceListEntry(&SubKeyName
);
342 if (!NT_SUCCESS(Status
))
351 DPRINT("IoCreateDriverList() done\n");
353 return(STATUS_SUCCESS
);
356 NTSTATUS INIT_FUNCTION
357 IoDestroyDriverList(VOID
)
359 PSERVICE_GROUP CurrentGroup
;
360 PSERVICE CurrentService
;
361 PLIST_ENTRY NextEntry
, TempEntry
;
363 DPRINT("IoDestroyDriverList() called\n");
365 /* Destroy the Group List */
366 for (NextEntry
= GroupListHead
.Flink
, TempEntry
= NextEntry
->Flink
;
367 NextEntry
!= &GroupListHead
;
368 NextEntry
= TempEntry
, TempEntry
= NextEntry
->Flink
)
371 CurrentGroup
= CONTAINING_RECORD(NextEntry
,
375 /* Remove it from the list */
376 RemoveEntryList(&CurrentGroup
->GroupListEntry
);
379 ExFreePool(CurrentGroup
->GroupName
.Buffer
);
380 if (CurrentGroup
->TagArray
)
381 ExFreePool(CurrentGroup
->TagArray
);
382 ExFreePool(CurrentGroup
);
385 /* Destroy the Service List */
386 for (NextEntry
= ServiceListHead
.Flink
, TempEntry
= NextEntry
->Flink
;
387 NextEntry
!= &ServiceListHead
;
388 NextEntry
= TempEntry
, TempEntry
= NextEntry
->Flink
)
391 CurrentService
= CONTAINING_RECORD(NextEntry
,
395 /* Remove it from the list */
396 RemoveEntryList(&CurrentService
->ServiceListEntry
);
399 ExFreePool(CurrentService
->ServiceName
.Buffer
);
400 ExFreePool(CurrentService
->RegistryPath
.Buffer
);
401 if (CurrentService
->ServiceGroup
.Buffer
)
402 ExFreePool(CurrentService
->ServiceGroup
.Buffer
);
403 if (CurrentService
->ImagePath
.Buffer
)
404 ExFreePool(CurrentService
->ImagePath
.Buffer
);
405 ExFreePool(CurrentService
);
408 DPRINT("IoDestroyDriverList() done\n");
411 return STATUS_SUCCESS
;
414 static INIT_FUNCTION NTSTATUS
415 IopLoadDriver(PSERVICE Service
)
417 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
419 IopDisplayLoadingMessage(Service
->ServiceName
.Buffer
, TRUE
);
420 Status
= ZwLoadDriver(&Service
->RegistryPath
);
421 IopBootLog(&Service
->ImagePath
, NT_SUCCESS(Status
) ? TRUE
: FALSE
);
422 if (!NT_SUCCESS(Status
))
424 DPRINT("IopLoadDriver() failed (Status %lx)\n", Status
);
426 if (Service
->ErrorControl
== 1)
430 else if (Service
->ErrorControl
== 2)
432 if (IsLastKnownGood
== FALSE
)
434 /* Boot last known good configuration */
437 else if (Service
->ErrorControl
== 3)
439 if (IsLastKnownGood
== FALSE
)
441 /* Boot last known good configuration */
454 * IopInitializeSystemDrivers
456 * Load drivers marked as system start.
466 IopInitializeSystemDrivers(VOID
)
468 PSERVICE_GROUP CurrentGroup
;
469 PSERVICE CurrentService
;
472 PLIST_ENTRY NextGroupEntry
, NextServiceEntry
;
474 DPRINT("IopInitializeSystemDrivers()\n");
477 for (NextGroupEntry
= GroupListHead
.Flink
;
478 NextGroupEntry
!= &GroupListHead
;
479 NextGroupEntry
= NextGroupEntry
->Flink
)
482 CurrentGroup
= CONTAINING_RECORD(NextGroupEntry
,
486 DPRINT("Group: %wZ\n", &CurrentGroup
->GroupName
);
488 /* Load all drivers with a valid tag */
489 for (i
= 0; i
< CurrentGroup
->TagCount
; i
++)
492 for (NextServiceEntry
= ServiceListHead
.Flink
;
493 NextServiceEntry
!= &ServiceListHead
;
494 NextServiceEntry
= NextServiceEntry
->Flink
)
497 CurrentService
= CONTAINING_RECORD(NextServiceEntry
,
501 if ((!RtlCompareUnicodeString(&CurrentGroup
->GroupName
,
502 &CurrentService
->ServiceGroup
,
504 (CurrentService
->Start
== SERVICE_SYSTEM_START
) &&
505 (CurrentService
->Tag
== CurrentGroup
->TagArray
[i
]))
508 DPRINT(" Path: %wZ\n", &CurrentService
->RegistryPath
);
509 Status
= IopLoadDriver(CurrentService
);
514 /* Load all drivers without a tag or with an invalid tag */
515 for (NextServiceEntry
= ServiceListHead
.Flink
;
516 NextServiceEntry
!= &ServiceListHead
;
517 NextServiceEntry
= NextServiceEntry
->Flink
)
520 CurrentService
= CONTAINING_RECORD(NextServiceEntry
,
524 if ((!RtlCompareUnicodeString(&CurrentGroup
->GroupName
,
525 &CurrentService
->ServiceGroup
,
527 (CurrentService
->Start
== SERVICE_SYSTEM_START
))
529 for (i
= 0; i
< CurrentGroup
->TagCount
; i
++)
531 if (CurrentGroup
->TagArray
[i
] == CurrentService
->Tag
)
537 if (i
>= CurrentGroup
->TagCount
)
539 DPRINT(" Path: %wZ\n", &CurrentService
->RegistryPath
);
540 Status
= IopLoadDriver(CurrentService
);
546 DPRINT("IopInitializeSystemDrivers() done\n");