xref: /reactos/ntoskrnl/config/cmconfig.c (revision 40462c92)
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 CODE_SEG("INIT")
18 NTSTATUS
19 NTAPI
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         Status = RtlAnsiStringToUnicodeString(&KeyName, &TempString, FALSE);
71         if (!NT_SUCCESS(Status))
72         {
73             NtClose(KeyHandle);
74             return Status;
75         }
76 
77         /* Create the key */
78         ParentHandle = KeyHandle;
79         InitializeObjectAttributes(&ObjectAttributes,
80                                    &KeyName,
81                                    OBJ_CASE_INSENSITIVE,
82                                    ParentHandle,
83                                    NULL);
84         Status = NtCreateKey(&KeyHandle,
85                              KEY_READ | KEY_WRITE,
86                              &ObjectAttributes,
87                              0,
88                              NULL,
89                              0,
90                              &Disposition);
91         NtClose(ParentHandle);
92 
93         /* Fail if the key couldn't be created, and make sure it's a new key */
94         if (!NT_SUCCESS(Status)) return Status;
95         ASSERT(Disposition == REG_CREATED_NEW_KEY);
96     }
97 
98     /* Setup the component information key */
99     RtlInitUnicodeString(&ValueName, L"Component Information");
100     Status = NtSetValueKey(KeyHandle,
101                            &ValueName,
102                            0,
103                            REG_BINARY,
104                            &Component->Flags,
105                            FIELD_OFFSET(CONFIGURATION_COMPONENT,
106                                         ConfigurationDataLength) -
107                            FIELD_OFFSET(CONFIGURATION_COMPONENT, Flags));
108     if (!NT_SUCCESS(Status))
109     {
110         /* Fail */
111         NtClose(KeyHandle);
112         return Status;
113     }
114 
115     /* Check if we have an identifier */
116     if (Component->IdentifierLength)
117     {
118         /* Build the string and convert it to Unicode */
119         RtlInitUnicodeString(&ValueName, L"Identifier");
120         RtlInitAnsiString(&TempString, Component->Identifier);
121         Status = RtlAnsiStringToUnicodeString(&ValueData,
122                                               &TempString,
123                                               TRUE);
124         if (NT_SUCCESS(Status))
125         {
126             /* Save the identifier in the registry */
127             Status = NtSetValueKey(KeyHandle,
128                                    &ValueName,
129                                    0,
130                                    REG_SZ,
131                                    ValueData.Buffer,
132                                    ValueData.Length + sizeof(UNICODE_NULL));
133             RtlFreeUnicodeString(&ValueData);
134         }
135 
136         /* Check for failure during conversion or registry write */
137         if (!NT_SUCCESS(Status))
138         {
139             /* Fail */
140             NtClose(KeyHandle);
141             return Status;
142         }
143     }
144 
145     /* Setup the configuration data string */
146     RtlInitUnicodeString(&ValueName, L"Configuration Data");
147 
148     /* Check if we got configuration data */
149     if (CurrentEntry->ConfigurationData)
150     {
151         /* Calculate the total length and check if it fits into our buffer */
152         Length = Component->ConfigurationDataLength +
153                  FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList);
154         if (Length > CmpConfigurationAreaSize)
155         {
156             ASSERTMSG("Component too large -- need reallocation!\n", FALSE);
157         }
158         else
159         {
160             /* Copy the data */
161             RtlCopyMemory(&CmpConfigurationData->PartialResourceList.Version,
162                           CurrentEntry->ConfigurationData,
163                           Component->ConfigurationDataLength);
164         }
165     }
166     else
167     {
168         /* No configuration data, setup defaults */
169         CmpConfigurationData->PartialResourceList.Version = 0;
170         CmpConfigurationData->PartialResourceList.Revision = 0;
171         CmpConfigurationData->PartialResourceList.Count = 0;
172         Length = FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST, PartialDescriptors) +
173                  FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList);
174     }
175 
176     /* Set the interface type and bus number */
177     CmpConfigurationData->InterfaceType = InterfaceType;
178     CmpConfigurationData->BusNumber = BusNumber;
179 
180     /* Save the actual data */
181     Status = NtSetValueKey(KeyHandle,
182                            &ValueName,
183                            0,
184                            REG_FULL_RESOURCE_DESCRIPTOR,
185                            CmpConfigurationData,
186                            Length);
187     if (!NT_SUCCESS(Status))
188     {
189         /* Fail */
190         NtClose(KeyHandle);
191     }
192     else
193     {
194         /* Return the new handle */
195         *NewHandle = KeyHandle;
196     }
197 
198     /* Return status */
199     return Status;
200 }
201 
202 CODE_SEG("INIT")
203 NTSTATUS
204 NTAPI
205 CmpSetupConfigurationTree(IN PCONFIGURATION_COMPONENT_DATA CurrentEntry,
206                           IN HANDLE ParentHandle,
207                           IN INTERFACE_TYPE InterfaceType,
208                           IN ULONG BusNumber)
209 {
210     PCONFIGURATION_COMPONENT Component;
211     USHORT DeviceIndexTable[MaximumType + 1] = {0};
212     ULONG Interface = InterfaceType, Bus = BusNumber, i;
213     NTSTATUS Status;
214     HANDLE NewHandle;
215 
216     /* Loop each entry */
217     while (CurrentEntry)
218     {
219         /* Check if this is an adapter */
220         Component = &CurrentEntry->ComponentEntry;
221         if ((Component->Class == AdapterClass) &&
222             (CurrentEntry->Parent->ComponentEntry.Class == SystemClass))
223         {
224             /* Check what kind of adapter it is */
225             switch (Component->Type)
226             {
227                 /* EISA */
228                 case EisaAdapter:
229                 {
230                     /* Fixup information */
231                     Interface = Eisa;
232                     Bus = CmpTypeCount[EisaAdapter]++;
233                     break;
234                 }
235 
236                 /* Turbo-channel */
237                 case TcAdapter:
238                 {
239                     /* Fixup information */
240                     Interface = TurboChannel;
241                     Bus = CmpTypeCount[TurboChannel]++;
242                     break;
243                 }
244 
245                 /* ISA, PCI, etc busses */
246                 case MultiFunctionAdapter:
247                 {
248                     /* Check if we have an  identifier */
249                     if (Component->Identifier)
250                     {
251                         /* Loop each multi-function adapter type */
252                         for (i = 0; CmpMultifunctionTypes[i].Identifier; i++)
253                         {
254                             /* Check for a name match */
255                             if (!_stricmp(CmpMultifunctionTypes[i].Identifier,
256                                           Component->Identifier))
257                             {
258                                 /* Match found */
259                                 break;
260                             }
261                         }
262 
263                         /* Fix up information */
264                         Interface = CmpMultifunctionTypes[i].InterfaceType;
265                         Bus = CmpMultifunctionTypes[i].Count++;
266                     }
267                     break;
268                 }
269 
270                 /* SCSI Bus */
271                 case ScsiAdapter:
272                 {
273                     /* Fix up */
274                     Interface = Internal;
275                     Bus = CmpTypeCount[ScsiAdapter]++;
276                     break;
277                 }
278 
279                 /* Unknown */
280                 default:
281                 {
282                     Interface = -1;
283                     Bus = CmpUnknownBusCount++;
284                     break;
285                 }
286             }
287         }
288 
289         /* Dump information on the component */
290 
291         /* Setup the hardware node */
292         Status = CmpInitializeRegistryNode(CurrentEntry,
293                                            ParentHandle,
294                                            &NewHandle,
295                                            Interface,
296                                            Bus,
297                                            DeviceIndexTable);
298         if (!NT_SUCCESS(Status)) return Status;
299 
300         /* Check for children */
301         if (CurrentEntry->Child)
302         {
303             /* Recurse child */
304             Status = CmpSetupConfigurationTree(CurrentEntry->Child,
305                                                NewHandle,
306                                                Interface,
307                                                Bus);
308             if (!NT_SUCCESS(Status))
309             {
310                 /* Fail */
311                 NtClose(NewHandle);
312                 return Status;
313             }
314         }
315 
316         /* Get to the next entry */
317         NtClose(NewHandle);
318         CurrentEntry = CurrentEntry->Sibling;
319     }
320 
321     /* We're done */
322     return STATUS_SUCCESS;
323 }
324 
325 CODE_SEG("INIT")
326 NTSTATUS
327 NTAPI
328 CmpInitializeHardwareConfiguration(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
329 {
330     NTSTATUS Status;
331     OBJECT_ATTRIBUTES ObjectAttributes;
332     HANDLE KeyHandle;
333     ULONG Disposition;
334     UNICODE_STRING KeyName;
335 
336     /* Setup the key name */
337     RtlInitUnicodeString(&KeyName,
338                          L"\\Registry\\Machine\\Hardware\\DeviceMap");
339     InitializeObjectAttributes(&ObjectAttributes,
340                                &KeyName,
341                                OBJ_CASE_INSENSITIVE,
342                                NULL,
343                                NULL);
344 
345     /* Create the device map key */
346     Status = NtCreateKey(&KeyHandle,
347                          KEY_READ | KEY_WRITE,
348                          &ObjectAttributes,
349                          0,
350                          NULL,
351                          0,
352                          &Disposition);
353     if (!NT_SUCCESS(Status))
354         return Status;
355     NtClose(KeyHandle);
356 
357     /* Nobody should've created this key yet! */
358     ASSERT(Disposition == REG_CREATED_NEW_KEY);
359 
360     /* Setup the key name */
361     RtlInitUnicodeString(&KeyName,
362                          L"\\Registry\\Machine\\Hardware\\Description");
363     InitializeObjectAttributes(&ObjectAttributes,
364                                &KeyName,
365                                OBJ_CASE_INSENSITIVE,
366                                NULL,
367                                NULL);
368 
369     /* Create the description key */
370     Status = NtCreateKey(&KeyHandle,
371                           KEY_READ | KEY_WRITE,
372                           &ObjectAttributes,
373                           0,
374                           NULL,
375                           0,
376                           &Disposition);
377     if (!NT_SUCCESS(Status))
378         return Status;
379 
380     /* Nobody should've created this key yet! */
381     ASSERT(Disposition == REG_CREATED_NEW_KEY);
382 
383     /* Allocate the configuration data buffer */
384     CmpConfigurationData = ExAllocatePoolWithTag(PagedPool,
385                                                  CmpConfigurationAreaSize,
386                                                  TAG_CM);
387     if (!CmpConfigurationData)
388     {
389         NtClose(KeyHandle);
390         return STATUS_INSUFFICIENT_RESOURCES;
391     }
392 
393     /* Check if we got anything from NTLDR */
394     if (LoaderBlock->ConfigurationRoot)
395     {
396         /* Setup the configuration tree */
397         Status = CmpSetupConfigurationTree(LoaderBlock->ConfigurationRoot,
398                                            KeyHandle,
399                                            -1,
400                                            -1);
401     }
402     else
403     {
404         /* Nothing else to do */
405         Status = STATUS_SUCCESS;
406     }
407 
408     /* Free the buffer, close our handle and return status */
409     ExFreePoolWithTag(CmpConfigurationData, TAG_CM);
410     NtClose(KeyHandle);
411     return Status;
412 }
413