// // get node // EFI_DEVICE_PATH_PROTOCOL* DevPathGetNode(EFI_DEVICE_PATH_PROTOCOL* devicePath, UINT8 type, UINT8 subType) { while(!EfiIsDevicePathEnd(devicePath)) { if(EfiDevicePathType(devicePath) == type && devicePath->SubType == subType) return devicePath; devicePath = EfiNextDevicePathNode(devicePath); } return nullptr; }
// // check net // BOOLEAN DevPathHasMacAddressNode(EFI_DEVICE_PATH_PROTOCOL* devicePath) { while(!EfiIsDevicePathEnd(devicePath)) { if(EfiDevicePathType(devicePath) == MESSAGING_DEVICE_PATH && devicePath->SubType == MSG_MAC_ADDR_DP) return TRUE; devicePath = EfiNextDevicePathNode(devicePath); } return FALSE; }
// // get partition number // UINT32 DevPathGetPartitionNumber(EFI_DEVICE_PATH_PROTOCOL* devicePath) { while(!EfiIsDevicePathEnd(devicePath)) { if(EfiDevicePathType(devicePath) == MEDIA_DEVICE_PATH && devicePath->SubType == MEDIA_HARDDRIVE_DP) { HARDDRIVE_DEVICE_PATH* hardDriveDevicePath = _CR(devicePath, HARDDRIVE_DEVICE_PATH, Header); if(hardDriveDevicePath->SignatureType == SIGNATURE_TYPE_GUID && hardDriveDevicePath->MBRType == MBR_TYPE_EFI_PARTITION_TABLE_HEADER) return hardDriveDevicePath->PartitionNumber; } devicePath = EfiNextDevicePathNode(devicePath); } return static_cast<UINT32>(-1); }
std::string getCanonicalEfiDevicePath(const CFDataRef& data) { std::string path; // Iterate through the EFI_DEVICE_PATH_PROTOCOL stacked structs. auto bytes = CFDataGetBytePtr((CFDataRef)data); size_t length = CFDataGetLength((CFDataRef)data); size_t search_offset = 0; while ((search_offset + sizeof(EFI_DEVICE_PATH_PROTOCOL)) < length) { auto node = (const EFI_DEVICE_PATH_PROTOCOL*)(bytes + search_offset); if (EfiIsDevicePathEnd(node)) { // End of the EFI device path stacked structs. break; } if (EfiDevicePathNodeLength(node) + search_offset > length) { // Malformed EFI device header. break; } // Only support paths and hard drive partitions. if (EfiDevicePathType(node) == MEDIA_DEVICE_PATH) { if (node->SubType == MEDIA_FILEPATH_DP) { for (int i = 0; i < EfiDevicePathNodeLength(node); i += 2) { // Strip UTF16 characters to UTF8. path += (((char*)(node)) + sizeof(EFI_DEVICE_PATH_PROTOCOL))[i]; } } else if (node->SubType == MEDIA_HARDDRIVE_DP) { // Extract the device UUID to later join with block devices. auto uuid = ((const HARDDRIVE_DEVICE_PATH*)node)->Signature; boost::uuids::uuid hdd_signature = {{ uuid[3], uuid[2], uuid[1], uuid[0], uuid[5], uuid[4], uuid[7], uuid[6], uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15], }}; path += boost::to_upper_copy(boost::uuids::to_string(hdd_signature)); } } search_offset += EfiDevicePathNodeLength(node); } return path; }
// // append file path // EFI_DEVICE_PATH_PROTOCOL* DevPathAppendLastComponent(EFI_DEVICE_PATH_PROTOCOL* devicePath, CHAR8 CONST* fileName, BOOLEAN replaceLastComponent) { UINTN fileNameLength = strlen(fileName); UINTN length = DevPathGetSize(devicePath) + (fileNameLength + 1) * sizeof(CHAR16); EFI_DEVICE_PATH_PROTOCOL* newDevicePath = static_cast<EFI_DEVICE_PATH_PROTOCOL*>(MmAllocatePool(length)); if(!newDevicePath) return nullptr; EFI_DEVICE_PATH_PROTOCOL* dstDevicePath = newDevicePath; EFI_DEVICE_PATH_PROTOCOL* srcDevicePath = devicePath; FILEPATH_DEVICE_PATH* srcFilePath = nullptr; FILEPATH_DEVICE_PATH* dstFilePath = nullptr; while(!EfiIsDevicePathEnd(srcDevicePath)) { if(EfiDevicePathType(srcDevicePath) == MEDIA_DEVICE_PATH && srcDevicePath->SubType == MEDIA_FILEPATH_DP) { srcFilePath = _CR(srcDevicePath, FILEPATH_DEVICE_PATH, Header); dstFilePath = _CR(dstDevicePath, FILEPATH_DEVICE_PATH, Header); } memcpy(dstDevicePath, srcDevicePath, DevicePathNodeLength(srcDevicePath)); srcDevicePath = EfiNextDevicePathNode(srcDevicePath); dstDevicePath = EfiNextDevicePathNode(dstDevicePath); } if(!srcFilePath || !dstFilePath) { MmFreePool(newDevicePath); return nullptr; } dstFilePath->Header.Type = MEDIA_DEVICE_PATH; dstFilePath->Header.SubType = MEDIA_FILEPATH_DP; UINTN writePosition = 0; if(replaceLastComponent) { CHAR16* pathName = srcFilePath->PathName; CHAR16* lastDirectory = nullptr; UINTN pathLength = (DevicePathNodeLength(&srcFilePath->Header) - SIZE_OF_FILEPATH_DEVICE_PATH) / sizeof(CHAR16); for(UINTN i = 0; i < pathLength && pathName[i]; i ++) { if(pathName[i] == L'\\' || pathName[i] == L'/') lastDirectory = pathName + i; } if(lastDirectory) lastDirectory += 1; else lastDirectory = pathName; writePosition = lastDirectory - pathName; } else { writePosition = (DevicePathNodeLength(&srcFilePath->Header) - SIZE_OF_FILEPATH_DEVICE_PATH) / sizeof(CHAR16); while(!srcFilePath->PathName[writePosition - 1] && writePosition) writePosition -= 1; } UINTN usedLength = ArchConvertPointerToAddress(dstFilePath->PathName + writePosition) - ArchConvertPointerToAddress(newDevicePath); BlUtf8ToUnicode(fileName, fileNameLength, dstFilePath->PathName + writePosition, (length - usedLength - END_DEVICE_PATH_LENGTH) / sizeof(CHAR16)); UINTN nodeLength = SIZE_OF_FILEPATH_DEVICE_PATH + (wcslen(dstFilePath->PathName) + 1) * sizeof(CHAR16); SetDevicePathNodeLength(&dstFilePath->Header, nodeLength); EFI_DEVICE_PATH_PROTOCOL* endOfPath = NextDevicePathNode(&dstFilePath->Header); SetDevicePathEndNode(endOfPath); return newDevicePath; }