xref: /reactos/ntoskrnl/config/cmconfig.c (revision cce399e7)
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     INTERFACE_TYPE Interface = InterfaceType;
213     ULONG Bus = BusNumber, i;
214     NTSTATUS Status;
215     HANDLE NewHandle;
216 
217     /* Loop each entry */
218     while (CurrentEntry)
219     {
220         /* Check if this is an adapter */
221         Component = &CurrentEntry->ComponentEntry;
222         if ((Component->Class == AdapterClass) &&
223             (CurrentEntry->Parent->ComponentEntry.Class == SystemClass))
224         {
225             /* Check what kind of adapter it is */
226             switch (Component->Type)
227             {
228                 /* EISA */
229                 case EisaAdapter:
230                 {
231                     /* Fixup information */
232                     Interface = Eisa;
233                     Bus = CmpTypeCount[EisaAdapter]++;
234                     break;
235                 }
236 
237                 /* Turbo-channel */
238                 case TcAdapter:
239                 {
240                     /* Fixup information */
241                     Interface = TurboChannel;
242                     Bus = CmpTypeCount[TurboChannel]++;
243                     break;
244                 }
245 
246                 /* ISA, PCI, etc busses */
247                 case MultiFunctionAdapter:
248                 {
249                     /* Check if we have an  identifier */
250                     if (Component->Identifier)
251                     {
252                         /* Loop each multi-function adapter type */
253                         for (i = 0; CmpMultifunctionTypes[i].Identifier; i++)
254                         {
255                             /* Check for a name match */
256                             if (!_stricmp(CmpMultifunctionTypes[i].Identifier,
257                                           Component->Identifier))
258                             {
259                                 /* Match found */
260                                 break;
261                             }
262                         }
263 
264                         /* Fix up information */
265                         Interface = CmpMultifunctionTypes[i].InterfaceType;
266                         Bus = CmpMultifunctionTypes[i].Count++;
267                     }
268                     break;
269                 }
270 
271                 /* SCSI Bus */
272                 case ScsiAdapter:
273                 {
274                     /* Fix up */
275                     Interface = Internal;
276                     Bus = CmpTypeCount[ScsiAdapter]++;
277                     break;
278                 }
279 
280                 /* Unknown */
281                 default:
282                 {
283                     Interface = InterfaceTypeUndefined;
284                     Bus = CmpUnknownBusCount++;
285                     break;
286                 }
287             }
288         }
289 
290         /* Dump information on the component */
291 
292         /* Setup the hardware node */
293         Status = CmpInitializeRegistryNode(CurrentEntry,
294                                            ParentHandle,
295                                            &NewHandle,
296                                            Interface,
297                                            Bus,
298                                            DeviceIndexTable);
299         if (!NT_SUCCESS(Status)) return Status;
300 
301         /* Check for children */
302         if (CurrentEntry->Child)
303         {
304             /* Recurse child */
305             Status = CmpSetupConfigurationTree(CurrentEntry->Child,
306                                                NewHandle,
307                                                Interface,
308                                                Bus);
309             if (!NT_SUCCESS(Status))
310             {
311                 /* Fail */
312                 NtClose(NewHandle);
313                 return Status;
314             }
315         }
316 
317         /* Get to the next entry */
318         NtClose(NewHandle);
319         CurrentEntry = CurrentEntry->Sibling;
320     }
321 
322     /* We're done */
323     return STATUS_SUCCESS;
324 }
325 
326 CODE_SEG("INIT")
327 NTSTATUS
328 NTAPI
329 CmpInitializeHardwareConfiguration(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
330 {
331     NTSTATUS Status;
332     OBJECT_ATTRIBUTES ObjectAttributes;
333     HANDLE KeyHandle;
334     ULONG Disposition;
335     UNICODE_STRING KeyName;
336 
337     /* Set the alternative system architecture information */
338 #if defined(SARCH_PC98)
339     SharedUserData->AlternativeArchitecture = NEC98x86;
340 #endif
341 
342     /* Setup the key name */
343     RtlInitUnicodeString(&KeyName,
344                          L"\\Registry\\Machine\\Hardware\\DeviceMap");
345     InitializeObjectAttributes(&ObjectAttributes,
346                                &KeyName,
347                                OBJ_CASE_INSENSITIVE,
348                                NULL,
349                                NULL);
350 
351     /* Create the device map key */
352     Status = NtCreateKey(&KeyHandle,
353                          KEY_READ | KEY_WRITE,
354                          &ObjectAttributes,
355                          0,
356                          NULL,
357                          0,
358                          &Disposition);
359     if (!NT_SUCCESS(Status))
360         return Status;
361     NtClose(KeyHandle);
362 
363     /* Nobody should've created this key yet! */
364     ASSERT(Disposition == REG_CREATED_NEW_KEY);
365 
366     /* Setup the key name */
367     RtlInitUnicodeString(&KeyName,
368                          L"\\Registry\\Machine\\Hardware\\Description");
369     InitializeObjectAttributes(&ObjectAttributes,
370                                &KeyName,
371                                OBJ_CASE_INSENSITIVE,
372                                NULL,
373                                NULL);
374 
375     /* Create the description key */
376     Status = NtCreateKey(&KeyHandle,
377                           KEY_READ | KEY_WRITE,
378                           &ObjectAttributes,
379                           0,
380                           NULL,
381                           0,
382                           &Disposition);
383     if (!NT_SUCCESS(Status))
384         return Status;
385 
386     /* Nobody should've created this key yet! */
387     ASSERT(Disposition == REG_CREATED_NEW_KEY);
388 
389     /* Allocate the configuration data buffer */
390     CmpConfigurationData = ExAllocatePoolWithTag(PagedPool,
391                                                  CmpConfigurationAreaSize,
392                                                  TAG_CM);
393     if (!CmpConfigurationData)
394     {
395         NtClose(KeyHandle);
396         return STATUS_INSUFFICIENT_RESOURCES;
397     }
398 
399     /* Check if we got anything from NTLDR */
400     if (LoaderBlock->ConfigurationRoot)
401     {
402         /* Setup the configuration tree */
403         Status = CmpSetupConfigurationTree(LoaderBlock->ConfigurationRoot,
404                                            KeyHandle,
405                                            InterfaceTypeUndefined,
406                                            -1);
407     }
408     else
409     {
410         /* Nothing else to do */
411         Status = STATUS_SUCCESS;
412     }
413 
414     /* Free the buffer, close our handle and return status */
415     ExFreePoolWithTag(CmpConfigurationData, TAG_CM);
416     NtClose(KeyHandle);
417     return Status;
418 }
419