/*++ Copyright (c) 1991 Microsoft Corporation Module Name: blconfig.c Abstract: This module implements the OS loader configuration initialization. Author: David N. Cutler (davec) 9-Sep-1991 Revision History: --*/ #include "bootlib.h" #include "stdio.h" #include "stdlib.h" ULONG BlMatchToken ( IN PCHAR TokenValue, IN CHAR * FIRMWARE_PTR TokenArray[] ); PCHAR BlGetNextToken ( IN PCHAR TokenString, OUT PCHAR OutputToken, OUT PULONG UnitNumber ); // // Define types of adapters that can be booted from. // typedef enum _ADAPTER_TYPES { AdapterEisa, AdapterScsi, AdapterMulti, AdapterNet, AdapterRamdisk, AdapterMaximum } ADAPTER_TYPES; // // Define type of controllers that can be booted from. // typedef enum _CONTROLLER_TYPES { ControllerDisk, ControllerCdrom, ControllerMaximum } CONTROLLER_TYPES; // // Define type of peripheral that can be booted from. // typedef enum _PERIPHERAL_TYPES { PeripheralRigidDisk, PeripheralFloppyDisk, #if defined(ELTORITO) PeripheralElTorito, #endif PeripheralMaximum } PERIPHERAL_TYPES; // // Define the ARC pathname mnemonics. // CHAR * FIRMWARE_PTR MnemonicTable[] = { "arc", "cpu", "fpu", "pic", "pdc", "sic", "sdc", "sc", "eisa", "tc", "scsi", "dti", "multi", "disk", "tape", "cdrom", "worm", "serial", "net", "video", "par", "point", "key", "audio", "other", "rdisk", "fdisk", "tape", "modem", "monitor", "print", "pointer", "keyboard", "term", "other" }; CHAR * FIRMWARE_PTR BlAdapterTypes[AdapterMaximum + 1] = {"eisa","scsi","multi","net","ramdisk",NULL}; CHAR * FIRMWARE_PTR BlControllerTypes[ControllerMaximum + 1] = {"disk","cdrom",NULL}; #if defined(ELTORITO) CHAR * FIRMWARE_PTR BlPeripheralTypes[PeripheralMaximum + 1] = {"rdisk","fdisk","cdrom",NULL}; #else CHAR * FIRMWARE_PTR BlPeripheralTypes[PeripheralMaximum + 1] = {"rdisk","fdisk",NULL}; #endif ARC_STATUS BlConfigurationInitialize ( IN PCONFIGURATION_COMPONENT Parent, IN PCONFIGURATION_COMPONENT_DATA ParentEntry ) /*++ Routine Description: This routine traverses the firmware configuration tree from the specified parent entry and constructs the corresponding NT configuration tree. Arguments: None. Return Value: ESUCCESS is returned if the initialization is successful. Otherwise, an unsuccessful status that describes the error is returned. --*/ { PCONFIGURATION_COMPONENT Child; PCONFIGURATION_COMPONENT_DATA ChildEntry; PCHAR ConfigurationData; PCONFIGURATION_COMPONENT_DATA PreviousSibling; PCONFIGURATION_COMPONENT Sibling; PCONFIGURATION_COMPONENT_DATA SiblingEntry; ARC_STATUS Status; // // Traverse the child configuration tree and allocate, initialize, and // construct the corresponding NT configuration tree. // Child = ArcGetChild(Parent); while (Child != NULL) { // // Allocate an entry of the appropriate size to hold the child // configuration information. // ChildEntry = (PCONFIGURATION_COMPONENT_DATA)BlAllocateHeap( sizeof(CONFIGURATION_COMPONENT_DATA) + Child->IdentifierLength + Child->ConfigurationDataLength); if (ChildEntry == NULL) { return ENOMEM; } // // Initialize the tree pointers and copy the component data. // if (ParentEntry == NULL) { BlLoaderBlock->ConfigurationRoot = ChildEntry; } else { ParentEntry->Child = ChildEntry; } ChildEntry->Parent = ParentEntry; ChildEntry->Sibling = NULL; ChildEntry->Child = NULL; RtlMoveMemory((PVOID)&ChildEntry->ComponentEntry, (PVOID)Child, sizeof(CONFIGURATION_COMPONENT)); ConfigurationData = (PCHAR)(ChildEntry + 1); // // If configuration data is specified, then copy the configuration // data. // if (Child->ConfigurationDataLength != 0) { ChildEntry->ConfigurationData = (PVOID)ConfigurationData; Status = ArcGetConfigurationData((PVOID)ConfigurationData, Child); if (Status != ESUCCESS) { return Status; } ConfigurationData += Child->ConfigurationDataLength; } else { ChildEntry->ConfigurationData = NULL; } // // If identifier data is specified, then copy the identifier data. // if (Child->IdentifierLength !=0) { ChildEntry->ComponentEntry.Identifier = ConfigurationData; RtlMoveMemory((PVOID)ConfigurationData, (PVOID)Child->Identifier, Child->IdentifierLength); } else { ChildEntry->ComponentEntry.Identifier = NULL; } // // Traverse the sibling configuration tree and allocate, initialize, // and construct the corresponding NT configuration tree. // PreviousSibling = ChildEntry; Sibling = ArcGetPeer(Child); while (Sibling != NULL) { // // Allocate an entry of the appropriate size to hold the sibling // configuration information. // SiblingEntry = (PCONFIGURATION_COMPONENT_DATA)BlAllocateHeap( sizeof(CONFIGURATION_COMPONENT_DATA) + Sibling->IdentifierLength + Sibling->ConfigurationDataLength); if (SiblingEntry == NULL) { return ENOMEM; } // // Initialize the tree pointers and copy the component data. // SiblingEntry->Parent = ParentEntry; SiblingEntry->Sibling = NULL; ChildEntry->Child = NULL; RtlMoveMemory((PVOID)&SiblingEntry->ComponentEntry, (PVOID)Sibling, sizeof(CONFIGURATION_COMPONENT)); ConfigurationData = (PCHAR)(SiblingEntry + 1); // // If configuration data is specified, then copy the configuration // data. // if (Sibling->ConfigurationDataLength != 0) { SiblingEntry->ConfigurationData = (PVOID)ConfigurationData; Status = ArcGetConfigurationData((PVOID)ConfigurationData, Sibling); if (Status != ESUCCESS) { return Status; } ConfigurationData += Sibling->ConfigurationDataLength; } else { SiblingEntry->ConfigurationData = NULL; } // // If identifier data is specified, then copy the identifier data. // if (Sibling->IdentifierLength !=0) { SiblingEntry->ComponentEntry.Identifier = ConfigurationData; RtlMoveMemory((PVOID)ConfigurationData, (PVOID)Sibling->Identifier, Sibling->IdentifierLength); } else { SiblingEntry->ComponentEntry.Identifier = NULL; } // // If the sibling has a child, then generate the tree for the // child. // if (ArcGetChild(Sibling) != NULL) { Status = BlConfigurationInitialize(Sibling, SiblingEntry); if (Status != ESUCCESS) { return Status; } } // // Set new sibling pointers and get the next sibling tree entry. // PreviousSibling->Sibling = SiblingEntry; PreviousSibling = SiblingEntry; Sibling = ArcGetPeer(Sibling); } // // Set new parent pointers and get the next child tree entry. // Parent = Child; ParentEntry = ChildEntry; Child = ArcGetChild(Child); } return ESUCCESS; } BOOLEAN BlSearchConfigTree( IN PCONFIGURATION_COMPONENT_DATA Node, IN CONFIGURATION_CLASS Class, IN CONFIGURATION_TYPE Type, IN ULONG Key, IN PNODE_CALLBACK CallbackRoutine ) /*++ Routine Description: Conduct a depth-first search of the firmware configuration tree starting at a given node, looking for nodes that match a given class and type. When a matching node is found, call a callback routine. Arguments: CurrentNode - node at which to begin the search. Class - configuration class to match, or -1 to match any class Type - configuration type to match, or -1 to match any class Key - key to match, or -1 to match any key FoundRoutine - pointer to a routine to be called when a node whose class and type match the class and type passed in is located. The routine takes a pointer to the configuration node and must return a boolean indicating whether to continue with the traversal. Return Value: FALSE if the caller should abandon the search. --*/ { PCONFIGURATION_COMPONENT_DATA Child; do { if (Child = Node->Child) { if (!BlSearchConfigTree(Child, Class, Type, Key, CallbackRoutine)) { return(FALSE); } } if (((Class == -1) || (Node->ComponentEntry.Class == Class)) &&((Type == -1) || (Node->ComponentEntry.Type == Type)) &&((Key == (ULONG)-1) || (Node->ComponentEntry.Key == Key))) { if (!CallbackRoutine(Node)) { return(FALSE); } } Node = Node->Sibling; } while ( Node != NULL ); return(TRUE); } VOID BlGetPathnameFromComponent( IN PCONFIGURATION_COMPONENT_DATA Component, OUT PCHAR ArcName ) /*++ Routine Description: This function builds an ARC pathname for the specified component. Arguments: Component - Supplies a pointer to a configuration component. ArcName - Returns the ARC name of the specified component. Caller must provide a large enough buffer. Return Value: None. --*/ { if (Component->Parent != NULL) { BlGetPathnameFromComponent(Component->Parent,ArcName); // // append our segment to the arcname // sprintf(ArcName+strlen(ArcName), "%s(%d)", MnemonicTable[Component->ComponentEntry.Type], Component->ComponentEntry.Key); } else { // // We are the parent, initialize the string and return // ArcName[0] = '\0'; } return; } BOOLEAN BlGetPathMnemonicKey( IN PCHAR OpenPath, IN PCHAR Mnemonic, IN PULONG Key ) /*++ Routine Description: This routine looks for the given Mnemonic in OpenPath. If Mnemonic is a component of the path, then it converts the key value to an integer wich is returned in Key. Arguments: OpenPath - Pointer to a string that contains an ARC pathname. Mnemonic - Pointer to a string that contains a ARC Mnemonic Key - Pointer to a ULONG where the Key value is stored. Return Value: FALSE if mnemonic is found in path and a valid key is converted. TRUE otherwise. --*/ { PCHAR Tmp; CHAR Digits[9]; ULONG i; CHAR String[16]; // // Construct a string of the form ")mnemonic(" // String[0]=')'; for(i=1;*Mnemonic;i++) { String[i] = * Mnemonic++; } String[i++]='('; String[i]='\0'; if ((Tmp=strstr(OpenPath,&String[1])) == NULL) { return TRUE; } if (Tmp != OpenPath) { if ((Tmp=strstr(OpenPath,String)) == NULL) { return TRUE; } } else { i--; } // // skip the mnemonic and convert the value in between parentheses to integer // Tmp+=i; for (i=0;i