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