[CMAKE]
[reactos.git] / ntoskrnl / config / cmconfig.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/config/cmconfig.c
5 * PURPOSE: Configuration Manager - System Configuration Routines
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include "ntoskrnl.h"
12 #define NDEBUG
13 #include "debug.h"
14
15 /* FUNCTIONS *****************************************************************/
16
17 NTSTATUS
18 NTAPI
19 INIT_FUNCTION
20 CmpInitializeRegistryNode(IN PCONFIGURATION_COMPONENT_DATA CurrentEntry,
21 IN HANDLE NodeHandle,
22 OUT PHANDLE NewHandle,
23 IN INTERFACE_TYPE InterfaceType,
24 IN ULONG BusNumber,
25 IN PUSHORT DeviceIndexTable)
26 {
27 NTSTATUS Status;
28 OBJECT_ATTRIBUTES ObjectAttributes;
29 UNICODE_STRING KeyName, ValueName, ValueData;
30 HANDLE KeyHandle, ParentHandle;
31 ANSI_STRING TempString;
32 CHAR TempBuffer[12];
33 WCHAR Buffer[12];
34 PCONFIGURATION_COMPONENT Component;
35 ULONG Disposition, Length = 0;
36
37 /* Get the component */
38 Component = &CurrentEntry->ComponentEntry;
39
40 /* Set system class components to ARC system type */
41 if (Component->Class == SystemClass) Component->Type = ArcSystem;
42
43 /* Create a key for the component */
44 InitializeObjectAttributes(&ObjectAttributes,
45 &CmTypeName[Component->Type],
46 OBJ_CASE_INSENSITIVE,
47 NodeHandle,
48 NULL);
49 Status = NtCreateKey(&KeyHandle,
50 KEY_READ | KEY_WRITE,
51 &ObjectAttributes,
52 0,
53 NULL,
54 0,
55 &Disposition);
56 if (!NT_SUCCESS(Status)) return Status;
57
58 /* Check if this is anything but a system class component */
59 if (Component->Class != SystemClass)
60 {
61 /* Build the sub-component string */
62 RtlIntegerToChar(DeviceIndexTable[Component->Type]++,
63 10,
64 12,
65 TempBuffer);
66 RtlInitAnsiString(&TempString, TempBuffer);
67
68 /* Convert it to Unicode */
69 RtlInitEmptyUnicodeString(&KeyName, Buffer, sizeof(Buffer));
70 RtlAnsiStringToUnicodeString(&KeyName, &TempString, FALSE);
71
72 /* Create the key */
73 ParentHandle = KeyHandle;
74 InitializeObjectAttributes(&ObjectAttributes,
75 &KeyName,
76 OBJ_CASE_INSENSITIVE,
77 ParentHandle,
78 NULL);
79 Status = NtCreateKey(&KeyHandle,
80 KEY_READ | KEY_WRITE,
81 &ObjectAttributes,
82 0,
83 NULL,
84 0,
85 &Disposition);
86 NtClose(ParentHandle);
87
88 /* Fail if the key couldn't be created, and make sure it's a new key */
89 if (!NT_SUCCESS(Status)) return Status;
90 ASSERT(Disposition == REG_CREATED_NEW_KEY);
91 }
92
93 /* Setup the component information key */
94 RtlInitUnicodeString(&ValueName, L"Component Information");
95 Status = NtSetValueKey(KeyHandle,
96 &ValueName,
97 0,
98 REG_BINARY,
99 &Component->Flags,
100 FIELD_OFFSET(CONFIGURATION_COMPONENT,
101 ConfigurationDataLength) -
102 FIELD_OFFSET(CONFIGURATION_COMPONENT, Flags));
103 if (!NT_SUCCESS(Status))
104 {
105 /* Fail */
106 NtClose(KeyHandle);
107 return Status;
108 }
109
110 /* Check if we have an identifier */
111 if (Component->IdentifierLength)
112 {
113 /* Build the string and convert it to Unicode */
114 RtlInitUnicodeString(&ValueName, L"Identifier");
115 RtlInitAnsiString(&TempString, Component->Identifier);
116 Status = RtlAnsiStringToUnicodeString(&ValueData,
117 &TempString,
118 TRUE);
119 if (NT_SUCCESS(Status))
120 {
121 /* Save the identifier in the registry */
122 Status = NtSetValueKey(KeyHandle,
123 &ValueName,
124 0,
125 REG_SZ,
126 ValueData.Buffer,
127 ValueData.Length + sizeof(UNICODE_NULL));
128 RtlFreeUnicodeString(&ValueData);
129 }
130
131 /* Check for failure during conversion or registry write */
132 if (!NT_SUCCESS(Status))
133 {
134 /* Fail */
135 NtClose(KeyHandle);
136 return Status;
137 }
138 }
139
140 /* Setup the configuration data string */
141 RtlInitUnicodeString(&ValueName, L"Configuration Data");
142
143 /* Check if we got configuration data */
144 if (CurrentEntry->ConfigurationData)
145 {
146 /* Calculate the total length and check if it fits into our buffer */
147 Length = Component->ConfigurationDataLength +
148 FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList);
149 if (Length > CmpConfigurationAreaSize)
150 {
151 ASSERTMSG("Component too large -- need reallocation!", FALSE);
152 }
153 else
154 {
155 /* Copy the data */
156 RtlCopyMemory(&CmpConfigurationData->PartialResourceList.Version,
157 CurrentEntry->ConfigurationData,
158 Component->ConfigurationDataLength);
159 }
160 }
161 else
162 {
163 /* No configuration data, setup defaults */
164 CmpConfigurationData->PartialResourceList.Version = 0;
165 CmpConfigurationData->PartialResourceList.Revision = 0;
166 CmpConfigurationData->PartialResourceList.Count = 0;
167 Length = FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST, PartialDescriptors) +
168 FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList);
169 }
170
171 /* Set the interface type and bus number */
172 CmpConfigurationData->InterfaceType = InterfaceType;
173 CmpConfigurationData->BusNumber = BusNumber;
174
175 /* Save the actual data */
176 Status = NtSetValueKey(KeyHandle,
177 &ValueName,
178 0,
179 REG_FULL_RESOURCE_DESCRIPTOR,
180 CmpConfigurationData,
181 Length);
182 if (!NT_SUCCESS(Status))
183 {
184 /* Fail */
185 NtClose(KeyHandle);
186 }
187 else
188 {
189 /* Return the new handle */
190 *NewHandle = KeyHandle;
191 }
192
193 /* Return status */
194 return Status;
195 }
196
197 NTSTATUS
198 NTAPI
199 INIT_FUNCTION
200 CmpSetupConfigurationTree(IN PCONFIGURATION_COMPONENT_DATA CurrentEntry,
201 IN HANDLE ParentHandle,
202 IN INTERFACE_TYPE InterfaceType,
203 IN ULONG BusNumber)
204 {
205 PCONFIGURATION_COMPONENT Component;
206 USHORT DeviceIndexTable[MaximumType + 1] = {0};
207 ULONG Interface = InterfaceType, Bus = BusNumber, i;
208 NTSTATUS Status;
209 HANDLE NewHandle;
210
211 /* Loop each entry */
212 while (CurrentEntry)
213 {
214 /* Check if this is an adapter */
215 Component = &CurrentEntry->ComponentEntry;
216 if ((Component->Class == AdapterClass) &&
217 (CurrentEntry->Parent->ComponentEntry.Class == SystemClass))
218 {
219 /* Check what kind of adapter it is */
220 switch (Component->Type)
221 {
222 /* EISA */
223 case EisaAdapter:
224
225 /* Fixup information */
226 Interface = Eisa;
227 Bus = CmpTypeCount[EisaAdapter]++;
228 break;
229
230 /* Turbo-channel */
231 case TcAdapter:
232
233 /* Fixup information */
234 Interface = TurboChannel;
235 Bus = CmpTypeCount[TurboChannel]++;
236 break;
237
238 /* ISA, PCI, etc busses */
239 case MultiFunctionAdapter:
240
241 /* Check if we have an identifier */
242 if (Component->Identifier)
243 {
244 /* Loop each multi-function adapter type */
245 for (i = 0; CmpMultifunctionTypes[i].Identifier; i++)
246 {
247 /* Check for a name match */
248 if (!_stricmp(CmpMultifunctionTypes[i].Identifier,
249 Component->Identifier))
250 {
251 /* Match found */
252 break;
253 }
254 }
255
256 /* Fix up information */
257 Interface = CmpMultifunctionTypes[i].InterfaceType;
258 Bus = CmpMultifunctionTypes[i].Count++;
259 }
260 break;
261
262 /* SCSI Bus */
263 case ScsiAdapter:
264
265 /* Fix up */
266 Interface = Internal;
267 Bus = CmpTypeCount[ScsiAdapter]++;
268 break;
269
270 /* Unknown */
271 default:
272 Interface = -1;
273 Bus = CmpUnknownBusCount++;
274 break;
275 }
276 }
277
278 /* Dump information on the component */
279
280 /* Setup the hardware node */
281 Status = CmpInitializeRegistryNode(CurrentEntry,
282 ParentHandle,
283 &NewHandle,
284 Interface,
285 Bus,
286 DeviceIndexTable);
287 if (!NT_SUCCESS(Status)) return Status;
288
289 /* Check for children */
290 if (CurrentEntry->Child)
291 {
292 /* Recurse child */
293 Status = CmpSetupConfigurationTree(CurrentEntry->Child,
294 NewHandle,
295 Interface,
296 Bus);
297 if (!NT_SUCCESS(Status))
298 {
299 /* Fail */
300 NtClose(NewHandle);
301 return Status;
302 }
303 }
304
305 /* Get to the next entry */
306 NtClose(NewHandle);
307 CurrentEntry = CurrentEntry->Sibling;
308 }
309
310 /* We're done */
311 return STATUS_SUCCESS;
312 }
313
314 NTSTATUS
315 NTAPI
316 INIT_FUNCTION
317 CmpInitializeHardwareConfiguration(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
318 {
319 NTSTATUS Status;
320 OBJECT_ATTRIBUTES ObjectAttributes;
321 HANDLE KeyHandle;
322 ULONG Disposition;
323 UNICODE_STRING KeyName;
324
325 /* Setup the key name */
326 RtlInitUnicodeString(&KeyName,
327 L"\\Registry\\Machine\\Hardware\\DeviceMap");
328 InitializeObjectAttributes(&ObjectAttributes,
329 &KeyName,
330 OBJ_CASE_INSENSITIVE,
331 NULL,
332 NULL);
333
334 /* Create the device map key */
335 Status = NtCreateKey(&KeyHandle,
336 KEY_READ | KEY_WRITE,
337 &ObjectAttributes,
338 0,
339 NULL,
340 0,
341 &Disposition);
342 if (!NT_SUCCESS(Status)) return Status;
343 NtClose(KeyHandle);
344
345 /* Nobody should've created this key yet! */
346 ASSERT(Disposition == REG_CREATED_NEW_KEY);
347
348 /* Setup the key name */
349 RtlInitUnicodeString(&KeyName,
350 L"\\Registry\\Machine\\Hardware\\Description");
351 InitializeObjectAttributes(&ObjectAttributes,
352 &KeyName,
353 OBJ_CASE_INSENSITIVE,
354 NULL,
355 NULL);
356
357 /* Create the description key */
358 Status = NtCreateKey(&KeyHandle,
359 KEY_READ | KEY_WRITE,
360 &ObjectAttributes,
361 0,
362 NULL,
363 0,
364 &Disposition);
365 if (!NT_SUCCESS(Status)) return Status;
366
367 /* Nobody should've created this key yet! */
368 ASSERT(Disposition == REG_CREATED_NEW_KEY);
369
370 /* Allocate the configuration data buffer */
371 CmpConfigurationData = ExAllocatePoolWithTag(PagedPool,
372 CmpConfigurationAreaSize,
373 TAG_CM);
374 if (!CmpConfigurationData) return STATUS_INSUFFICIENT_RESOURCES;
375
376 /* Check if we got anything from NTLDR */
377 if (LoaderBlock->ConfigurationRoot)
378 {
379 /* Setup the configuration tree */
380 Status = CmpSetupConfigurationTree(LoaderBlock->ConfigurationRoot,
381 KeyHandle,
382 -1,
383 -1);
384 }
385 else
386 {
387 /* Nothing else to do */
388 Status = STATUS_SUCCESS;
389 }
390
391 /* Close our handle, free the buffer and return status */
392 ExFreePoolWithTag(CmpConfigurationData, TAG_CM);
393 NtClose(KeyHandle);
394 return Status;
395 }