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 * DuplicateDevicePath ( IN EFI_DEVICE_PATH *DevPath ) { EFI_DEVICE_PATH *NewDevPath; UINTN Size; // // Check parameter // if( DevPath == NULL ) { return (EFI_DEVICE_PATH *) NULL; } // // Compute the size // Size = DevicePathSize (DevPath); // // Make a copy // NewDevPath = (EFI_DEVICE_PATH *) AllocatePool (Size); if (NewDevPath) { BS->CopyMem (NewDevPath, DevPath, Size); } return NewDevPath; }
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; }
static EFI_STATUS try_start_first_option(EFI_HANDLE parent_image_handle) { EFI_STATUS rc; EFI_HANDLE image_handle; if (!first_new_option) { return EFI_SUCCESS; } rc = uefi_call_wrapper(BS->LoadImage, 6, 0, parent_image_handle, first_new_option, NULL, 0, &image_handle); if (EFI_ERROR(rc)) { CHAR16 *dps = DevicePathToStr(first_new_option); UINTN s = DevicePathSize(first_new_option); unsigned int i; UINT8 *dpv = (void *)first_new_option; Print(L"LoadImage failed: %d\nDevice path: \"%s\"\n", rc, dps); for (i = 0; i < s; i++) { if (i > 0 && i % 16 == 0) Print(L"\n"); Print(L"%02x ", dpv[i]); } Print(L"\n"); uefi_call_wrapper(BS->Stall, 1, 500000000); return rc; } EFI_LOADED_IMAGE *image; rc = uefi_call_wrapper(BS->HandleProtocol, 3, image_handle, &LoadedImageProtocol, (void *)&image); if (!EFI_ERROR(rc)) { image->LoadOptions = first_new_option_args; image->LoadOptionsSize = first_new_option_size; } rc = uefi_call_wrapper(BS->StartImage, 3, image_handle, NULL, NULL); if (EFI_ERROR(rc)) { Print(L"StartImage failed: %d\n", rc); uefi_call_wrapper(BS->Stall, 1, 500000000); } return rc; }
EFI_DEVICE_PATH_PROTOCOL * DuplicateDevicePath ( IN EFI_DEVICE_PATH_PROTOCOL *DevPath ) /*++ Routine Description: Function creates a duplicate copy of an existing device path. Arguments: DevPath - A pointer to a device path data structure Returns: If the memory is successfully allocated, then the contents of DevPath are copied to the newly allocated buffer, and a pointer to that buffer is returned. Otherwise, NULL is returned. --*/ { EFI_DEVICE_PATH_PROTOCOL *NewDevPath; UINTN Size; // // Compute the size // Size = DevicePathSize (DevPath); // // Make a copy // NewDevPath = AllocatePool (Size); if (NewDevPath) { CopyMem (NewDevPath, DevPath, Size); } return NewDevPath; }
EFI_STATUS add_to_boot_list(EFI_FILE_HANDLE fh, CHAR16 *dirname, CHAR16 *filename, CHAR16 *label, CHAR16 *arguments) { CHAR16 *fullpath = NULL; UINT64 pathlen = 0; EFI_STATUS rc = EFI_SUCCESS; rc = make_full_path(dirname, filename, &fullpath, &pathlen); if (EFI_ERROR(rc)) return rc; EFI_DEVICE_PATH *dph = NULL; EFI_DEVICE_PATH *file = NULL; EFI_DEVICE_PATH *full_device_path = NULL; EFI_DEVICE_PATH *dp = NULL; dph = DevicePathFromHandle(this_image->DeviceHandle); if (!dph) { rc = EFI_OUT_OF_RESOURCES; goto err; } file = FileDevicePath(fh, fullpath); if (!file) { rc = EFI_OUT_OF_RESOURCES; goto err; } full_device_path = AppendDevicePath(dph, file); if (!full_device_path) { rc = EFI_OUT_OF_RESOURCES; goto err; } rc = FindSubDevicePath(full_device_path, MEDIA_DEVICE_PATH, MEDIA_HARDDRIVE_DP, &dp); if (EFI_ERROR(rc)) { if (rc == EFI_NOT_FOUND) { dp = full_device_path; } else { rc = EFI_OUT_OF_RESOURCES; goto err; } } #ifdef DEBUG_FALLBACK { UINTN s = DevicePathSize(dp); UINTN i; UINT8 *dpv = (void *)dp; for (i = 0; i < s; i++) { if (i > 0 && i % 16 == 0) Print(L"\n"); Print(L"%02x ", dpv[i]); } Print(L"\n"); CHAR16 *dps = DevicePathToStr(dp); Print(L"device path: \"%s\"\n", dps); } #endif UINT16 option; rc = find_boot_option(dp, full_device_path, fullpath, label, arguments, &option); if (EFI_ERROR(rc)) { add_boot_option(dp, full_device_path, fullpath, label, arguments); } else if (option != 0) { CHAR16 *newbootorder; newbootorder = AllocateZeroPool(sizeof (CHAR16) * nbootorder); if (!newbootorder) return EFI_OUT_OF_RESOURCES; newbootorder[0] = bootorder[option]; CopyMem(newbootorder + 1, bootorder, sizeof (CHAR16) * option); CopyMem(newbootorder + option + 1, bootorder + option + 1, sizeof (CHAR16) * (nbootorder - option - 1)); FreePool(bootorder); bootorder = newbootorder; } err: if (file) FreePool(file); if (full_device_path) FreePool(full_device_path); if (dp) FreePool(dp); if (fullpath) FreePool(fullpath); return rc; }
EFI_STATUS find_boot_option(EFI_DEVICE_PATH *dp, EFI_DEVICE_PATH *fulldp, CHAR16 *filename, CHAR16 *label, CHAR16 *arguments, UINT16 *optnum) { unsigned int size = sizeof(UINT32) + sizeof (UINT16) + StrLen(label)*2 + 2 + DevicePathSize(dp) + StrLen(arguments) * 2; CHAR8 *data = AllocateZeroPool(size + 2); if (!data) return EFI_OUT_OF_RESOURCES; CHAR8 *cursor = data; *(UINT32 *)cursor = LOAD_OPTION_ACTIVE; cursor += sizeof (UINT32); *(UINT16 *)cursor = DevicePathSize(dp); cursor += sizeof (UINT16); StrCpy((CHAR16 *)cursor, label); cursor += StrLen(label)*2 + 2; CopyMem(cursor, dp, DevicePathSize(dp)); cursor += DevicePathSize(dp); StrCpy((CHAR16 *)cursor, arguments); int i = 0; CHAR16 varname[] = L"Boot0000"; CHAR16 hexmap[] = L"0123456789ABCDEF"; EFI_GUID global = EFI_GLOBAL_VARIABLE; EFI_STATUS rc; CHAR8 *candidate = AllocateZeroPool(size); if (!candidate) { FreePool(data); return EFI_OUT_OF_RESOURCES; } for(i = 0; i < nbootorder && i < 0x10000; i++) { varname[4] = hexmap[(bootorder[i] & 0xf000) >> 12]; varname[5] = hexmap[(bootorder[i] & 0x0f00) >> 8]; varname[6] = hexmap[(bootorder[i] & 0x00f0) >> 4]; varname[7] = hexmap[(bootorder[i] & 0x000f) >> 0]; UINTN candidate_size = size; rc = uefi_call_wrapper(RT->GetVariable, 5, varname, &global, NULL, &candidate_size, candidate); if (EFI_ERROR(rc)) continue; if (candidate_size != size) continue; if (CompareMem(candidate, data, size)) continue; /* at this point, we have duplicate data. */ if (!first_new_option) { first_new_option = DuplicateDevicePath(fulldp); first_new_option_args = arguments; first_new_option_size = StrLen(arguments) * sizeof (CHAR16); } *optnum = i; FreePool(candidate); FreePool(data); return EFI_SUCCESS; } FreePool(candidate); FreePool(data); return EFI_NOT_FOUND; }
EFI_STATUS add_boot_option(EFI_DEVICE_PATH *hddp, EFI_DEVICE_PATH *fulldp, CHAR16 *filename, CHAR16 *label, CHAR16 *arguments) { static int i = 0; CHAR16 varname[] = L"Boot0000"; CHAR16 hexmap[] = L"0123456789ABCDEF"; EFI_GUID global = EFI_GLOBAL_VARIABLE; EFI_STATUS rc; for(; i <= 0xffff; i++) { varname[4] = hexmap[(i & 0xf000) >> 12]; varname[5] = hexmap[(i & 0x0f00) >> 8]; varname[6] = hexmap[(i & 0x00f0) >> 4]; varname[7] = hexmap[(i & 0x000f) >> 0]; void *var = LibGetVariable(varname, &global); if (!var) { int size = sizeof(UINT32) + sizeof (UINT16) + StrLen(label)*2 + 2 + DevicePathSize(hddp) + StrLen(arguments) * 2; CHAR8 *data = AllocateZeroPool(size + 2); CHAR8 *cursor = data; *(UINT32 *)cursor = LOAD_OPTION_ACTIVE; cursor += sizeof (UINT32); *(UINT16 *)cursor = DevicePathSize(hddp); cursor += sizeof (UINT16); StrCpy((CHAR16 *)cursor, label); cursor += StrLen(label)*2 + 2; CopyMem(cursor, hddp, DevicePathSize(hddp)); cursor += DevicePathSize(hddp); StrCpy((CHAR16 *)cursor, arguments); Print(L"Creating boot entry \"%s\" with label \"%s\" " L"for file \"%s\"\n", varname, label, filename); if (!first_new_option) { first_new_option = DuplicateDevicePath(fulldp); first_new_option_args = arguments; first_new_option_size = StrLen(arguments) * sizeof (CHAR16); } rc = uefi_call_wrapper(RT->SetVariable, 5, varname, &global, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, size, data); FreePool(data); if (EFI_ERROR(rc)) { Print(L"Could not create variable: %d\n", rc); return rc; } CHAR16 *newbootorder = AllocateZeroPool(sizeof (CHAR16) * (nbootorder + 1)); if (!newbootorder) return EFI_OUT_OF_RESOURCES; int j = 0; newbootorder[0] = i & 0xffff; if (nbootorder) { for (j = 0; j < nbootorder; j++) newbootorder[j+1] = bootorder[j]; FreePool(bootorder); } bootorder = newbootorder; nbootorder += 1; #ifdef DEBUG_FALLBACK Print(L"nbootorder: %d\nBootOrder: ", nbootorder); for (j = 0 ; j < nbootorder ; j++) Print(L"%04x ", bootorder[j]); Print(L"\n"); #endif return EFI_SUCCESS; } } return EFI_OUT_OF_RESOURCES; }
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 = (EFI_DEVICE_PATH *) AllocatePool (Size); if (Dst) { DstPos = (UINT8 *) Dst; // // Copy all device path instances // while (Inst = DevicePathInstance (&Src1, &Size)) { BS->CopyMem(DstPos, Inst, Size); DstPos += Size; BS->CopyMem(DstPos, Src2, Src2Size); DstPos += Src2Size; BS->CopyMem(DstPos, EndInstanceDevicePath, sizeof(EFI_DEVICE_PATH)); DstPos += sizeof(EFI_DEVICE_PATH); } // Change last end marker DstPos -= sizeof(EFI_DEVICE_PATH); BS->CopyMem(DstPos, EndDevicePath, sizeof(EFI_DEVICE_PATH)); } return Dst; }
EFI_STATUS add_to_boot_list(EFI_FILE_HANDLE fh, CHAR16 *dirname, CHAR16 *filename, CHAR16 *label, CHAR16 *arguments) { CHAR16 *fullpath = NULL; UINT64 pathlen = 0; EFI_STATUS rc = EFI_SUCCESS; rc = make_full_path(dirname, filename, &fullpath, &pathlen); if (EFI_ERROR(rc)) return rc; EFI_DEVICE_PATH *dph = NULL, *dpf = NULL, *dp = NULL; dph = DevicePathFromHandle(this_image->DeviceHandle); if (!dph) { rc = EFI_OUT_OF_RESOURCES; goto err; } dpf = FileDevicePath(fh, fullpath); if (!dpf) { rc = EFI_OUT_OF_RESOURCES; goto err; } dp = AppendDevicePath(dph, dpf); if (!dp) { rc = EFI_OUT_OF_RESOURCES; goto err; } #ifdef DEBUG_FALLBACK UINTN s = DevicePathSize(dp); int i; UINT8 *dpv = (void *)dp; for (i = 0; i < s; i++) { if (i > 0 && i % 16 == 0) Print(L"\n"); Print(L"%02x ", dpv[i]); } Print(L"\n"); CHAR16 *dps = DevicePathToStr(dp); Print(L"device path: \"%s\"\n", dps); #endif if (!first_new_option) { CHAR16 *dps = DevicePathToStr(dp); Print(L"device path: \"%s\"\n", dps); first_new_option = DuplicateDevicePath(dp); first_new_option_args = arguments; first_new_option_size = StrLen(arguments) * sizeof (CHAR16); } add_boot_option(dp, fullpath, label, arguments); err: if (dpf) FreePool(dpf); if (dp) FreePool(dp); if (fullpath) FreePool(fullpath); return rc; }
EFI_DEVICE_PATH_PROTOCOL * AppendDevicePath ( IN EFI_DEVICE_PATH_PROTOCOL *Src1, IN EFI_DEVICE_PATH_PROTOCOL *Src2 ) /*++ Routine Description: Function is used to append a device path to all the instances in another device path. Arguments: Src1 - A pointer to a device path data structure. Src2 - A pointer to a device path data structure. Returns: A pointer to the new device path is returned. NULL is returned if space for the new device path could not be allocated from pool. It is up to the caller to free the memory used by Src1 and Src2 if they are no longer needed. 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_PROTOCOL *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; Size -= Src1Inst * sizeof(EFI_DEVICE_PATH_PROTOCOL); Dst = AllocatePool (Size); if (Dst) { DstPos = (UINT8 *) Dst; // // Copy all device path instances // Inst = DevicePathInstance (&Src1, &Size); while (Inst) { CopyMem(DstPos, Inst, Size); DstPos += Size - sizeof(EFI_DEVICE_PATH_PROTOCOL); CopyMem(DstPos, Src2, Src2Size); DstPos += Src2Size - sizeof(EFI_DEVICE_PATH_PROTOCOL); CopyMem(DstPos, EndInstanceDevicePath, sizeof(EFI_DEVICE_PATH_PROTOCOL)); DstPos += sizeof(EFI_DEVICE_PATH_PROTOCOL); Inst = DevicePathInstance (&Src1, &Size); } // // Change last end marker // DstPos -= sizeof(EFI_DEVICE_PATH_PROTOCOL); CopyMem(DstPos, EndDevicePath, sizeof(EFI_DEVICE_PATH_PROTOCOL)); } return Dst; }