xref: /reactos/ntoskrnl/config/cmconfig.c (revision 60eea2d7)
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 }
396