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