1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: BSD - See COPYING.ARM in the top level directory 4 * FILE: ntoskrnl/config/cmboot.c 5 * PURPOSE: Configuration Manager - Boot Initialization 6 * PROGRAMMERS: ReactOS Portable Systems Group 7 * Alex Ionescu (alex.ionescu@reactos.org) 8 */ 9 10 /* INCLUDES *******************************************************************/ 11 12 #include "ntoskrnl.h" 13 #define NDEBUG 14 #include "debug.h" 15 16 /* GLOBALS ********************************************************************/ 17 18 extern ULONG InitSafeBootMode; 19 20 /* FUNCTIONS ******************************************************************/ 21 22 HCELL_INDEX 23 NTAPI 24 INIT_FUNCTION 25 CmpFindControlSet(IN PHHIVE SystemHive, 26 IN HCELL_INDEX RootCell, 27 IN PUNICODE_STRING SelectKeyName, 28 OUT PBOOLEAN AutoSelect) 29 { 30 UNICODE_STRING KeyName; 31 PCM_KEY_NODE Node; 32 HCELL_INDEX SelectCell, AutoSelectCell, SelectValueCell, ControlSetCell; 33 HCELL_INDEX CurrentValueCell; 34 PCM_KEY_VALUE KeyValue; 35 ULONG Length; 36 PULONG ControlSetId; 37 ANSI_STRING ControlSetAnsiName; 38 CHAR Buffer[128]; 39 WCHAR WideBuffer[128]; 40 NTSTATUS Status; 41 PULONG CurrentData; 42 43 /* Sanity check */ 44 ASSERT(SystemHive->ReleaseCellRoutine == NULL); 45 46 /* Get the Select subkey */ 47 RtlInitUnicodeString(&KeyName, L"select"); 48 Node = (PCM_KEY_NODE)HvGetCell(SystemHive, RootCell); 49 if (!Node) return HCELL_NIL; 50 SelectCell = CmpFindSubKeyByName(SystemHive, Node, &KeyName); 51 if (SelectCell == HCELL_NIL) return SelectCell; 52 53 /* Get AutoSelect value */ 54 RtlInitUnicodeString(&KeyName, L"AutoSelect"); 55 Node = (PCM_KEY_NODE)HvGetCell(SystemHive, SelectCell); 56 if (!Node) return HCELL_NIL; 57 AutoSelectCell = CmpFindValueByName(SystemHive, Node, &KeyName); 58 if (AutoSelectCell == HCELL_NIL) 59 { 60 /* Assume TRUE if the value is missing. */ 61 *AutoSelect = TRUE; 62 } 63 else 64 { 65 /* Read the value */ 66 KeyValue = (PCM_KEY_VALUE)HvGetCell(SystemHive, AutoSelectCell); 67 if (KeyValue == NULL) return HCELL_NIL; 68 69 /* Convert it to a boolean */ 70 *AutoSelect = *(PBOOLEAN)CmpValueToData(SystemHive, KeyValue, &Length); 71 } 72 73 /* Now find the control set being looked up */ 74 Node = (PCM_KEY_NODE)HvGetCell(SystemHive, SelectCell); 75 if (!Node) return HCELL_NIL; 76 SelectValueCell = CmpFindValueByName(SystemHive, Node, SelectKeyName); 77 if (SelectValueCell == HCELL_NIL) return SelectValueCell; 78 79 /* Read the value (corresponding to the CCS ID) */ 80 KeyValue = (PCM_KEY_VALUE)HvGetCell(SystemHive, SelectValueCell); 81 if (!KeyValue) return HCELL_NIL; 82 if (KeyValue->Type != REG_DWORD) return HCELL_NIL; 83 ControlSetId = (PULONG)CmpValueToData(SystemHive, KeyValue, &Length); 84 85 /* Now build an Ansi String for the CCS's Name */ 86 sprintf(Buffer, "ControlSet%03lu", *ControlSetId); 87 ControlSetAnsiName.Length = (USHORT)strlen(Buffer); 88 ControlSetAnsiName.MaximumLength = (USHORT)strlen(Buffer); 89 ControlSetAnsiName.Buffer = Buffer; 90 91 /* And convert it to Unicode... */ 92 KeyName.MaximumLength = 256; 93 KeyName.Buffer = WideBuffer; 94 Status = RtlAnsiStringToUnicodeString(&KeyName, 95 &ControlSetAnsiName, 96 FALSE); 97 if (!NT_SUCCESS(Status)) return HCELL_NIL; 98 99 /* Now open it */ 100 Node = (PCM_KEY_NODE)HvGetCell(SystemHive, RootCell); 101 if (!Node) return HCELL_NIL; 102 ControlSetCell = CmpFindSubKeyByName(SystemHive, Node, &KeyName); 103 if (ControlSetCell == HCELL_NIL) return ControlSetCell; 104 105 /* Get the value of the "Current" CCS */ 106 RtlInitUnicodeString(&KeyName, L"Current"); 107 Node = (PCM_KEY_NODE)HvGetCell(SystemHive, SelectCell); 108 if (!Node) return HCELL_NIL; 109 CurrentValueCell = CmpFindValueByName(SystemHive, Node, &KeyName); 110 111 /* Make sure it exists */ 112 if (CurrentValueCell != HCELL_NIL) 113 { 114 /* Get the current value and make sure its a ULONG */ 115 KeyValue = (PCM_KEY_VALUE)HvGetCell(SystemHive, CurrentValueCell); 116 if (!KeyValue) return HCELL_NIL; 117 if (KeyValue->Type == REG_DWORD) 118 { 119 /* Get the data and update it */ 120 CurrentData = (PULONG)CmpValueToData(SystemHive, 121 KeyValue, 122 &Length); 123 if (!CurrentData) return HCELL_NIL; 124 *CurrentData = *ControlSetId; 125 } 126 } 127 128 /* Return the CCS Cell */ 129 return ControlSetCell; 130 } 131 132 ULONG 133 NTAPI 134 INIT_FUNCTION 135 CmpFindTagIndex(IN PHHIVE Hive, 136 IN HCELL_INDEX TagCell, 137 IN HCELL_INDEX GroupOrderCell, 138 IN PUNICODE_STRING GroupName) 139 { 140 PCM_KEY_VALUE TagValue, Value; 141 HCELL_INDEX OrderCell; 142 PULONG TagOrder, DriverTag; 143 ULONG CurrentTag, Length; 144 PCM_KEY_NODE Node; 145 BOOLEAN BufferAllocated; 146 ASSERT(Hive->ReleaseCellRoutine == NULL); 147 148 /* Get the tag */ 149 Value = HvGetCell(Hive, TagCell); 150 ASSERT(Value); 151 DriverTag = (PULONG)CmpValueToData(Hive, Value, &Length); 152 ASSERT(DriverTag); 153 154 /* Get the order array */ 155 Node = HvGetCell(Hive, GroupOrderCell); 156 ASSERT(Node); 157 OrderCell = CmpFindValueByName(Hive, Node, GroupName); 158 if (OrderCell == HCELL_NIL) return -2; 159 160 /* And read it */ 161 TagValue = HvGetCell(Hive, OrderCell); 162 CmpGetValueData(Hive, TagValue, &Length, (PVOID*)&TagOrder, &BufferAllocated, &OrderCell); 163 ASSERT(TagOrder); 164 165 /* Parse each tag */ 166 for (CurrentTag = 1; CurrentTag <= TagOrder[0]; CurrentTag++) 167 { 168 /* Find a match */ 169 if (TagOrder[CurrentTag] == *DriverTag) 170 { 171 /* Found it -- return the tag */ 172 if (BufferAllocated) ExFreePool(TagOrder); 173 return CurrentTag; 174 } 175 } 176 177 /* No matches, so assume next to last ordering */ 178 if (BufferAllocated) ExFreePool(TagOrder); 179 return -2; 180 } 181 182 BOOLEAN 183 NTAPI 184 INIT_FUNCTION 185 CmpAddDriverToList(IN PHHIVE Hive, 186 IN HCELL_INDEX DriverCell, 187 IN HCELL_INDEX GroupOrderCell, 188 IN PUNICODE_STRING RegistryPath, 189 IN PLIST_ENTRY BootDriverListHead) 190 { 191 PBOOT_DRIVER_NODE DriverNode; 192 PBOOT_DRIVER_LIST_ENTRY DriverEntry; 193 PCM_KEY_NODE Node; 194 ULONG Length; 195 USHORT NameLength; 196 HCELL_INDEX ValueCell, TagCell; PCM_KEY_VALUE Value; 197 PUNICODE_STRING FileName, RegistryString; 198 UNICODE_STRING UnicodeString; 199 PULONG ErrorControl; 200 PWCHAR Buffer; 201 ASSERT(Hive->ReleaseCellRoutine == NULL); 202 203 /* Allocate a driver node and initialize it */ 204 DriverNode = CmpAllocate(sizeof(BOOT_DRIVER_NODE), FALSE, TAG_CM); 205 if (!DriverNode) return FALSE; 206 DriverEntry = &DriverNode->ListEntry; 207 DriverEntry->RegistryPath.Buffer = NULL; 208 DriverEntry->FilePath.Buffer = NULL; 209 210 /* Get the driver cell */ 211 Node = HvGetCell(Hive, DriverCell); 212 ASSERT(Node); 213 214 /* Get the name from the cell */ 215 DriverNode->Name.Length = Node->Flags & KEY_COMP_NAME ? 216 CmpCompressedNameSize(Node->Name, Node->NameLength) : 217 Node->NameLength; 218 DriverNode->Name.MaximumLength = DriverNode->Name.Length; 219 NameLength = DriverNode->Name.Length; 220 221 /* Now allocate the buffer for it and copy the name */ 222 DriverNode->Name.Buffer = CmpAllocate(NameLength, FALSE, TAG_CM); 223 if (!DriverNode->Name.Buffer) return FALSE; 224 if (Node->Flags & KEY_COMP_NAME) 225 { 226 /* Compressed name */ 227 CmpCopyCompressedName(DriverNode->Name.Buffer, 228 DriverNode->Name.Length, 229 Node->Name, 230 Node->NameLength); 231 } 232 else 233 { 234 /* Normal name */ 235 RtlCopyMemory(DriverNode->Name.Buffer, Node->Name, Node->NameLength); 236 } 237 238 /* Now find the image path */ 239 RtlInitUnicodeString(&UnicodeString, L"ImagePath"); 240 ValueCell = CmpFindValueByName(Hive, Node, &UnicodeString); 241 if (ValueCell == HCELL_NIL) 242 { 243 /* Couldn't find it, so assume the drivers path */ 244 Length = sizeof(L"System32\\Drivers\\") + NameLength + sizeof(L".sys"); 245 246 /* Allocate the path name */ 247 FileName = &DriverEntry->FilePath; 248 FileName->Length = 0; 249 FileName->MaximumLength = (USHORT)Length; 250 FileName->Buffer = CmpAllocate(Length, FALSE,TAG_CM); 251 if (!FileName->Buffer) return FALSE; 252 253 /* Write the path name */ 254 RtlAppendUnicodeToString(FileName, L"System32\\Drivers\\"); 255 RtlAppendUnicodeStringToString(FileName, &DriverNode->Name); 256 RtlAppendUnicodeToString(FileName, L".sys"); 257 } 258 else 259 { 260 /* Path name exists, so grab it */ 261 Value = HvGetCell(Hive, ValueCell); 262 ASSERT(Value); 263 264 /* Allocate and setup the path name */ 265 FileName = &DriverEntry->FilePath; 266 Buffer = (PWCHAR)CmpValueToData(Hive, Value, &Length); 267 FileName->MaximumLength = FileName->Length = (USHORT)Length; 268 FileName->Buffer = CmpAllocate(Length, FALSE, TAG_CM); 269 270 /* Transfer the data */ 271 if (!(FileName->Buffer) || !(Buffer)) return FALSE; 272 RtlCopyMemory(FileName->Buffer, Buffer, Length); 273 } 274 275 /* Now build the registry path */ 276 RegistryString = &DriverEntry->RegistryPath; 277 RegistryString->Length = 0; 278 RegistryString->MaximumLength = RegistryPath->Length + NameLength; 279 RegistryString->Buffer = CmpAllocate(RegistryString->MaximumLength, FALSE, TAG_CM); 280 if (!RegistryString->Buffer) return FALSE; 281 282 /* Add the driver name to it */ 283 RtlAppendUnicodeStringToString(RegistryString, RegistryPath); 284 RtlAppendUnicodeStringToString(RegistryString, &DriverNode->Name); 285 286 /* The entry is done, add it */ 287 InsertHeadList(BootDriverListHead, &DriverEntry->Link); 288 289 /* Now find error control settings */ 290 RtlInitUnicodeString(&UnicodeString, L"ErrorControl"); 291 ValueCell = CmpFindValueByName(Hive, Node, &UnicodeString); 292 if (ValueCell == HCELL_NIL) 293 { 294 /* Couldn't find it, so assume default */ 295 DriverNode->ErrorControl = NormalError; 296 } 297 else 298 { 299 /* Otherwise, read whatever the data says */ 300 Value = HvGetCell(Hive, ValueCell); 301 ASSERT(Value); 302 ErrorControl = (PULONG)CmpValueToData(Hive, Value, &Length); 303 ASSERT(ErrorControl); 304 DriverNode->ErrorControl = *ErrorControl; 305 } 306 307 /* Next, get the group cell */ 308 RtlInitUnicodeString(&UnicodeString, L"group"); 309 ValueCell = CmpFindValueByName(Hive, Node, &UnicodeString); 310 if (ValueCell == HCELL_NIL) 311 { 312 /* Couldn't find, so set an empty string */ 313 RtlInitEmptyUnicodeString(&DriverNode->Group, NULL, 0); 314 } 315 else 316 { 317 /* Found it, read the group value */ 318 Value = HvGetCell(Hive, ValueCell); 319 ASSERT(Value); 320 321 /* Copy it into the node */ 322 DriverNode->Group.Buffer = (PWCHAR)CmpValueToData(Hive, Value, &Length); 323 if (!DriverNode->Group.Buffer) return FALSE; 324 DriverNode->Group.Length = (USHORT)Length - sizeof(UNICODE_NULL); 325 DriverNode->Group.MaximumLength = DriverNode->Group.Length; 326 } 327 328 /* Finally, find the tag */ 329 RtlInitUnicodeString(&UnicodeString, L"Tag"); 330 TagCell = CmpFindValueByName(Hive, Node, &UnicodeString); 331 if (TagCell == HCELL_NIL) 332 { 333 /* No tag, so load last */ 334 DriverNode->Tag = -1; 335 } 336 else 337 { 338 /* Otherwise, decode it based on tag order */ 339 DriverNode->Tag = CmpFindTagIndex(Hive, 340 TagCell, 341 GroupOrderCell, 342 &DriverNode->Group); 343 } 344 345 /* All done! */ 346 return TRUE; 347 } 348 349 BOOLEAN 350 NTAPI 351 INIT_FUNCTION 352 CmpIsLoadType(IN PHHIVE Hive, 353 IN HCELL_INDEX Cell, 354 IN SERVICE_LOAD_TYPE LoadType) 355 { 356 PCM_KEY_NODE Node; 357 HCELL_INDEX ValueCell; 358 UNICODE_STRING ValueString = RTL_CONSTANT_STRING(L"Start"); 359 PCM_KEY_VALUE Value; 360 ULONG Length; 361 PLONG Data; 362 ASSERT(Hive->ReleaseCellRoutine == NULL); 363 364 /* Open the start cell */ 365 Node = HvGetCell(Hive, Cell); 366 ASSERT(Node); 367 ValueCell = CmpFindValueByName(Hive, Node, &ValueString); 368 if (ValueCell == HCELL_NIL) return FALSE; 369 370 /* Read the start value */ 371 Value = HvGetCell(Hive, ValueCell); 372 ASSERT(Value); 373 Data = (PLONG)CmpValueToData(Hive, Value, &Length); 374 ASSERT(Data); 375 376 /* Return if the type matches */ 377 return (*Data == LoadType); 378 } 379 380 BOOLEAN 381 NTAPI 382 INIT_FUNCTION 383 CmpFindDrivers(IN PHHIVE Hive, 384 IN HCELL_INDEX ControlSet, 385 IN SERVICE_LOAD_TYPE LoadType, 386 IN PWCHAR BootFileSystem OPTIONAL, 387 IN PLIST_ENTRY DriverListHead) 388 { 389 HCELL_INDEX ServicesCell, ControlCell, GroupOrderCell, DriverCell; 390 HCELL_INDEX SafeBootCell = HCELL_NIL; 391 UNICODE_STRING Name; 392 ULONG i; 393 WCHAR Buffer[128]; 394 UNICODE_STRING UnicodeString, KeyPath; 395 PBOOT_DRIVER_NODE FsNode; 396 PCM_KEY_NODE ControlNode, ServicesNode, Node; 397 ASSERT(Hive->ReleaseCellRoutine == NULL); 398 399 /* Open the control set key */ 400 ControlNode = HvGetCell(Hive, ControlSet); 401 ASSERT(ControlNode); 402 403 /* Get services cell */ 404 RtlInitUnicodeString(&Name, L"Services"); 405 ServicesCell = CmpFindSubKeyByName(Hive, ControlNode, &Name); 406 if (ServicesCell == HCELL_NIL) return FALSE; 407 408 /* Open services key */ 409 ServicesNode = HvGetCell(Hive, ServicesCell); 410 ASSERT(ServicesNode); 411 412 /* Get control cell */ 413 RtlInitUnicodeString(&Name, L"Control"); 414 ControlCell = CmpFindSubKeyByName(Hive, ControlNode, &Name); 415 if (ControlCell == HCELL_NIL) return FALSE; 416 417 /* Get the group order cell and read it */ 418 RtlInitUnicodeString(&Name, L"GroupOrderList"); 419 Node = HvGetCell(Hive, ControlCell); 420 ASSERT(Node); 421 GroupOrderCell = CmpFindSubKeyByName(Hive, Node, &Name); 422 if (GroupOrderCell == HCELL_NIL) return FALSE; 423 424 /* Get Safe Boot cell */ 425 if(InitSafeBootMode) 426 { 427 /* Open the Safe Boot key */ 428 RtlInitUnicodeString(&Name, L"SafeBoot"); 429 Node = HvGetCell(Hive, ControlCell); 430 ASSERT(Node); 431 SafeBootCell = CmpFindSubKeyByName(Hive, Node, &Name); 432 if (SafeBootCell == HCELL_NIL) return FALSE; 433 434 /* Open the correct start key (depending on the mode) */ 435 Node = HvGetCell(Hive, SafeBootCell); 436 ASSERT(Node); 437 switch(InitSafeBootMode) 438 { 439 /* NOTE: Assumes MINIMAL (1) and DSREPAIR (3) load same items */ 440 case 1: 441 case 3: RtlInitUnicodeString(&Name, L"Minimal"); break; 442 case 2: RtlInitUnicodeString(&Name, L"Network"); break; 443 default: return FALSE; 444 } 445 SafeBootCell = CmpFindSubKeyByName(Hive, Node, &Name); 446 if(SafeBootCell == HCELL_NIL) return FALSE; 447 } 448 449 /* Build the root registry path */ 450 RtlInitEmptyUnicodeString(&KeyPath, Buffer, sizeof(Buffer)); 451 RtlAppendUnicodeToString(&KeyPath, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"); 452 453 /* Find the first subkey (ie: the first driver or service) */ 454 i = 0; 455 DriverCell = CmpFindSubKeyByNumber(Hive, ServicesNode, i); 456 while (DriverCell != HCELL_NIL) 457 { 458 /* Make sure it's a driver of this start type AND is "safe" to load */ 459 if (CmpIsLoadType(Hive, DriverCell, LoadType) && 460 CmpIsSafe(Hive, SafeBootCell, DriverCell)) 461 { 462 /* Add it to the list */ 463 CmpAddDriverToList(Hive, 464 DriverCell, 465 GroupOrderCell, 466 &KeyPath, 467 DriverListHead); 468 469 } 470 471 /* Try the next subkey */ 472 DriverCell = CmpFindSubKeyByNumber(Hive, ServicesNode, ++i); 473 } 474 475 /* Check if we have a boot file system */ 476 if (BootFileSystem) 477 { 478 /* Find it */ 479 RtlInitUnicodeString(&UnicodeString, BootFileSystem); 480 DriverCell = CmpFindSubKeyByName(Hive, ServicesNode, &UnicodeString); 481 if (DriverCell != HCELL_NIL) 482 { 483 /* Always add it to the list */ 484 CmpAddDriverToList(Hive, 485 DriverCell, 486 GroupOrderCell, 487 &KeyPath, 488 DriverListHead); 489 490 /* Mark it as critical so it always loads */ 491 FsNode = CONTAINING_RECORD(DriverListHead->Flink, 492 BOOT_DRIVER_NODE, 493 ListEntry.Link); 494 FsNode->ErrorControl = SERVICE_ERROR_CRITICAL; 495 } 496 } 497 498 /* We're done! */ 499 return TRUE; 500 } 501 502 BOOLEAN 503 NTAPI 504 INIT_FUNCTION 505 CmpDoSort(IN PLIST_ENTRY DriverListHead, 506 IN PUNICODE_STRING OrderList) 507 { 508 PWCHAR Current, End = NULL; 509 PLIST_ENTRY NextEntry; 510 UNICODE_STRING GroupName; 511 PBOOT_DRIVER_NODE CurrentNode; 512 513 /* We're going from end to start, so get to the last group and keep going */ 514 Current = &OrderList->Buffer[OrderList->Length / sizeof(WCHAR)]; 515 while (Current > OrderList->Buffer) 516 { 517 /* Scan the current string */ 518 do 519 { 520 if (*Current == UNICODE_NULL) End = Current; 521 } while ((*(--Current - 1) != UNICODE_NULL) && (Current != OrderList->Buffer)); 522 523 /* This is our cleaned up string for this specific group */ 524 ASSERT(End != NULL); 525 GroupName.Length = (USHORT)(End - Current) * sizeof(WCHAR); 526 GroupName.MaximumLength = GroupName.Length; 527 GroupName.Buffer = Current; 528 529 /* Now loop the driver list */ 530 NextEntry = DriverListHead->Flink; 531 while (NextEntry != DriverListHead) 532 { 533 /* Get this node */ 534 CurrentNode = CONTAINING_RECORD(NextEntry, 535 BOOT_DRIVER_NODE, 536 ListEntry.Link); 537 538 /* Get the next entry now since we'll do a relink */ 539 NextEntry = CurrentNode->ListEntry.Link.Flink; 540 541 /* Is there a group name and does it match the current group? */ 542 if ((CurrentNode->Group.Buffer) && 543 (RtlEqualUnicodeString(&GroupName, &CurrentNode->Group, TRUE))) 544 { 545 /* Remove from this location and re-link in the new one */ 546 RemoveEntryList(&CurrentNode->ListEntry.Link); 547 InsertHeadList(DriverListHead, &CurrentNode->ListEntry.Link); 548 } 549 } 550 551 /* Move on */ 552 Current--; 553 } 554 555 /* All done */ 556 return TRUE; 557 } 558 559 BOOLEAN 560 NTAPI 561 INIT_FUNCTION 562 CmpSortDriverList(IN PHHIVE Hive, 563 IN HCELL_INDEX ControlSet, 564 IN PLIST_ENTRY DriverListHead) 565 { 566 HCELL_INDEX Controls, GroupOrder, ListCell; 567 UNICODE_STRING Name, DependList; 568 PCM_KEY_VALUE ListNode; 569 ULONG Length; 570 PCM_KEY_NODE Node; 571 ASSERT(Hive->ReleaseCellRoutine == NULL); 572 573 /* Open the control key */ 574 Node = HvGetCell(Hive, ControlSet); 575 ASSERT(Node); 576 RtlInitUnicodeString(&Name, L"Control"); 577 Controls = CmpFindSubKeyByName(Hive, Node, &Name); 578 if (Controls == HCELL_NIL) return FALSE; 579 580 /* Open the service group order */ 581 Node = HvGetCell(Hive, Controls); 582 ASSERT(Node); 583 RtlInitUnicodeString(&Name, L"ServiceGroupOrder"); 584 GroupOrder = CmpFindSubKeyByName(Hive, Node, &Name); 585 if (GroupOrder == HCELL_NIL) return FALSE; 586 587 /* Open the list key */ 588 Node = HvGetCell(Hive, GroupOrder); 589 ASSERT(Node); 590 RtlInitUnicodeString(&Name, L"list"); 591 ListCell = CmpFindValueByName(Hive, Node, &Name); 592 if (ListCell == HCELL_NIL) return FALSE; 593 594 /* Now read the actual list */ 595 ListNode = HvGetCell(Hive, ListCell); 596 ASSERT(ListNode); 597 if (ListNode->Type != REG_MULTI_SZ) return FALSE; 598 599 /* Copy it into a buffer */ 600 DependList.Buffer = (PWCHAR)CmpValueToData(Hive, ListNode, &Length); 601 if (!DependList.Buffer) return FALSE; 602 DependList.Length = DependList.MaximumLength = (USHORT)Length - sizeof(UNICODE_NULL); 603 604 /* And start the recurive sort algorithm */ 605 return CmpDoSort(DriverListHead, &DependList); 606 } 607 608 BOOLEAN 609 NTAPI 610 INIT_FUNCTION 611 CmpOrderGroup(IN PBOOT_DRIVER_NODE StartNode, 612 IN PBOOT_DRIVER_NODE EndNode) 613 { 614 PBOOT_DRIVER_NODE CurrentNode, PreviousNode; 615 PLIST_ENTRY ListEntry; 616 617 /* Base case, nothing to do */ 618 if (StartNode == EndNode) return TRUE; 619 620 /* Loop the nodes */ 621 CurrentNode = StartNode; 622 do 623 { 624 /* Save this as the previous node */ 625 PreviousNode = CurrentNode; 626 627 /* And move to the next one */ 628 ListEntry = CurrentNode->ListEntry.Link.Flink; 629 CurrentNode = CONTAINING_RECORD(ListEntry, 630 BOOT_DRIVER_NODE, 631 ListEntry.Link); 632 633 /* Check if the previous driver had a bigger tag */ 634 if (PreviousNode->Tag > CurrentNode->Tag) 635 { 636 /* Check if we need to update the tail */ 637 if (CurrentNode == EndNode) 638 { 639 /* Update the tail */ 640 ListEntry = CurrentNode->ListEntry.Link.Blink; 641 EndNode = CONTAINING_RECORD(ListEntry, 642 BOOT_DRIVER_NODE, 643 ListEntry.Link); 644 } 645 646 /* Remove this driver since we need to move it */ 647 RemoveEntryList(&CurrentNode->ListEntry.Link); 648 649 /* Keep looping until we find a driver with a lower tag than ours */ 650 while ((PreviousNode->Tag > CurrentNode->Tag) && (PreviousNode != StartNode)) 651 { 652 /* We'll be re-inserted at this spot */ 653 ListEntry = PreviousNode->ListEntry.Link.Blink; 654 PreviousNode = CONTAINING_RECORD(ListEntry, 655 BOOT_DRIVER_NODE, 656 ListEntry.Link); 657 } 658 659 /* Do the insert in the new location */ 660 InsertTailList(&PreviousNode->ListEntry.Link, &CurrentNode->ListEntry.Link); 661 662 /* Update the head, if needed */ 663 if (PreviousNode == StartNode) StartNode = CurrentNode; 664 } 665 } while (CurrentNode != EndNode); 666 667 /* All done */ 668 return TRUE; 669 } 670 671 BOOLEAN 672 NTAPI 673 INIT_FUNCTION 674 CmpResolveDriverDependencies(IN PLIST_ENTRY DriverListHead) 675 { 676 PLIST_ENTRY NextEntry; 677 PBOOT_DRIVER_NODE StartNode, EndNode, CurrentNode; 678 679 /* Loop the list */ 680 NextEntry = DriverListHead->Flink; 681 while (NextEntry != DriverListHead) 682 { 683 /* Find the first entry */ 684 StartNode = CONTAINING_RECORD(NextEntry, 685 BOOT_DRIVER_NODE, 686 ListEntry.Link); 687 do 688 { 689 /* Find the last entry */ 690 EndNode = CONTAINING_RECORD(NextEntry, 691 BOOT_DRIVER_NODE, 692 ListEntry.Link); 693 694 /* Get the next entry */ 695 NextEntry = NextEntry->Flink; 696 CurrentNode = CONTAINING_RECORD(NextEntry, 697 BOOT_DRIVER_NODE, 698 ListEntry.Link); 699 700 /* If the next entry is back to the top, break out */ 701 if (NextEntry == DriverListHead) break; 702 703 /* Otherwise, check if this entry is equal */ 704 if (!RtlEqualUnicodeString(&StartNode->Group, 705 &CurrentNode->Group, 706 TRUE)) 707 { 708 /* It is, so we've detected a cycle, break out */ 709 break; 710 } 711 } while (NextEntry != DriverListHead); 712 713 /* Now we have the correct start and end pointers, so do the sort */ 714 CmpOrderGroup(StartNode, EndNode); 715 } 716 717 /* We're done */ 718 return TRUE; 719 } 720 721 BOOLEAN 722 NTAPI 723 INIT_FUNCTION 724 CmpIsSafe(IN PHHIVE Hive, 725 IN HCELL_INDEX SafeBootCell, 726 IN HCELL_INDEX DriverCell) 727 { 728 PCM_KEY_NODE SafeBootNode; 729 PCM_KEY_NODE DriverNode; 730 PCM_KEY_VALUE KeyValue; 731 HCELL_INDEX CellIndex; 732 ULONG Length = 0; 733 UNICODE_STRING Name; 734 PWCHAR OriginalName; 735 ASSERT(Hive->ReleaseCellRoutine == NULL); 736 737 /* Driver key node (mandatory) */ 738 ASSERT(DriverCell != HCELL_NIL); 739 DriverNode = HvGetCell(Hive, DriverCell); 740 ASSERT(DriverNode); 741 742 /* Safe boot key node (optional but return TRUE if not present) */ 743 if(SafeBootCell == HCELL_NIL) return TRUE; 744 SafeBootNode = HvGetCell(Hive, SafeBootCell); 745 if(!SafeBootNode) return FALSE; 746 747 /* Search by the name from the group */ 748 RtlInitUnicodeString(&Name, L"Group"); 749 CellIndex = CmpFindValueByName(Hive, DriverNode, &Name); 750 if(CellIndex != HCELL_NIL) 751 { 752 KeyValue = HvGetCell(Hive, CellIndex); 753 ASSERT(KeyValue); 754 if (KeyValue->Type == REG_SZ || KeyValue->Type == REG_EXPAND_SZ) 755 { 756 /* Compose the search 'key' */ 757 Name.Buffer = (PWCHAR)CmpValueToData(Hive, KeyValue, &Length); 758 if (!Name.Buffer) return FALSE; 759 Name.Length = (USHORT)Length - sizeof(UNICODE_NULL); 760 Name.MaximumLength = Name.Length; 761 /* Search for corresponding key in the Safe Boot key */ 762 CellIndex = CmpFindSubKeyByName(Hive, SafeBootNode, &Name); 763 if(CellIndex != HCELL_NIL) return TRUE; 764 } 765 } 766 767 /* Group has not been found - find driver name */ 768 Name.Length = DriverNode->Flags & KEY_COMP_NAME ? 769 CmpCompressedNameSize(DriverNode->Name, 770 DriverNode->NameLength) : 771 DriverNode->NameLength; 772 Name.MaximumLength = Name.Length; 773 /* Now allocate the buffer for it and copy the name */ 774 Name.Buffer = CmpAllocate(Name.Length, FALSE, TAG_CM); 775 if (!Name.Buffer) return FALSE; 776 if (DriverNode->Flags & KEY_COMP_NAME) 777 { 778 /* Compressed name */ 779 CmpCopyCompressedName(Name.Buffer, 780 Name.Length, 781 DriverNode->Name, 782 DriverNode->NameLength); 783 } 784 else 785 { 786 /* Normal name */ 787 RtlCopyMemory(Name.Buffer, DriverNode->Name, DriverNode->NameLength); 788 } 789 CellIndex = CmpFindSubKeyByName(Hive, SafeBootNode, &Name); 790 RtlFreeUnicodeString(&Name); 791 if(CellIndex != HCELL_NIL) return TRUE; 792 793 /* Not group or driver name - search by image name */ 794 RtlInitUnicodeString(&Name, L"ImagePath"); 795 CellIndex = CmpFindValueByName(Hive, DriverNode, &Name); 796 if(CellIndex != HCELL_NIL) 797 { 798 KeyValue = HvGetCell(Hive, CellIndex); 799 ASSERT(KeyValue); 800 if (KeyValue->Type == REG_SZ || KeyValue->Type == REG_EXPAND_SZ) 801 { 802 /* Compose the search 'key' */ 803 OriginalName = (PWCHAR)CmpValueToData(Hive, KeyValue, &Length); 804 if (!OriginalName) return FALSE; 805 /* Get the base image file name */ 806 Name.Buffer = wcsrchr(OriginalName, L'\\'); 807 if (!Name.Buffer) return FALSE; 808 ++Name.Buffer; 809 /* Length of the base name must be >=1 */ 810 Name.Length = (USHORT)Length - (USHORT)((PUCHAR)Name.Buffer - (PUCHAR)OriginalName) 811 - sizeof(UNICODE_NULL); 812 if(Name.Length < 1) return FALSE; 813 Name.MaximumLength = Name.Length; 814 /* Search for corresponding key in the Safe Boot key */ 815 CellIndex = CmpFindSubKeyByName(Hive, SafeBootNode, &Name); 816 if(CellIndex != HCELL_NIL) return TRUE; 817 } 818 } 819 /* Nothing found - nothing else to search */ 820 return FALSE; 821 } 822 823 /* EOF */ 824