/** * Set file position * * @v This File handle * @v Position New file position * @ret Status EFI status code */ static EFI_STATUS EFIAPI FileSetPosition(EFI_FILE_HANDLE This, UINT64 Position) { EFI_GRUB_FILE *File = _CR(This, EFI_GRUB_FILE, EfiFile); UINT64 FileSize; PrintInfo(L"SetPosition(%llx|'%s', %lld) %s\n", (UINT64) This, FileName(File), Position, (File->IsDir)?L"<DIR>":L""); /* If this is a directory, reset the Index to the start */ if (File->IsDir) { if (Position != 0) return EFI_INVALID_PARAMETER; File->DirIndex = 0; return EFI_SUCCESS; } /* Fail if we attempt to seek past the end of the file (since * we do not support writes). */ FileSize = GrubGetFileSize(File); if (Position > FileSize) { PrintError(L"'%s': Cannot seek to %#llx of %llx\n", FileName(File), Position, FileSize); return EFI_UNSUPPORTED; } /* Set position */ GrubSetFileOffset(File, Position); PrintDebug(L"'%s': Position set to %llx\n", FileName(File), Position); return EFI_SUCCESS; }
/** * Flush file modified data * * @v This File handle * @v Type Type of information * @v Len Buffer size * @v Data Buffer * @ret Status EFI status code */ static EFI_STATUS EFIAPI FileFlush(EFI_FILE_HANDLE This) { EFI_GRUB_FILE *File = _CR(This, EFI_GRUB_FILE, EfiFile); PrintInfo(L"Flush(%llx|'%s')\n", (UINT64)This, FileName(File)); return EFI_SUCCESS; }
/** * Write to file * * @v This File handle * @v Len Length to write * @v Data Data buffer * @ret Status EFI status code */ static EFI_STATUS EFIAPI FileWrite(EFI_FILE_HANDLE This, UINTN *Len, VOID *Data) { EFI_GRUB_FILE *File = _CR(This, EFI_GRUB_FILE, EfiFile); PrintError(L"Cannot write to '%s'\n", FileName(File)); return EFI_WRITE_PROTECTED; }
/** * Open root directory * * @v This EFI simple file system * @ret Root File handle for the root directory * @ret Status EFI status code */ EFI_STATUS EFIAPI FileOpenVolume(EFI_FILE_IO_INTERFACE *This, EFI_FILE_HANDLE *Root) { EFI_FS *FSInstance = _CR(This, EFI_FS, FileIoInterface); PrintInfo(L"OpenVolume\n"); *Root = &FSInstance->RootFile->EfiFile; return EFI_SUCCESS; }
/** * Set file information * * @v This File handle * @v Type Type of information * @v Len Buffer size * @v Data Buffer * @ret Status EFI status code */ static EFI_STATUS EFIAPI FileSetInfo(EFI_FILE_HANDLE This, EFI_GUID *Type, UINTN Len, VOID *Data) { EFI_GRUB_FILE *File = _CR(This, EFI_GRUB_FILE, EfiFile); CHAR16 GuidString[36]; GuidToString(GuidString, Type); PrintError(L"Cannot set information of type %s for file '%s'\n", GuidString, FileName(File)); return EFI_WRITE_PROTECTED; }
/** * Close and delete file * * @v This File handle * @ret Status EFI status code */ static EFI_STATUS EFIAPI FileDelete(EFI_FILE_HANDLE This) { EFI_GRUB_FILE *File = _CR(This, EFI_GRUB_FILE, EfiFile); PrintError(L"Cannot delete '%s'\n", FileName(File)); /* Close file */ FileClose(This); /* Warn of failure to delete */ return EFI_WARN_DELETE_FAILURE; }
/** * Get file position * * @v This File handle * @ret Position New file position * @ret Status EFI status code */ static EFI_STATUS EFIAPI FileGetPosition(EFI_FILE_HANDLE This, UINT64 *Position) { EFI_GRUB_FILE *File = _CR(This, EFI_GRUB_FILE, EfiFile); PrintInfo(L"GetPosition(%llx|'%s', %lld)\n", This, FileName(File)); if (File->IsDir) *Position = File->DirIndex; else *Position = GrubGetFileOffset(File); return EFI_SUCCESS; }
/** * Read from file * * @v This File handle * @v Len Length to read * @v Data Data buffer * @ret Status EFI status code */ static EFI_STATUS EFIAPI FileRead(EFI_FILE_HANDLE This, UINTN *Len, VOID *Data) { EFI_GRUB_FILE *File = _CR(This, EFI_GRUB_FILE, EfiFile); PrintInfo(L"Read(%llx|'%s', %d) %s\n", This, FileName(File), *Len, File->IsDir?L"<DIR>":L""); /* If this is a directory, then fetch the directory entries */ if (File->IsDir) return FileReadDir(File, Len, Data); return GrubRead(File, Data, Len); }
// // 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); }
static EFI_STATUS EFIAPI FSBindingStop(EFI_DRIVER_BINDING_PROTOCOL *This, EFI_HANDLE ControllerHandle, UINTN NumberOfChildren, EFI_HANDLE *ChildHandleBuffer) { EFI_STATUS Status; EFI_FS *Instance; EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FileIoInterface; PrintDebug(L"FSBindingStop\n"); /* Get a pointer back to our FS instance through its installed protocol */ Status = BS->OpenProtocol(ControllerHandle, &gEfiSimpleFileSystemProtocolGuid, (VOID **) &FileIoInterface, This->DriverBindingHandle, ControllerHandle, EFI_OPEN_PROTOCOL_GET_PROTOCOL); if (EFI_ERROR(Status)) { PrintStatusError(Status, L"Could not locate our instance"); return Status; } Instance = _CR(FileIoInterface, EFI_FS, FileIoInterface); FSUninstall(Instance, ControllerHandle); Status = GrubDeviceExit(Instance); if (EFI_ERROR(Status)) { PrintStatusError(Status, L"Could not destroy grub device"); } BS->CloseProtocol(ControllerHandle, &gEfiDiskIo2ProtocolGuid, This->DriverBindingHandle, ControllerHandle); BS->CloseProtocol(ControllerHandle, &gEfiDiskIoProtocolGuid, This->DriverBindingHandle, ControllerHandle); FreeFsInstance(Instance); return EFI_SUCCESS; }
/** * Close file * * @v This File handle * @ret Status EFI status code */ static EFI_STATUS EFIAPI FileClose(EFI_FILE_HANDLE This) { EFI_GRUB_FILE *File = _CR(This, EFI_GRUB_FILE, EfiFile); PrintInfo(L"Close(%llx|'%s') %s\n", (UINT64) This, FileName(File), IS_ROOT(File)?L"<ROOT>":L""); /* Nothing to do it this is the root */ if (IS_ROOT(File)) return EFI_SUCCESS; if (--File->RefCount == 0) { /* Close the file if it's a regular one */ if (!File->IsDir) GrubClose(File); /* NB: basename points into File->path and does not need to be freed */ FreePool(File->path); GrubDestroyFile(File); } return EFI_SUCCESS; }
/** * Open file * * @v This File handle * @ret new New file handle * @v Name File name * @v Mode File mode * @v Attributes File attributes (for newly-created files) * @ret Status EFI status code */ static EFI_STATUS EFIAPI FileOpen(EFI_FILE_HANDLE This, EFI_FILE_HANDLE *New, CHAR16 *Name, UINT64 Mode, UINT64 Attributes) { EFI_STATUS Status; EFI_GRUB_FILE *File = _CR(This, EFI_GRUB_FILE, EfiFile); EFI_GRUB_FILE *NewFile; // TODO: Use dynamic buffers? char path[MAX_PATH], clean_path[MAX_PATH], *dirname; INTN i, len; BOOLEAN AbsolutePath = (*Name == L'\\'); PrintInfo(L"Open(%llx%s, \"%s\")\n", (UINT64) This, IS_ROOT(File)?L" <ROOT>":L"", Name); /* Fail unless opening read-only */ if (Mode != EFI_FILE_MODE_READ) { PrintWarning(L"File '%s' can only be opened in read-only mode\n", Name); return EFI_WRITE_PROTECTED; } /* Additional failures */ if ((StrCmp(Name, L"..") == 0) && IS_ROOT(File)) { PrintInfo(L"Trying to open <ROOT>'s parent\n"); return EFI_NOT_FOUND; } /* See if we're trying to reopen current (which the EFI Shell insists on doing) */ if ((*Name == 0) || (StrCmp(Name, L".") == 0)) { PrintInfo(L" Reopening %s\n", IS_ROOT(File)?L"<ROOT>":FileName(File)); File->RefCount++; *New = This; PrintInfo(L" RET: %llx\n", (UINT64) *New); return EFI_SUCCESS; } /* If we have an absolute path, don't bother completing with the parent */ if (AbsolutePath) { len = 0; } else { strcpya(path, File->path); len = strlena(path); /* Add delimiter if needed */ if ((len == 0) || (path[len-1] != '/')) path[len++] = '/'; } /* Copy the rest of the path (converted to UTF-8) */ Status = Utf16ToUtf8NoAlloc(Name, &path[len], sizeof(path) - len); if (EFI_ERROR(Status)) { PrintStatusError(Status, L"Could not convert path to UTF-8"); return Status; } /* Convert the delimiters */ for (i = strlena(path) - 1 ; i >= len; i--) { if (path[i] == '\\') path[i] = '/'; } /* We only want to handle with absolute paths */ clean_path[0] = '/'; /* Find out if we're dealing with root by removing the junk */ CopyPathRelative(&clean_path[1], path, MAX_PATH - 1); if (clean_path[1] == 0) { /* We're dealing with the root */ PrintInfo(L" Reopening <ROOT>\n"); *New = &File->FileSystem->RootFile->EfiFile; /* Must make sure that DirIndex is reset too (NB: no concurrent access!) */ File->FileSystem->RootFile->DirIndex = 0; PrintInfo(L" RET: %llx\n", (UINT64) *New); return EFI_SUCCESS; } // TODO: eventually we should seek for already opened files and increase RefCount */ /* Allocate and initialise an instance of a file */ Status = GrubCreateFile(&NewFile, File->FileSystem); if (EFI_ERROR(Status)) { PrintStatusError(Status, L"Could not instantiate file"); return Status; } NewFile->path = AllocatePool(strlena(clean_path)+1); if (NewFile->path == NULL) { GrubDestroyFile(NewFile); PrintError(L"Could not instantiate path\n"); return EFI_OUT_OF_RESOURCES; } strcpya(NewFile->path, clean_path); /* Isolate the basename and dirname */ // TODO: would be nicer to have those if path.c for (i = strlena(clean_path) - 1; i >= 0; i--) { if (clean_path[i] == '/') { clean_path[i] = 0; break; } } dirname = (i <= 0) ? "/" : clean_path; NewFile->basename = &NewFile->path[i+1]; /* Find if we're working with a directory and fill the grub timestamp */ Status = GrubDir(NewFile, dirname, InfoHook, (VOID *) NewFile); if (EFI_ERROR(Status)) { if (Status != EFI_NOT_FOUND) PrintStatusError(Status, L"Could not get file attributes for '%s'", Name); FreePool(NewFile->path); GrubDestroyFile(NewFile); return Status; } /* Finally we can call on GRUB open() if it's a regular file */ if (!NewFile->IsDir) { Status = GrubOpen(NewFile); if (EFI_ERROR(Status)) { if (Status != EFI_NOT_FOUND) PrintStatusError(Status, L"Could not open file '%s'", Name); FreePool(NewFile->path); GrubDestroyFile(NewFile); return Status; } } NewFile->RefCount++; *New = &NewFile->EfiFile; PrintInfo(L" RET: %llx\n", (UINT64) *New); return EFI_SUCCESS; }
// // get utf8 name // CHAR8* DevPathExtractFilePathName(EFI_DEVICE_PATH_PROTOCOL* devicePath, BOOLEAN fullPath) { FILEPATH_DEVICE_PATH* startFilePath = nullptr; FILEPATH_DEVICE_PATH* endFilePath = nullptr; UINTN totalLength = 0; while(!EfiIsDevicePathEnd(devicePath)) { if(devicePath->Type == MEDIA_DEVICE_PATH && devicePath->SubType == MEDIA_FILEPATH_DP) { endFilePath = _CR(devicePath, FILEPATH_DEVICE_PATH, Header); totalLength += DevicePathNodeLength(devicePath) - SIZE_OF_FILEPATH_DEVICE_PATH + sizeof(CHAR16); if(!startFilePath) startFilePath = endFilePath; } else if(startFilePath) { break; } devicePath = EfiNextDevicePathNode(devicePath); } if(!startFilePath) return nullptr; CHAR16* pathName = nullptr; CHAR16* allocatedPathName = nullptr; UINTN pathLength = 0; if(startFilePath != endFilePath) { allocatedPathName = static_cast<CHAR16*>(MmAllocatePool(totalLength)); if(!allocatedPathName) return nullptr; pathName = allocatedPathName; while(TRUE) { UINTN length = (DevicePathNodeLength(&startFilePath->Header) - SIZE_OF_FILEPATH_DEVICE_PATH) / sizeof(CHAR16); for(UINTN i = 0; i < length && startFilePath->PathName[i]; i ++, pathLength ++) pathName[pathLength] = startFilePath->PathName[i]; if(startFilePath == endFilePath) break; startFilePath = _CR(EfiNextDevicePathNode(&startFilePath->Header), FILEPATH_DEVICE_PATH, Header); } } else { pathName = startFilePath->PathName; pathLength = (DevicePathNodeLength(&startFilePath->Header) - SIZE_OF_FILEPATH_DEVICE_PATH) / sizeof(CHAR16); while(!pathName[pathLength - 1] && pathLength) pathLength -= 1; } CHAR16* lastDirectory = nullptr; for(UINTN i = 0; i < pathLength && pathName[i]; i ++) { if(pathName[i] == L'\\' || pathName[i] == L'/') lastDirectory = pathName + i; } if(lastDirectory && !fullPath) lastDirectory += 1; else lastDirectory = pathName; CHAR8* retValue = BlAllocateUtf8FromUnicode(lastDirectory, pathName + pathLength - lastDirectory); if(retValue) BlConvertPathSeparator(retValue, '/', '\\'); if(allocatedPathName) MmFreePool(allocatedPathName); return retValue; }
// // get partition handle by number // EFI_HANDLE DevPathGetPartitionHandleByNumber(EFI_DEVICE_PATH_PROTOCOL* referencePath, UINT32 number) { UINTN nodeCount = DevPathGetNodeCount(referencePath); if(!nodeCount) return nullptr; UINTN count = 0; EFI_HANDLE* handleArray = nullptr; if(EFI_ERROR(EfiBootServices->LocateHandleBuffer(ByProtocol, &EfiBlockIoProtocolGuid, nullptr, &count, &handleArray))) return nullptr; EFI_HANDLE retValue = nullptr; for(UINTN i = 0; i < count; i ++) { EFI_HANDLE theHandle = handleArray[i]; if(!theHandle) continue; EFI_DEVICE_PATH_PROTOCOL* devicePath = DevPathGetDevicePathProtocol(theHandle); if(!devicePath) continue; if(DevPathGetNodeCount(devicePath) != nodeCount) continue; EFI_DEVICE_PATH_PROTOCOL* pathA = referencePath; EFI_DEVICE_PATH_PROTOCOL* pathB = devicePath; BOOLEAN checkResult = TRUE; for(UINTN i = 0; i < nodeCount && !EfiIsDevicePathEnd(pathA) && !EfiIsDevicePathEnd(pathB); i ++) { if(EfiDevicePathNodeLength(pathA) != EfiDevicePathNodeLength(pathB)) { checkResult = FALSE; break; } #if 0 if(pathA->Type == MESSAGING_DEVICE_PATH && pathA->SubType == MSG_VENDOR_DP && !memcmp(pathA + 1, &EfiDevicePathMessagingSASGuid, sizeof(EFI_GUID))) { SAS_DEVICE_PATH* sasA = _CR(pathA, SAS_DEVICE_PATH, Header); SAS_DEVICE_PATH* sasB = _CR(pathB, SAS_DEVICE_PATH, Header); if(sasA->SasAddress != sasB->SasAddress || sasA->Lun != sasB->Lun || sasA->RelativeTargetPort != sasB->RelativeTargetPort) { checkResult = FALSE; break; } } #endif if(memcmp(pathA, pathB, EfiDevicePathNodeLength(pathA))) { checkResult = FALSE; break; } } if(!checkResult) continue; if(DevPathGetPartitionNumber(devicePath) != number) continue; retValue = theHandle; break; } MmFreePool(handleArray); return retValue; }
int main(void) { //CTIMER_DECLARE(); #if 0 uint32_t memory = SRAM1_LOC; uint32_t lut = SRAM1_LOC; //while(1); memset((void *)QQ_LOC, 0x01, 0x3000); g_qqueue->writeIndex = 0; g_qqueue->produced = 0; g_qqueue->consumed = 0; while(1) getRLSFrame(&memory, &lut); #endif #if 0 int i = 0x12345678; foo(&i); printf("%d\n", i); while(1); #endif #if 0 int i; uint32_t lut = SRAM1_LOC; uint32_t memory = SRAM1_LOC+0x1000; uint8_t *plut = (uint8_t *)lut; for (i=0; i<0x4000; i++) plut[i] = i%5==0 ? 1 : 0; while(1) getRLSFrame(&memory, &lut); #endif #if 1 _DBG("M0 start\n"); chirpOpen(); exec_init(); frame_init(); rls_init(); #if 0 while(1) { if (g_foo) loop0(); } #endif #if 0 vsync(); #endif #if 0 //while(g_loop); uint8_t type = CAM_GRAB_M1R2; uint32_t memory = SRAM1_LOC; uint16_t offset = 0; uint16_t width = 320; uint16_t height = 200; while(1) { getFrame(&type, &memory, &offset, &offset, &width, &height); i++; if (i%50==0) { _DBD32(i), _CR(); } } #endif //printf("M0 ready\n"); exec_loop(); #endif #if 0 while(1) { CTIMER_START(); syncM1((uint32_t *)&LPC_GPIO_PORT->PIN[1], 0x2000); CTIMER_STOP(); printf("%d\n", CTIMER_GET()); } #endif #if 0 { uint32_t i; uint8_t *lut = (uint8_t *)SRAM1_LOC + 0x10000; uint32_t memory = SRAM1_LOC; uint32_t size = SRAM1_SIZE/2; for (i=0; i<0x10000; i++) lut[i] = 0; lut[0xb400] = 0; lut[0xb401] = 1; lut[0xb402] = 1; lut[0xb403] = 1; lut[0xb404] = 0; lut[0xb405] = 1; lut[0xb406] = 1; lut[0xb407] = 0; lut[0xb408] = 0; lut[0xb409] = 0; while(1) getRLSFrame(&memory, &size); //, (uint32_t *)&lut); } #endif return 0; }
/** * Get file information * * @v This File handle * @v Type Type of information * @v Len Buffer size * @v Data Buffer * @ret Status EFI status code */ static EFI_STATUS EFIAPI FileGetInfo(EFI_FILE_HANDLE This, EFI_GUID *Type, UINTN *Len, VOID *Data) { EFI_STATUS Status; EFI_GRUB_FILE *File = _CR(This, EFI_GRUB_FILE, EfiFile); EFI_FILE_SYSTEM_INFO *FSInfo = (EFI_FILE_SYSTEM_INFO *) Data; EFI_FILE_INFO *Info = (EFI_FILE_INFO *) Data; CHAR16 GuidString[36]; EFI_TIME Time; CHAR8* label; PrintInfo(L"GetInfo(%llx|'%s', %d) %s\n", (UINT64) This, FileName(File), *Len, File->IsDir?L"<DIR>":L""); /* Determine information to return */ if (CompareMem(Type, &GenericFileInfo, sizeof(*Type)) == 0) { /* Fill file information */ PrintExtra(L"Get regular file information\n"); if (*Len < MINIMUM_INFO_LENGTH) { *Len = MINIMUM_INFO_LENGTH; return EFI_BUFFER_TOO_SMALL; } ZeroMem(Data, sizeof(EFI_FILE_INFO)); Info->Attribute = EFI_FILE_READ_ONLY; GrubTimeToEfiTime(File->Mtime, &Time); CopyMem(&Info->CreateTime, &Time, sizeof(Time)); CopyMem(&Info->LastAccessTime, &Time, sizeof(Time)); CopyMem(&Info->ModificationTime, &Time, sizeof(Time)); if (File->IsDir) { Info->Attribute |= EFI_FILE_DIRECTORY; } else { Info->FileSize = GrubGetFileSize(File); Info->PhysicalSize = GrubGetFileSize(File); } Status = Utf8ToUtf16NoAlloc(File->basename, Info->FileName, (INTN)(Info->Size - sizeof(EFI_FILE_INFO))); if (EFI_ERROR(Status)) { if (Status != EFI_BUFFER_TOO_SMALL) PrintStatusError(Status, L"Could not convert basename to UTF-8"); return Status; } /* The Info struct size already accounts for the extra NUL */ Info->Size = sizeof(EFI_FILE_INFO) + StrLen(Info->FileName) * sizeof(CHAR16); return EFI_SUCCESS; } else if (CompareMem(Type, &FileSystemInfo, sizeof(*Type)) == 0) { /* Get file system information */ PrintExtra(L"Get file system information\n"); if (*Len < MINIMUM_FS_INFO_LENGTH) { *Len = MINIMUM_FS_INFO_LENGTH; return EFI_BUFFER_TOO_SMALL; } ZeroMem(Data, sizeof(EFI_FILE_INFO)); FSInfo->Size = *Len; FSInfo->ReadOnly = 1; /* NB: This should really be cluster size, but we don't have access to that */ FSInfo->BlockSize = File->FileSystem->BlockIo->Media->BlockSize; if (FSInfo->BlockSize == 0) { PrintWarning(L"Corrected Media BlockSize\n"); FSInfo->BlockSize = 512; } FSInfo->VolumeSize = (File->FileSystem->BlockIo->Media->LastBlock + 1) * FSInfo->BlockSize; /* No idea if we can easily get this for GRUB, and the device is RO anyway */ FSInfo->FreeSpace = 0; Status = GrubLabel(File, &label); if (EFI_ERROR(Status)) { PrintStatusError(Status, L"Could not read disk label"); } else { Status = Utf8ToUtf16NoAlloc(label, FSInfo->VolumeLabel, (INTN)(FSInfo->Size - sizeof(EFI_FILE_SYSTEM_INFO))); if (EFI_ERROR(Status)) { if (Status != EFI_BUFFER_TOO_SMALL) PrintStatusError(Status, L"Could not convert label to UTF-8"); return Status; } Info->Size = sizeof(EFI_FILE_SYSTEM_INFO) + StrLen(FSInfo->VolumeLabel) * sizeof(CHAR16); } return EFI_SUCCESS; } else { GuidToString(GuidString, Type); PrintError(L"'%s': Cannot get information of type %s\n", FileName(File), GuidString); return EFI_UNSUPPORTED; } }
// // 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; }