/** @file This Library will install CrDeviceVariableLib for reference. ;****************************************************************************** ;* Copyright (c) 2016, Insyde Software Corp. All Rights Reserved. ;* ;* You may not reproduce, distribute, publish, display, perform, modify, adapt, ;* transmit, broadcast, present, recite, release, license or otherwise exploit ;* any part of this publication in any form, by any means, without the prior ;* written permission of Insyde Software Corporation. ;* ;****************************************************************************** */ #include CHAR16 mVarName[] = L"CrDevVar000"; UINT32 mCrBaudRateTable [] = { 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 0 }; EFI_GUID mCrTerminalGuidTable [] = { DEVICE_PATH_MESSAGING_VT_100, DEVICE_PATH_MESSAGING_VT_100_PLUS, DEVICE_PATH_MESSAGING_VT_UTF8, DEVICE_PATH_MESSAGING_PC_ANSI, DEVICE_PATH_MESSAGING_LOG_TERM, NULL_GUID }; UART_DEVICE_PATH mUartNode = { MESSAGING_DEVICE_PATH, MSG_UART_DP, (UINT8) (sizeof (UART_DEVICE_PATH)), (UINT8) ((sizeof (UART_DEVICE_PATH)) >> 8), 0, 115200, 8, 1, 1 }; UART_FLOW_CONTROL_DEVICE_PATH mFlowControlNode = { MESSAGING_DEVICE_PATH, MSG_VENDOR_DP, (UINT8) (sizeof (UART_FLOW_CONTROL_DEVICE_PATH)), (UINT8) ((sizeof (UART_FLOW_CONTROL_DEVICE_PATH)) >> 8), DEVICE_PATH_MESSAGING_UART_FLOW_CONTROL, 0 }; VENDOR_DEVICE_PATH mTerminalNode = { MESSAGING_DEVICE_PATH, MSG_VENDOR_DP, (UINT8) (sizeof (VENDOR_DEVICE_PATH)), (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8), DEVICE_PATH_MESSAGING_PC_ANSI }; static EFI_DEVICE_PATH_PROTOCOL mEnd = { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, END_DEVICE_PATH_LENGTH, 0 }; CHAR16* CrDevVariableName ( IN UINTN Index ) { Int2Str (Index, &mVarName[8]); return mVarName; } UINTN CalculateCrDeviceVarSize ( IN CONST CHAR16 *NameStr, IN EFI_DEVICE_PATH *DPath, OUT UINTN *DpathOffse ) { UINTN VarSize; VarSize = (UINTN) &(((CR_DEVICE_VAR *) 0)->DevName); VarSize += StrSize (NameStr); *DpathOffse = VarSize; VarSize += GetDevicePathSize (DPath); return VarSize; } BOOLEAN CheckCrDeviceVariableExist ( IN CHAR16 *VarName ) { EFI_STATUS Status; UINT8 Data; UINTN Size; Size = sizeof (UINT8); Status = gRT->GetVariable (VarName, &gH2OCrConfigurationGuid, NULL, &Size, &Data); if (Status == EFI_BUFFER_TOO_SMALL) { Status = EFI_SUCCESS; } return (Status == EFI_SUCCESS ? TRUE : FALSE); } EFI_STATUS CreateDeviceVariableFromPcd ( IN CR_DEVICE_PCD *CrPcdDevice, IN UINTN DeviceCount, IN BOOLEAN LoadDefault ) { EFI_STATUS Status; UINTN BufferSize; UINTN VarSize; UINTN DPathOffset; UINT8 Index; UINT8 *CrDeviceVar; CR_DEVICE_VAR *Var; BOOLEAN DevVarExist; DEBUG ((DEBUG_INFO, "\nCr << %a >>\n", __FUNCTION__)); CrDeviceVar = NULL; BufferSize = 0; for (Index = 0; Index < DeviceCount; Index++) { DevVarExist = CheckCrDeviceVariableExist (CrDevVariableName (Index)); // // if Load default or device Variable not exist then create new variable // if (((DevVarExist == TRUE) && LoadDefault) || (DevVarExist == FALSE)) { VarSize = CalculateCrDeviceVarSize (CrPcdDevice[Index].DevName, CrPcdDevice[Index].DevPath, &DPathOffset); CrDeviceVar = (UINT8*)PrepareEnoughCrDeviceVariable (CrDeviceVar, VarSize, &BufferSize); if (CrDeviceVar == NULL) { ASSERT (0); return EFI_OUT_OF_RESOURCES; } // // Parpare CR device header, name, device path. // Var = (CR_DEVICE_VAR*) CrDeviceVar; Var->Exist = CrPcdDevice[Index].Exist; Var->UseGlobal = CrPcdDevice[Index].UseGlobal; Var->PortEnable = CrPcdDevice[Index].PortEnable; Var->ItmeType = CrPcdDevice[Index].ItemType; Var->SetInPCD = TRUE; CopyMem (&(Var->DevName), CrPcdDevice[Index].DevName, StrSize(CrPcdDevice[Index].DevName)); CopyMem (&CrDeviceVar[DPathOffset], CrPcdDevice[Index].DevPath, GetDevicePathSize (CrPcdDevice[Index].DevPath)); // // Save CR Device Variable // Status = gRT->SetVariable ( mVarName, &gH2OCrConfigurationGuid, EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, VarSize, (VOID*) CrDeviceVar ); ASSERT_EFI_ERROR(Status); DEBUG ((DEBUG_INFO, " Create %s : %r Size:%d\n", mVarName, Status, VarSize)); } } if (CrDeviceVar != NULL) { FreePool (CrDeviceVar); } DEBUG ((DEBUG_INFO, "\n")); return EFI_SUCCESS; } VOID* GetNextColumnPtr ( IN CONST CHAR16* StrPtr ) { while (*StrPtr != 0) { StrPtr++; }; return (VOID*)(++StrPtr); } EFI_DEVICE_PATH* GetDevicePathFromVariable ( IN CR_DEVICE_VAR *CrDeviceVar ) { return (EFI_DEVICE_PATH*) GetNextColumnPtr ((CHAR16*) &CrDeviceVar->DevName); } EFI_DEVICE_PATH* ParserDevicePathString ( IN CONST CHAR16 *Str, IN OUT CR_DEVICE_PCD *PcdDevice ) { EFI_DEVICE_PATH *FullDevPath; EFI_DEVICE_PATH *TempDevPath; UpdateTemplateDeviceNode (); // // Convert String to device path // FullDevPath = ConvertTextToDevicePath (Str); PcdDevice->Exist = TRUE; PcdDevice->UseGlobal = TRUE; // // Check is it a vaild Cr device path. // Filepath node only support "*" string // Other filepath node, return an end-of-device-path. // TempDevPath = VerifyMediaFileNode (FullDevPath, PcdDevice); if (TempDevPath != NULL) { FreePool(FullDevPath); return TempDevPath; } // // Verify Uart node, if uart Node didn't exist then create it. // FullDevPath = VerifyUartNode (FullDevPath, PcdDevice); // // Verify FlowControl & Terminal node // return VerifyMessagingDeviceNode (FullDevPath, PcdDevice); } CHAR16* Int2Str ( IN UINTN Number, IN CHAR16 *Str ) { const CHAR16 Digit[] = L"0123456789"; CHAR16 *Ptr; UINTN Shifter; Ptr = Str; Shifter = Number; // //Move to where representation ends // do { Ptr++; Shifter = Shifter/10; } while (Shifter); *Ptr = 0; // //Move back, inserting digits as u go // do{ *--Ptr = Digit[Number % 10]; Number = Number / 10; }while(Number); return Str; } EFI_STATUS ParsingCrDevicePcdValue ( OUT CR_DEVICE_PCD **PcdCrDevice, OUT UINTN *DeviceCount ) { CR_DEVICE_PCD *PtrPcd; CR_DEVICE_PCD *CrDevice; CONST CHAR16 *TmpStr; UINTN Count; UINTN BufferCount; DEBUG ((DEBUG_INFO, "\nCr << %a >>\n", __FUNCTION__)); Count = 0; BufferCount = MAX_CR_DEVICE_VARIABLE; PtrPcd = (CR_DEVICE_PCD*)PcdGetPtr (PcdH2OCrDevice); CrDevice = AllocateZeroPool (BufferCount * sizeof (CR_DEVICE_PCD)); if (CrDevice == NULL) { ASSERT (0); return EFI_OUT_OF_RESOURCES; } for (Count = 0; PtrPcd->PortEnable != 0xff; Count++) { if (Count >= BufferCount) { break; } CrDevice[Count].PortEnable = PtrPcd->PortEnable; CrDevice[Count].DevName = (CHAR16*)&(PtrPcd->DevName); TmpStr = (CHAR16*)GetNextColumnPtr (CrDevice[Count].DevName); DEBUG ((DEBUG_INFO, " PCD value: Idx=%d, En:%d, Name=%s, Dpath Str=%s\n",Count, CrDevice[Count].PortEnable,CrDevice[Count].DevName, TmpStr)); // // Covert device path string to device path node // CrDevice[Count].DevPath = ParserDevicePathString (TmpStr, &CrDevice[Count]); DEBUG ((DEBUG_INFO, " >>Result DPath: %s\n", ConvertDevicePathToText ((const EFI_DEVICE_PATH *)CrDevice[Count].DevPath, FALSE, TRUE))); // // Get next device // PtrPcd = (CR_DEVICE_PCD*) GetNextColumnPtr (TmpStr); } *DeviceCount = Count; *PcdCrDevice = CrDevice; return EFI_SUCCESS; } EFI_STATUS ParsingDevicePath2Attribute ( IN EFI_DEVICE_PATH *DevPath, OUT CR_DEVICE_ATTRIBUTES *Attribute ) { VENDOR_DEVICE_PATH *Vendor; UART_DEVICE_PATH *Uart; UINT8 Index = 0; // // Get Uart Node // Uart = NULL; Uart = (UART_DEVICE_PATH*) LocateDevicePathNode (&DevPath, MESSAGING_DEVICE_PATH, MSG_UART_DP); if (Uart == NULL) { ASSERT(0); return EFI_UNSUPPORTED; } else if (!(DevPath->Type == MESSAGING_DEVICE_PATH && DevPath->SubType == MSG_VENDOR_DP)) { // // Uart node's next deviceNode is not MESSAGING_DEVICE_PATH // ASSERT (0); return EFI_UNSUPPORTED; } // // Check flow control // Vendor = (VENDOR_DEVICE_PATH *) DevPath; if (CompareGuid (&Vendor->Guid, &gEfiUartDevicePathGuid)) { Attribute->FlowControl = (UINT8)(((UART_FLOW_CONTROL_DEVICE_PATH *) Vendor)->FlowControlMap); Vendor = (VENDOR_DEVICE_PATH *) NextDevicePathNode ((VOID*)Vendor); } else { Attribute->FlowControl = 0; } // // Get terminal type // for (Index = 0; mCrTerminalGuidTable[Index].Data1 != 0; Index++) { if (CompareGuid (&Vendor->Guid, &mCrTerminalGuidTable[Index])) { Attribute->TerminalType = Index; break; } } // // Get BaudRate // for (Index = 0; mCrBaudRateTable[Index] != 0; Index++) { if (Uart->BaudRate == mCrBaudRateTable[Index]) { break; } } Attribute->BaudRate = (mCrBaudRateTable[Index] == 0) ? --Index : Index; // // DataBits only support 0x07 - 7 Bits // 0x08 - 8 Bits // Attribute->DataBits = (Uart->DataBits == 7 || Uart->DataBits == 8)? Uart->DataBits : 8; // //StopBits only support 0x01 - 1 Stop Bit // 0x03 - 2 Stop Bits // Attribute->StopBits = (Uart->StopBits == 1 || Uart->StopBits == 3)? Uart->StopBits : 1; // //Parity only support 0x01 - No Parity // 0x02 - Even Parity // 0x03 - Odd Parity // Attribute->Parity = (Uart->Parity >= 1 && Uart->Parity <= 3)? Uart->Parity : 1; return EFI_SUCCESS; } EFI_STATUS CalculateNewVariableSize ( IN OUT CR_DEVICE_VAR **CrDeviceVar, IN OUT UINTN *VarSize, IN UINT8 NewFlowcontrol, OUT DPATH_UPDATE *UpdateType ) { EFI_DEVICE_PATH *NextPath; VENDOR_DEVICE_PATH *VendorDPath; UINT32 OriginalFlowControl; UINTN NewVarSize; CR_DEVICE_VAR *NewCrDeviceVar; OriginalFlowControl = 0; NextPath = GetDevicePathFromVariable (*CrDeviceVar); VendorDPath = (VENDOR_DEVICE_PATH*) LocateDevicePathNode (&NextPath, MESSAGING_DEVICE_PATH, MSG_VENDOR_DP); if (VendorDPath == NULL) { return EFI_NOT_FOUND; } if (CompareGuid (&(VendorDPath->Guid), &gEfiUartDevicePathGuid)) { OriginalFlowControl = ((UART_FLOW_CONTROL_DEVICE_PATH*)VendorDPath)->FlowControlMap; if (OriginalFlowControl == 0) { // // if FlowControl is disable, set FlowControl to non zero, then FlowControl node will delete. // OriginalFlowControl = 1; } } if ((OriginalFlowControl == 0) && (NewFlowcontrol != 0)) { NewVarSize = (*VarSize) + sizeof (UART_FLOW_CONTROL_DEVICE_PATH); NewCrDeviceVar = AllocatePool (NewVarSize); if (NewCrDeviceVar == NULL) { return EFI_OUT_OF_RESOURCES; } CopyMem (NewCrDeviceVar, *CrDeviceVar, *VarSize); FreePool (*CrDeviceVar); *UpdateType = UPDATE_ADD; } else if ((OriginalFlowControl != 0) && (NewFlowcontrol == 0)) { NewVarSize = (*VarSize) - sizeof (UART_FLOW_CONTROL_DEVICE_PATH); NewCrDeviceVar = (*CrDeviceVar); *UpdateType = UPDATE_DELETE; } else { *UpdateType = UPDATE_NONE; return EFI_SUCCESS; } *CrDeviceVar = NewCrDeviceVar; *VarSize = NewVarSize; return EFI_SUCCESS; } EFI_STATUS ParsingAttribute2DevicePath ( IN OUT EFI_DEVICE_PATH *DevPath, IN CR_DEVICE_ATTRIBUTES *Attribute, IN DPATH_UPDATE UpdateType ) { EFI_DEVICE_PATH *DuplicateDpath; EFI_DEVICE_PATH *NodeAfterUart; VENDOR_DEVICE_PATH *TerminalNode; VENDOR_DEVICE_PATH *DuplicateTerminalNode; UART_FLOW_CONTROL_DEVICE_PATH *FlowNode; UART_DEVICE_PATH *Uart; DuplicateDpath = NULL; NodeAfterUart = DevPath; Uart = (UART_DEVICE_PATH*) LocateDevicePathNode (&NodeAfterUart, MESSAGING_DEVICE_PATH, MSG_UART_DP); if (Uart == NULL) { return EFI_UNSUPPORTED; } Uart->BaudRate = mCrBaudRateTable[Attribute->BaudRate]; Uart->DataBits = Attribute->DataBits; Uart->StopBits = Attribute->StopBits; Uart->Parity = Attribute->Parity; if (UpdateType != UPDATE_NONE) { DuplicateDpath = DuplicateDevicePath (NodeAfterUart); } switch (UpdateType) { case UPDATE_DELETE: FlowNode = (UART_FLOW_CONTROL_DEVICE_PATH*)NodeAfterUart; DuplicateTerminalNode = (VENDOR_DEVICE_PATH*) NextDevicePathNode ((VOID*)DuplicateDpath); CopyMem (FlowNode, DuplicateTerminalNode, sizeof (VENDOR_DEVICE_PATH) + sizeof (EFI_DEVICE_PATH)); TerminalNode = (VENDOR_DEVICE_PATH*) FlowNode; FlowNode = NULL; break; case UPDATE_ADD: TerminalNode = (VENDOR_DEVICE_PATH*) NodeAfterUart; CopyMem (TerminalNode, &mFlowControlNode, sizeof (UART_FLOW_CONTROL_DEVICE_PATH)); FlowNode = (UART_FLOW_CONTROL_DEVICE_PATH*)TerminalNode; TerminalNode = (VENDOR_DEVICE_PATH*)(FlowNode + 1); CopyMem (TerminalNode, DuplicateDpath, sizeof (VENDOR_DEVICE_PATH) + sizeof (EFI_DEVICE_PATH)); break; default: TerminalNode = (VENDOR_DEVICE_PATH*)NodeAfterUart; if (CompareGuid (&(TerminalNode->Guid), &gEfiUartDevicePathGuid)) { FlowNode = (UART_FLOW_CONTROL_DEVICE_PATH*)TerminalNode; TerminalNode = (VENDOR_DEVICE_PATH*) NextDevicePathNode ((VOID*)FlowNode); } else { FlowNode = NULL; } } if (FlowNode != NULL) { FlowNode->FlowControlMap = Attribute->FlowControl; } TerminalNode->Guid = mCrTerminalGuidTable[Attribute->TerminalType]; if (DuplicateDpath != NULL) { FreePool (DuplicateDpath); } return EFI_SUCCESS; } VOID* PrepareEnoughCrDeviceVariable ( IN VOID *CrDeviceVar, IN UINTN NewSize, IN OUT UINTN *BufferSize ) { UINT8 *TmpPool; if (NewSize > (*BufferSize)) { TmpPool = (UINT8*) ReallocatePool(*BufferSize, NewSize, (VOID*)CrDeviceVar); if (TmpPool != NULL) { *BufferSize = NewSize; return TmpPool; } else { if (CrDeviceVar != NULL) { FreePool (CrDeviceVar); } return NULL; } } else { return CrDeviceVar; } } VOID UpdateTemplateDeviceNode ( VOID ) { CR_CONFIGURATION *CrConfig; CrConfig = NULL; CrConfig = (CR_CONFIGURATION*) CommonGetVariableData (CONSOLE_REDIRECTION_VARSTORE_DEFAULT_NAME, &gH2OCrConfigurationGuid); if (CrConfig != NULL) { mUartNode.BaudRate = mCrBaudRateTable[CrConfig->GlobalBaudRate]; mUartNode.DataBits = CrConfig->GlobalDataBits; mUartNode.Parity = CrConfig->GlobalParity; mUartNode.StopBits = CrConfig->GlobalStopBits; mTerminalNode.Guid = mCrTerminalGuidTable[CrConfig->GlobalTerminalType]; mFlowControlNode.FlowControlMap = CrConfig->GlobalFlowControl; FreePool (CrConfig); } } EFI_DEVICE_PATH* VerifyMediaFileNode ( IN EFI_DEVICE_PATH *FullDevPath, OUT CR_DEVICE_PCD *PcdDevice ) { CHAR16 *Asterisk = L"*"; EFI_DEVICE_PATH *TempDevPath; EFI_DEVICE_PATH *NextDevPath; NextDevPath = FullDevPath; TempDevPath = LocateDevicePathNode (&NextDevPath, MEDIA_DEVICE_PATH, MEDIA_FILEPATH_DP); if (TempDevPath != NULL) { PcdDevice->Exist = FALSE; if (StrCmp(((FILEPATH_DEVICE_PATH*)TempDevPath)->PathName, Asterisk) != 0) { PcdDevice->ItemType = INVALID_ITEM; DEBUG ((DEBUG_INFO, " Invalid DevicePath!!\n")); return AppendDevicePath (NULL, NULL); } PcdDevice->ItemType = ASTERISK_ITEM; DEBUG ((DEBUG_INFO, " DevicePath with * !\n")); // // if DevicePath with '*' then del * DevicePath node. // CopyMem (TempDevPath, NextDevPath, sizeof (EFI_DEVICE_PATH)); return DuplicateDevicePath(FullDevPath); } return NULL; } EFI_DEVICE_PATH* VerifyUartNode ( IN EFI_DEVICE_PATH *FullDevPath, OUT CR_DEVICE_PCD *PcdDevice ) { UART_DEVICE_PATH *Uart; UINTN Index; EFI_DEVICE_PATH *NextDevPath; EFI_DEVICE_PATH *TempDevPath; NextDevPath = FullDevPath; TempDevPath = LocateDevicePathNode (&NextDevPath, MESSAGING_DEVICE_PATH, MSG_UART_DP); if (TempDevPath == NULL) { // // Create default Uart node // TempDevPath = AppendDevicePathNode (FullDevPath, (EFI_DEVICE_PATH*)&mUartNode); DEBUG ((DEBUG_INFO, " Create Uart Device Node!\n")); FreePool(FullDevPath); return TempDevPath; } else { PcdDevice->UseGlobal = FALSE; // // Check Uart node is vaild? // Uart = (UART_DEVICE_PATH*)TempDevPath; // // Check BaudRate valid // for (Index = 0; mCrBaudRateTable[Index] != 0; Index++) { if (Uart->BaudRate == mCrBaudRateTable[Index]) { break; } } if (mCrBaudRateTable[Index] == 0) { Uart->BaudRate = mUartNode.BaudRate ; } // // Check DataBits vaild. only support 0x07 - 7 Bits // 0x08 - 8 Bits // if (!(Uart->DataBits == 7 || Uart->DataBits == 8)) { Uart->DataBits = mUartNode.DataBits; } // // Check StopBits vaild. only support 0x01 - 1 Stop Bit // 0x03 - 2 Stop Bits // if (!(Uart->StopBits == 1 || Uart->StopBits == 3)) { Uart->StopBits = mUartNode.StopBits; } // // Check Parity vaild. only support 0x01 - No Parity // 0x02 - Even Parity // 0x03 - Odd Parity // if (!(Uart->Parity >= 1 && Uart->Parity <= 3)) { Uart->Parity = mUartNode.Parity; } } return FullDevPath; } EFI_DEVICE_PATH* VerifyMessagingDeviceNode ( IN EFI_DEVICE_PATH *FullDevPath, OUT CR_DEVICE_PCD *PcdDevice ) { UART_FLOW_CONTROL_DEVICE_PATH *FlowDpath; UINTN Index; EFI_DEVICE_PATH *NextDevPath; EFI_DEVICE_PATH *TempDevPath; NextDevPath = FullDevPath; TempDevPath = LocateDevicePathNode(&NextDevPath, MESSAGING_DEVICE_PATH, MSG_VENDOR_DP); if (TempDevPath == NULL) { // // Create default FlowControl & Terminal node // if (mFlowControlNode.FlowControlMap != 0) { TempDevPath = AppendMultiDevicePathNode (FullDevPath, 2, &mFlowControlNode, &mTerminalNode); DEBUG ((DEBUG_INFO, " Create FlowControl & Terminal Node!\n")); } else { TempDevPath = AppendDevicePathNode (FullDevPath, (EFI_DEVICE_PATH*)&mTerminalNode); DEBUG ((DEBUG_INFO, " Create Terminal Device Node!\n")); } FreePool(FullDevPath); return TempDevPath; } else { PcdDevice->UseGlobal = FALSE; FlowDpath = (UART_FLOW_CONTROL_DEVICE_PATH*)TempDevPath; // // Check is a FlowControl node? // if (CompareGuid (&FlowDpath->Guid, &gEfiUartDevicePathGuid)) { // // check is a terminal follow by flow control node? // if (FlowDpath->FlowControlMap > 2) { FlowDpath->FlowControlMap = 0; } TempDevPath = LocateDevicePathNode(&NextDevPath, MESSAGING_DEVICE_PATH, MSG_VENDOR_DP); if (TempDevPath == NULL) { TempDevPath = AppendDevicePathNode (FullDevPath, (EFI_DEVICE_PATH*)&mTerminalNode); DEBUG ((DEBUG_INFO, " Create Terminal Device Node after flow control!\n")); FreePool(FullDevPath); return TempDevPath; } } // // Check terminal node is vaild // for (Index = 0; mCrTerminalGuidTable[Index].Data1 != 0; Index++) { if (CompareGuid (&(((VENDOR_DEVICE_PATH*)TempDevPath)->Guid), &mCrTerminalGuidTable[Index])) { break; } } if (mCrTerminalGuidTable[Index].Data1 == 0) { CopyGuid (&(((VENDOR_DEVICE_PATH*)TempDevPath)->Guid), &mTerminalNode.Guid); } } return FullDevPath; } EFI_STATUS FreeDevicePathPool ( IN CR_DEVICE_PCD *CrDevice, IN UINTN DeviceCount ) { UINT8 Index; for (Index = 0; Index < DeviceCount; Index++) { if (CrDevice[Index].DevPath != NULL) { FreePool((VOID*) CrDevice[Index].DevPath); } } return EFI_SUCCESS; } EFI_DEVICE_PATH_PROTOCOL * AppendMultiDevicePathNode ( EFI_DEVICE_PATH_PROTOCOL *SrcDevicePath, UINTN NumOfArgs, ... ) { VA_LIST Marker; UINTN Index; UINTN NewSize; UINTN SrcSize; EFI_DEVICE_PATH_PROTOCOL *DevPathNode; EFI_DEVICE_PATH_PROTOCOL *DevPathPtr; EFI_DEVICE_PATH_PROTOCOL *NewDevicePath; SrcSize = GetDevicePathSize(SrcDevicePath); NewSize = SrcSize; VA_START (Marker, NumOfArgs); // Caculate the new device path size for (Index = 0; Index < NumOfArgs; Index++) { DevPathNode = VA_ARG (Marker, EFI_DEVICE_PATH_PROTOCOL *); NewSize += DevicePathNodeLength (DevPathNode); } VA_END(Marker); NewDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) AllocateCopyPool (NewSize, SrcDevicePath); DevPathPtr = (EFI_DEVICE_PATH_PROTOCOL *)((UINTN)NewDevicePath + SrcSize - sizeof(EFI_DEVICE_PATH_PROTOCOL)); VA_START (Marker, NumOfArgs); // Copy node to DevicePath for (Index = 0; Index < NumOfArgs; Index++) { DevPathNode = VA_ARG (Marker, EFI_DEVICE_PATH_PROTOCOL *); CopyMem (DevPathPtr, DevPathNode, DevicePathNodeLength (DevPathNode)); DevPathPtr = (EFI_DEVICE_PATH_PROTOCOL *)((UINT8*)DevPathPtr + DevicePathNodeLength (DevPathNode)); } // // Copy End Node // CopyMem (DevPathPtr, &mEnd, sizeof(EFI_DEVICE_PATH_PROTOCOL)); return NewDevicePath; } /** Get the device path node for given device path type and device path sub-type @param [in] DevicePath The device path to be processed @param [in] DevicePathType The device path type @param [in] DevicePathSubType The device path sub type @return The retrieved device path node with the given DevicePathType and DevicePathSubType **/ EFI_DEVICE_PATH_PROTOCOL * LocateDevicePathNode( IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath, IN UINT8 DevPathType, IN UINT8 DevPathSubType ) { EFI_DEVICE_PATH_PROTOCOL *DevPath; if (*DevicePath == NULL) return NULL; DevPath = *DevicePath; while (!IsDevicePathEnd(DevPath)) { if (DevPath->Type == DevPathType && DevPath->SubType == DevPathSubType) { *DevicePath = NextDevicePathNode (DevPath); return DevPath; } DevPath = NextDevicePathNode(DevPath); } *DevicePath = NULL; if (DevPathType == END_DEVICE_PATH_TYPE && DevPathSubType == END_ENTIRE_DEVICE_PATH_SUBTYPE) return DevPath; return NULL; }