/*++ Copyright (c) 1998 Intel Corporation Module Name: dpath.c Abstract: MBR & Device Path functions Revision History --*/ #include "lib.h" #define ALIGN_SIZE(a) ((a % MIN_ALIGNMENT_SIZE) ? MIN_ALIGNMENT_SIZE - (a % MIN_ALIGNMENT_SIZE) : 0) EFI_DEVICE_PATH * DevicePathFromHandle ( IN EFI_HANDLE Handle ) { EFI_STATUS Status; EFI_DEVICE_PATH *DevicePath; Status = BS->HandleProtocol (Handle, &DevicePathProtocol, (VOID*)&DevicePath); if (EFI_ERROR(Status)) { DevicePath = NULL; } return DevicePath; } EFI_DEVICE_PATH * DevicePathInstance ( IN OUT EFI_DEVICE_PATH **DevicePath, OUT UINTN *Size ) { EFI_DEVICE_PATH *Start, *Next, *DevPath; UINTN Count; DevPath = *DevicePath; Start = DevPath; if (!DevPath) { return NULL; } /* * Check for end of device path type * */ for (Count = 0; ; Count++) { Next = NextDevicePathNode(DevPath); if (IsDevicePathEndType(DevPath)) { break; } if (Count > 01000) { /* * BugBug: Debug code to catch bogus device paths */ DEBUG((D_ERROR, "DevicePathInstance: DevicePath %x Size %d", *DevicePath, ((UINT8 *) DevPath) - ((UINT8 *) Start) )); DumpHex (0, 0, ((UINT8 *) DevPath) - ((UINT8 *) Start), Start); break; } DevPath = Next; } ASSERT (DevicePathSubType(DevPath) == END_ENTIRE_DEVICE_PATH_SUBTYPE || DevicePathSubType(DevPath) == END_INSTANCE_DEVICE_PATH_SUBTYPE); /* * Set next position */ if (DevicePathSubType(DevPath) == END_ENTIRE_DEVICE_PATH_SUBTYPE) { Next = NULL; } *DevicePath = Next; /* * Return size and start of device path instance */ *Size = ((UINT8 *) DevPath) - ((UINT8 *) Start); return Start; } UINTN DevicePathInstanceCount ( IN EFI_DEVICE_PATH *DevicePath ) { UINTN Count, Size; Count = 0; while (DevicePathInstance(&DevicePath, &Size)) { Count += 1; } return Count; } EFI_DEVICE_PATH * AppendDevicePath ( IN EFI_DEVICE_PATH *Src1, IN EFI_DEVICE_PATH *Src2 ) /* Src1 may have multiple "instances" and each instance is appended * Src2 is appended to each instance is Src1. (E.g., it's possible * to append a new instance to the complete device path by passing * it in Src2) */ { UINTN Src1Size, Src1Inst, Src2Size, Size; EFI_DEVICE_PATH *Dst, *Inst; UINT8 *DstPos; /* * If there's only 1 path, just duplicate it */ if (!Src1) { ASSERT (!IsDevicePathUnpacked (Src2)); return DuplicateDevicePath (Src2); } if (!Src2) { ASSERT (!IsDevicePathUnpacked (Src1)); return DuplicateDevicePath (Src1); } /* * Verify we're not working with unpacked paths */ /* ASSERT (!IsDevicePathUnpacked (Src1)); * ASSERT (!IsDevicePathUnpacked (Src2)); */ /* * Append Src2 to every instance in Src1 */ Src1Size = DevicePathSize(Src1); Src1Inst = DevicePathInstanceCount(Src1); Src2Size = DevicePathSize(Src2); Size = Src1Size * Src1Inst + Src2Size; Dst = AllocatePool (Size); if (Dst) { DstPos = (UINT8 *) Dst; /* * Copy all device path instances */ while (Inst = DevicePathInstance (&Src1, &Size)) { CopyMem(DstPos, Inst, Size); DstPos += Size; CopyMem(DstPos, Src2, Src2Size); DstPos += Src2Size; CopyMem(DstPos, EndInstanceDevicePath, sizeof(EFI_DEVICE_PATH)); DstPos += sizeof(EFI_DEVICE_PATH); } /* Change last end marker */ DstPos -= sizeof(EFI_DEVICE_PATH); CopyMem(DstPos, EndDevicePath, sizeof(EFI_DEVICE_PATH)); } return Dst; } EFI_DEVICE_PATH * AppendDevicePathNode ( IN EFI_DEVICE_PATH *Src1, IN EFI_DEVICE_PATH *Src2 ) /* Src1 may have multiple "instances" and each instance is appended * Src2 is a signal device path node (without a terminator) that is * appended to each instance is Src1. */ { EFI_DEVICE_PATH *Temp, *Eop; UINTN Length; /* * Build a Src2 that has a terminator on it */ Length = DevicePathNodeLength(Src2); Temp = AllocatePool (Length + sizeof(EFI_DEVICE_PATH)); if (!Temp) { return NULL; } CopyMem (Temp, Src2, Length); Eop = NextDevicePathNode(Temp); SetDevicePathEndNode(Eop); /* * Append device paths */ Src1 = AppendDevicePath (Src1, Temp); FreePool (Temp); return Src1; } EFI_DEVICE_PATH * FileDevicePath ( IN EFI_HANDLE Device OPTIONAL, IN CHAR16 *FileName ) /*++ N.B. Results are allocated from pool. The caller must FreePool the resulting device path structure --*/ { UINTN Size; FILEPATH_DEVICE_PATH *FilePath; EFI_DEVICE_PATH *Eop, *DevicePath; Size = StrSize(FileName); FilePath = AllocateZeroPool (Size + SIZE_OF_FILEPATH_DEVICE_PATH + sizeof(EFI_DEVICE_PATH)); DevicePath = NULL; if (FilePath) { /* * Build a file path */ FilePath->Header.Type = MEDIA_DEVICE_PATH; FilePath->Header.SubType = MEDIA_FILEPATH_DP; SetDevicePathNodeLength (&FilePath->Header, Size + SIZE_OF_FILEPATH_DEVICE_PATH); CopyMem (FilePath->PathName, FileName, Size); Eop = NextDevicePathNode(&FilePath->Header); SetDevicePathEndNode(Eop); /* * Append file path to device's device path */ DevicePath = (EFI_DEVICE_PATH *) FilePath; if (Device) { DevicePath = AppendDevicePath ( DevicePathFromHandle(Device), DevicePath ); FreePool(FilePath); } } return DevicePath; } UINTN DevicePathSize ( IN EFI_DEVICE_PATH *DevPath ) { EFI_DEVICE_PATH *Start; /* * Search for the end of the device path structure * */ Start = DevPath; while (!IsDevicePathEnd(DevPath)) { DevPath = NextDevicePathNode(DevPath); } /* * Compute the size */ return ((UINTN) DevPath - (UINTN) Start) + sizeof(EFI_DEVICE_PATH); } EFI_DEVICE_PATH * DuplicateDevicePath ( IN EFI_DEVICE_PATH *DevPath ) { EFI_DEVICE_PATH *NewDevPath; UINTN Size; /* * Compute the size */ Size = DevicePathSize (DevPath); /* * Make a copy */ NewDevPath = AllocatePool (Size); if (NewDevPath) { CopyMem (NewDevPath, DevPath, Size); } return NewDevPath; } EFI_DEVICE_PATH * UnpackDevicePath ( IN EFI_DEVICE_PATH *DevPath ) { EFI_DEVICE_PATH *Src, *Dest, *NewPath; UINTN Size; /* * Walk device path and round sizes to valid boundries * */ Src = DevPath; Size = 0; for (; ;) { Size += DevicePathNodeLength(Src); Size += ALIGN_SIZE(Size); if (IsDevicePathEnd(Src)) { break; } Src = NextDevicePathNode(Src); } /* * Allocate space for the unpacked path */ NewPath = AllocateZeroPool (Size); if (NewPath) { ASSERT (((UINTN)NewPath) % MIN_ALIGNMENT_SIZE == 0); /* * Copy each node */ Src = DevPath; Dest = NewPath; for (; ;) { Size = DevicePathNodeLength(Src); CopyMem (Dest, Src, Size); Size += ALIGN_SIZE(Size); SetDevicePathNodeLength (Dest, Size); Dest->Type |= EFI_DP_TYPE_UNPACKED; Dest = (EFI_DEVICE_PATH *) (((UINT8 *) Dest) + Size); if (IsDevicePathEnd(Src)) { break; } Src = NextDevicePathNode(Src); } } return NewPath; } EFI_DEVICE_PATH* AppendDevicePathInstance ( IN EFI_DEVICE_PATH *Src, IN EFI_DEVICE_PATH *Instance ) { UINT8 *Ptr; EFI_DEVICE_PATH *DevPath; UINTN SrcSize; UINTN InstanceSize; if (Src == NULL) { return DuplicateDevicePath (Instance); } SrcSize = DevicePathSize(Src); InstanceSize = DevicePathSize(Instance); Ptr = AllocatePool (SrcSize + InstanceSize); DevPath = (EFI_DEVICE_PATH *)Ptr; ASSERT(DevPath); CopyMem (Ptr, Src, SrcSize); /* FreePool (Src); */ while (!IsDevicePathEnd(DevPath)) { DevPath = NextDevicePathNode(DevPath); } /* * Convert the End to an End Instance, since we are * appending another instacne after this one its a good * idea. */ DevPath->SubType = END_INSTANCE_DEVICE_PATH_SUBTYPE; DevPath = NextDevicePathNode(DevPath); CopyMem (DevPath, Instance, InstanceSize); return (EFI_DEVICE_PATH *)Ptr; } EFI_STATUS LibDevicePathToInterface ( IN EFI_GUID *Protocol, IN EFI_DEVICE_PATH *FilePath, OUT VOID **Interface ) { EFI_STATUS Status; EFI_HANDLE Device; Status = BS->LocateDevicePath (Protocol, &FilePath, &Device); if (!EFI_ERROR(Status)) { /* If we didn't get a direct match return not found */ Status = EFI_NOT_FOUND; if (IsDevicePathEnd(FilePath)) { /* * It was a direct match, lookup the protocol interface */ Status = BS->HandleProtocol (Device, Protocol, Interface); } } /* * If there was an error, do not return an interface */ if (EFI_ERROR(Status)) { *Interface = NULL; } return Status; } VOID _DevPathPci ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { PCI_DEVICE_PATH *Pci; Pci = DevPath; CatPrint(Str, L"Pci(%x|%x)", Pci->Device, Pci->Function); } VOID _DevPathPccard ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { PCCARD_DEVICE_PATH *Pccard; Pccard = DevPath; CatPrint(Str, L"Pccard(Socket%x)", Pccard->SocketNumber); } VOID _DevPathMemMap ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { MEMMAP_DEVICE_PATH *MemMap; MemMap = DevPath; CatPrint(Str, L"MemMap(%d:%x-%x)", MemMap->MemoryType, MemMap->StartingAddress, MemMap->EndingAddress ); } VOID _DevPathController ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { CONTROLLER_DEVICE_PATH *Controller; Controller = DevPath; CatPrint(Str, L"Ctrl(%d)", Controller->Controller ); } VOID _DevPathVendor ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { VENDOR_DEVICE_PATH *Vendor; CHAR16 *Type; UNKNOWN_DEVICE_VENDOR_DEVICE_PATH *UnknownDevPath; Vendor = DevPath; switch (DevicePathType(&Vendor->Header)) { case HARDWARE_DEVICE_PATH: Type = L"Hw"; break; case MESSAGING_DEVICE_PATH: Type = L"Msg"; break; case MEDIA_DEVICE_PATH: Type = L"Media"; break; default: Type = L"?"; break; } CatPrint(Str, L"Ven%s(%g", Type, &Vendor->Guid); if (CompareGuid (&Vendor->Guid, &UnknownDevice) == 0) { /* * GUID used by EFI to enumerate an EDD 1.1 device */ UnknownDevPath = (UNKNOWN_DEVICE_VENDOR_DEVICE_PATH *)Vendor; CatPrint(Str, L":%02x)", UnknownDevPath->LegacyDriveLetter); } else { CatPrint(Str, L")"); } } VOID _DevPathAcpi ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { ACPI_HID_DEVICE_PATH *Acpi; Acpi = DevPath; if ((Acpi->HID & PNP_EISA_ID_MASK) == PNP_EISA_ID_CONST) { CatPrint(Str, L"Acpi(PNP%04x,%x)", EISA_ID_TO_NUM (Acpi->HID), Acpi->UID); } else { CatPrint(Str, L"Acpi(%08x,%x)", Acpi->HID, Acpi->UID); } } VOID _DevPathAtapi ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { ATAPI_DEVICE_PATH *Atapi; Atapi = DevPath; CatPrint(Str, L"Ata(%s,%s)", Atapi->PrimarySecondary ? L"Secondary" : L"Primary", Atapi->SlaveMaster ? L"Slave" : L"Master" ); } VOID _DevPathScsi ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { SCSI_DEVICE_PATH *Scsi; Scsi = DevPath; CatPrint(Str, L"Scsi(Pun%x,Lun%x)", Scsi->Pun, Scsi->Lun); } VOID _DevPathFibre ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { FIBRECHANNEL_DEVICE_PATH *Fibre; Fibre = DevPath; CatPrint(Str, L"Fibre(%lx)", Fibre->WWN); } VOID _DevPath1394 ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { F1394_DEVICE_PATH *F1394; F1394 = DevPath; CatPrint(Str, L"1394(%g)", &F1394->Guid); } VOID _DevPathUsb ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { USB_DEVICE_PATH *Usb; Usb = DevPath; CatPrint(Str, L"Usb(%x)", Usb->Port); } VOID _DevPathI2O ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { I2O_DEVICE_PATH *I2O; I2O = DevPath; CatPrint(Str, L"I2O(%x)", I2O->Tid); } VOID _DevPathMacAddr ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { MAC_ADDR_DEVICE_PATH *MAC; UINTN HwAddressSize; UINTN Index; MAC = DevPath; HwAddressSize = sizeof(EFI_MAC_ADDRESS); if (MAC->IfType == 0x01 || MAC->IfType == 0x00) { HwAddressSize = 6; } CatPrint(Str, L"Mac("); for(Index = 0; Index < HwAddressSize; Index++) { CatPrint(Str, L"%02x",MAC->MacAddress.Addr[Index]); } CatPrint(Str, L")"); } VOID _DevPathIPv4 ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { IPv4_DEVICE_PATH *IP; IP = DevPath; CatPrint(Str, L"IPv4(not-done)"); } VOID _DevPathIPv6 ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { IPv6_DEVICE_PATH *IP; IP = DevPath; CatPrint(Str, L"IP-v6(not-done)"); } VOID _DevPathInfiniBand ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { INFINIBAND_DEVICE_PATH *InfiniBand; InfiniBand = DevPath; CatPrint(Str, L"InfiniBand(not-done)"); } VOID _DevPathUart ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { UART_DEVICE_PATH *Uart; CHAR8 Parity; Uart = DevPath; switch (Uart->Parity) { case 0 : Parity = 'D'; break; case 1 : Parity = 'N'; break; case 2 : Parity = 'E'; break; case 3 : Parity = 'O'; break; case 4 : Parity = 'M'; break; case 5 : Parity = 'S'; break; default : Parity = 'x'; break; } if (Uart->BaudRate == 0) { CatPrint(Str, L"Uart(DEFAULT %c",Uart->BaudRate,Parity); } else { CatPrint(Str, L"Uart(%d %c",Uart->BaudRate,Parity); } if (Uart->DataBits == 0) { CatPrint(Str, L"D"); } else { CatPrint(Str, L"%d",Uart->DataBits); } switch (Uart->StopBits) { case 0 : CatPrint(Str, L"D)"); break; case 1 : CatPrint(Str, L"1)"); break; case 2 : CatPrint(Str, L"1.5)"); break; case 3 : CatPrint(Str, L"2)"); break; default : CatPrint(Str, L"x)"); break; } } VOID _DevPathHardDrive ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { HARDDRIVE_DEVICE_PATH *Hd; Hd = DevPath; switch (Hd->SignatureType) { case SIGNATURE_TYPE_MBR: CatPrint(Str, L"HD(Part%d,Sig%08X)", Hd->PartitionNumber, *((UINT32 *)(&(Hd->Signature[0]))) ); break; case SIGNATURE_TYPE_GUID: CatPrint(Str, L"HD(Part%d,Sig%g)", Hd->PartitionNumber, (EFI_GUID *) &(Hd->Signature[0]) ); break; default: CatPrint(Str, L"HD(Part%d,MBRType=%02x,SigType=%02x)", Hd->PartitionNumber, Hd->MBRType, Hd->SignatureType ); break; } } VOID _DevPathCDROM ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { CDROM_DEVICE_PATH *Cd; Cd = DevPath; CatPrint(Str, L"CDROM(Entry%x)", Cd->BootEntry); } VOID _DevPathFilePath ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { FILEPATH_DEVICE_PATH *Fp; Fp = DevPath; CatPrint(Str, L"%s", Fp->PathName); } VOID _DevPathMediaProtocol ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { MEDIA_PROTOCOL_DEVICE_PATH *MediaProt; MediaProt = DevPath; CatPrint(Str, L"%g", &MediaProt->Protocol); } VOID _DevPathBssBss ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { BBS_BBS_DEVICE_PATH *Bss; CHAR16 *Type; Bss = DevPath; switch (Bss->DeviceType) { case BBS_TYPE_FLOPPY: Type = L"Floppy"; break; case BBS_TYPE_HARDDRIVE: Type = L"Harddrive"; break; case BBS_TYPE_CDROM: Type = L"CDROM"; break; case BBS_TYPE_PCMCIA: Type = L"PCMCIA"; break; case BBS_TYPE_USB: Type = L"Usb"; break; case BBS_TYPE_EMBEDDED_NETWORK: Type = L"Net"; break; default: Type = L"?"; break; } CatPrint(Str, L"Bss-%s(%a)", Type, Bss->String); } VOID _DevPathEndInstance ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { CatPrint(Str, L","); } VOID _DevPathNodeUnknown ( IN OUT POOL_PRINT *Str, IN VOID *DevPath ) { CatPrint(Str, L"?"); } struct { UINT8 Type; UINT8 SubType; VOID (*Function)(POOL_PRINT *, VOID *); } DevPathTable[] = { HARDWARE_DEVICE_PATH, HW_PCI_DP, _DevPathPci, HARDWARE_DEVICE_PATH, HW_PCCARD_DP, _DevPathPccard, HARDWARE_DEVICE_PATH, HW_MEMMAP_DP, _DevPathMemMap, HARDWARE_DEVICE_PATH, HW_VENDOR_DP, _DevPathVendor, HARDWARE_DEVICE_PATH, HW_CONTROLLER_DP, _DevPathController, ACPI_DEVICE_PATH, ACPI_DP, _DevPathAcpi, MESSAGING_DEVICE_PATH, MSG_ATAPI_DP, _DevPathAtapi, MESSAGING_DEVICE_PATH, MSG_SCSI_DP, _DevPathScsi, MESSAGING_DEVICE_PATH, MSG_FIBRECHANNEL_DP, _DevPathFibre, MESSAGING_DEVICE_PATH, MSG_1394_DP, _DevPath1394, MESSAGING_DEVICE_PATH, MSG_USB_DP, _DevPathUsb, MESSAGING_DEVICE_PATH, MSG_I2O_DP, _DevPathI2O, MESSAGING_DEVICE_PATH, MSG_MAC_ADDR_DP, _DevPathMacAddr, MESSAGING_DEVICE_PATH, MSG_IPv4_DP, _DevPathIPv4, MESSAGING_DEVICE_PATH, MSG_IPv6_DP, _DevPathIPv6, MESSAGING_DEVICE_PATH, MSG_INFINIBAND_DP, _DevPathInfiniBand, MESSAGING_DEVICE_PATH, MSG_UART_DP, _DevPathUart, MESSAGING_DEVICE_PATH, MSG_VENDOR_DP, _DevPathVendor, MEDIA_DEVICE_PATH, MEDIA_HARDDRIVE_DP, _DevPathHardDrive, MEDIA_DEVICE_PATH, MEDIA_CDROM_DP, _DevPathCDROM, MEDIA_DEVICE_PATH, MEDIA_VENDOR_DP, _DevPathVendor, MEDIA_DEVICE_PATH, MEDIA_FILEPATH_DP, _DevPathFilePath, MEDIA_DEVICE_PATH, MEDIA_PROTOCOL_DP, _DevPathMediaProtocol, BBS_DEVICE_PATH, BBS_BBS_DP, _DevPathBssBss, END_DEVICE_PATH_TYPE, END_INSTANCE_DEVICE_PATH_SUBTYPE, _DevPathEndInstance, 0, 0, NULL }; CHAR16 * DevicePathToStr ( EFI_DEVICE_PATH *DevPath ) /*++ Turns the Device Path into a printable string. Allcoates the string from pool. The caller must FreePool the returned string. --*/ { POOL_PRINT Str; EFI_DEVICE_PATH *DevPathNode; VOID (*DumpNode)(POOL_PRINT *, VOID *); UINTN Index, NewSize; ZeroMem(&Str, sizeof(Str)); /* * Unpacked the device path */ DevPath = UnpackDevicePath(DevPath); ASSERT (DevPath); /* * Process each device path node * */ DevPathNode = DevPath; while (!IsDevicePathEnd(DevPathNode)) { /* * Find the handler to dump this device path node */ DumpNode = NULL; for (Index = 0; DevPathTable[Index].Function; Index += 1) { if (DevicePathType(DevPathNode) == DevPathTable[Index].Type && DevicePathSubType(DevPathNode) == DevPathTable[Index].SubType) { DumpNode = DevPathTable[Index].Function; break; } } /* * If not found, use a generic function */ if (!DumpNode) { DumpNode = _DevPathNodeUnknown; } /* * Put a path seperator in if needed */ if (Str.len && DumpNode != _DevPathEndInstance) { CatPrint (&Str, L"/"); } /* * Print this node of the device path */ DumpNode (&Str, DevPathNode); /* * Next device path node */ DevPathNode = NextDevicePathNode(DevPathNode); } /* * Shrink pool used for string allocation */ FreePool (DevPath); NewSize = (Str.len + 1) * sizeof(CHAR16); Str.str = ReallocatePool (Str.str, NewSize, NewSize); Str.str[Str.len] = 0; return Str.str; } BOOLEAN LibMatchDevicePaths ( IN EFI_DEVICE_PATH *Multi, IN EFI_DEVICE_PATH *Single ) { EFI_DEVICE_PATH *DevicePath, *DevicePathInst; UINTN Size; if (!Multi || !Single) { return FALSE; } DevicePath = Multi; while (DevicePathInst = DevicePathInstance (&DevicePath, &Size)) { if (CompareMem (Single, DevicePathInst, Size) == 0) { return TRUE; } } return FALSE; } EFI_DEVICE_PATH * LibDuplicateDevicePathInstance ( IN EFI_DEVICE_PATH *DevPath ) { EFI_DEVICE_PATH *NewDevPath,*DevicePathInst,*Temp; UINTN Size; /* * get the size of an instance from the input */ Temp = DevPath; DevicePathInst = DevicePathInstance (&Temp, &Size); /* * Make a copy and set proper end type */ NewDevPath = NULL; if (Size) { NewDevPath = AllocatePool (Size + sizeof(EFI_DEVICE_PATH)); } if (NewDevPath) { CopyMem (NewDevPath, DevicePathInst, Size); Temp = NextDevicePathNode(NewDevPath); SetDevicePathEndNode(Temp); } return NewDevPath; }