protected override void SetupEndlessLaunch(string description, string path) { LogHelper.Log("EFIFirmwareService:SetupEndlessLaunch:"); ObtainPrivileges(SE_SYSTEM_ENVIRONMENT_NAME); ObtainPrivileges(SE_SHUTDOWN_NAME); ESPPartitionInfo partitionInfo = FindESPPartition(); if (partitionInfo == null) { throw new FirmwareSetupException(FirmwareSetupErrorCode.EspPartitionNotFoundError, "Could not Found USB ESP volume"); } LogHelper.Log("EFIFirmwareService:SetupEndlessLaunch: ESP partition found:{0}", partitionInfo); //We assume there is at least the Windows UEFI entry entries = GetGPTUefiEntries(); if (entries == null || entries.Count == 0) { throw new FirmwareSetupException(FirmwareSetupErrorCode.NoExistingUefiEntriesError, "Found 0 UEFI entries"); } PrintUefiEntries(); UefiGPTEntry entry = CreateUefiEntry(partitionInfo, description, path); if (entry == null) { throw new FirmwareSetupException(FirmwareSetupErrorCode.CreateNewUefiEntryError, "Create new Uefi entry failed"); } if (!entries.Contains(entry)) { entries.Add(entry); } PrintUefiEntries(); bool inBootOrder = AddToBootOrder(entry); LogHelper.Log("EFIFirmwareService:SetupEndlessLaunch: In Boot order: {0}", inBootOrder); if (!inBootOrder) { throw new FirmwareSetupException(FirmwareSetupErrorCode.AddToBootOrderError, "Add new entry to BootOrder failed"); } else { if (!SetBootNext(entry)) { throw new FirmwareSetupException(FirmwareSetupErrorCode.SetBootNextError, "Set BootNext failed"); } } }
private bool SetBootNext(UefiGPTEntry entry) { LogHelper.Log("EFIFirmwareService:SetBootNext: Boot{0}", entry.number.ToString("X4")); byte[] bootNextBytes = BitConverter.GetBytes(entry.number); if (!SetFirmwareEnvironmentVariable("BootNext", EFI_GLOBAL_VARIABLE, bootNextBytes, (uint)bootNextBytes.Length)) { LogHelper.Log("EFIFirmwareService:SetBootNext: Error: {0}", Marshal.GetLastWin32Error()); } else { LogHelper.Log("EFIFirmwareService:SetBootNext: Success"); return(true); } return(false); }
private bool AddToBootOrder(UefiGPTEntry entry) { LogHelper.Log("EFIFirmwareService:AddToBootOrder: Boot{0}", entry.number.ToString("X4")); UInt16[] bootOrder = GetBootOrder(); LogHelper.Log("EFIFirmwareService:AddToBootOrder: Current BootOrder:"); PrintBootOrder(bootOrder); foreach (UInt16 bootNumber in bootOrder) { if (entry.number == bootNumber) { LogHelper.Log("EFIFirmwareService:AddToBootOrder: Already in BootOrder"); return(true); } } byte[] newBootOrderBytes = new byte[(bootOrder.Length + 1) * sizeof(UInt16)]; //Copy existing order bytes for (int i = 0; i < bootOrder.Length; i++) { Array.Copy(BitConverter.GetBytes(bootOrder[i]), 0, newBootOrderBytes, i * sizeof(UInt16), sizeof(UInt16)); } Array.Copy(BitConverter.GetBytes(entry.number), 0, newBootOrderBytes, bootOrder.Length * sizeof(UInt16), sizeof(UInt16)); bool success = SetFirmwareEnvironmentVariable("BootOrder", UEFI_BOOT_NAMESPACE, newBootOrderBytes, (uint)newBootOrderBytes.Length); if (!success) { LogHelper.Log("EFIFirmwareService:AddToBootOrder Failed: Error: {0}", Marshal.GetLastWin32Error()); } LogHelper.Log("EFIFirmwareService:AddToBootOrder: New BootOrder: "); PrintBootOrder(GetBootOrder()); return(success); }
private List <UefiGPTEntry> GetGPTUefiEntries() { List <UefiGPTEntry> entries = new List <UefiGPTEntry>(); int countEmpty = 0; for (int i = 0; i <= 0xffff && countEmpty <= 5; i++) { byte[] vardata = new byte[10000]; int signature_type = -1; uint size = GetFirmwareEnvironmentVariable(string.Format(LOAD_OPTION_FORMAT, i), EFI_GLOBAL_VARIABLE, vardata, (uint)vardata.Length); if (size > 0) { UefiGPTEntry entry = new UefiGPTEntry(); entry.number = (UInt16)i; entry.description = new string(Encoding.Unicode.GetString(vardata, 6, (int)size).TakeWhile(x => x != 0).ToArray()); var descBytes = Encoding.Unicode.GetBytes(entry.description); //Device type int devPathTypeStart = 6 + entry.description.Length * 2 + 2; int iteration = 0; while (devPathTypeStart + HARD_DRIVE_DISKPATH_SIZE < (int)size) { iteration++; byte devPathType = vardata[devPathTypeStart]; //Device subtype int devPathSubTypeStart = devPathTypeStart + 1; byte devPathSubType = vardata[devPathSubTypeStart]; switch (devPathType) { case 0x4: //Device type switch switch (devPathSubType) //Device subtype switch { case 0x1: int signature_type_index = devPathTypeStart + SIGNATURE_TYPE_OFFSET; signature_type = vardata[signature_type_index]; switch (signature_type) //Device signature type { case 0x1: //MBR We're interested only in GPT entries, as our Drive use a GPT partition table break; case 0x2: //GPT We're interested only in GPT entries, as our Drive use a GPT partition table int partNumOffset = devPathTypeStart + PARTITION_NUMBER_OFFSET; entry.partitionNumber = (int)BitConverter.ToUInt32(vardata, partNumOffset); int signatureOffet = devPathTypeStart + SIGNATURE_OFFSET; entry.guid = new Guid(vardata.Skip(signatureOffet).Take(16).ToArray()); break; } break; case 0x4: { var filepath = new string(Encoding.Unicode.GetString(vardata, devPathTypeStart + 4, (int)size).TakeWhile(x => x != 0).ToArray()); entry.path = filepath; } break; } break; case 0x7f: // End of device path break; } devPathTypeStart = devPathTypeStart + HARD_DRIVE_DISKPATH_SIZE; } entries.Add(entry); countEmpty = 0; } else { countEmpty++; } } return(entries); }
private UefiGPTEntry CreateUefiEntry(ESPPartitionInfo espPartitionInfo, string description, string path) { LogHelper.Log("EFIFirmwareService:CreateUefiEntry:Description: {0}", description); LogHelper.Log("EFIFirmwareService:CreateUefiEntry:Path: {0}", path); foreach (UefiGPTEntry entry in entries) { if (entry.guid.Equals(espPartitionInfo.partitionId)) { LogHelper.Log("EFIFirmwareService:CreateUefiEntry:Entry for {0} already exists. Return the existing entry", espPartitionInfo.partitionId); return(entry); } } EFI_HARD_DRIVE_PATH hdPath = new EFI_HARD_DRIVE_PATH(); LogHelper.Log("EFIFirmwareService:CreateUefiEntry: Partition startingOffset: {0}", espPartitionInfo.startingOffset / espPartitionInfo.blockSize); LogHelper.Log("EFIFirmwareService:CreateUefiEntry: PartitionLength: {0}", espPartitionInfo.partitionLength / espPartitionInfo.blockSize); //EFI_HARD_DRIVE_PATH hdPath.type = 0x4; hdPath.subtype = 0x1; hdPath.signature = new byte[16]; hdPath.length = (ushort)Marshal.SizeOf(hdPath); hdPath.part_num = (UInt32)espPartitionInfo.partitionNumber; hdPath.start = (UInt64)(espPartitionInfo.startingOffset / espPartitionInfo.blockSize); hdPath.size = (UInt64)(espPartitionInfo.partitionLength / espPartitionInfo.blockSize); hdPath.signature = espPartitionInfo.partitionId.ToByteArray(); hdPath.mbr_type = 2; /* GPT */ hdPath.signature_type = 2; /* GPT partition UUID */ //EFI_END_DEVICE_PATH EFI_END_DEVICE_PATH endPath = new EFI_END_DEVICE_PATH(); endPath.type = 0x7f; /* Descriptor end */ endPath.subtype = 0xff; /* Full path end */ endPath.length = 4; // EFI_FILE_PATH EFI_FILE_PATH filePath = new EFI_FILE_PATH(); byte[] pathBytes = Encoding.Unicode.GetBytes(path); byte[] descBytes = Encoding.Unicode.GetBytes(description); filePath.length = (ushort)(Marshal.SizeOf(filePath) + pathBytes.Length + 2); filePath.type = 4; /* Media device */ filePath.subtype = 4; /* File path */ // EFI_LOAD_OPTION EFI_LOAD_OPTION loadOption = new EFI_LOAD_OPTION(); loadOption.attributes = 1; //Mark as active loadOption.file_path_list_length = (ushort)(hdPath.length + filePath.length + endPath.length); int totalSize = Marshal.SizeOf(loadOption) + hdPath.length + filePath.length + endPath.length + descBytes.Length + 2; byte[] entryBytes = new byte[totalSize]; int offset = 0; //Copy EFI_LOAD_OPTION offset += CopyStructureToArray <EFI_LOAD_OPTION>(loadOption, offset, entryBytes); //Copy Description Array.Copy(descBytes, 0, entryBytes, offset, descBytes.Length); offset += descBytes.Length; offset += 2; //Copy EFI_HARD_DRIVE_PATH offset += CopyStructureToArray <EFI_HARD_DRIVE_PATH>(hdPath, offset, entryBytes); //Copy EFI_FILE_PATH without the actual path string /EFI/BOOT/<loader>.efi offset += CopyStructureToArray <EFI_FILE_PATH>(filePath, offset, entryBytes); //Copy path i.e: /EFI/BOOT/<loader>.efi Array.Copy(pathBytes, 0, entryBytes, offset, pathBytes.Length); offset += pathBytes.Length; offset += 2; //Copy EFI_END_DEVICE_PATH offset += CopyStructureToArray <EFI_END_DEVICE_PATH>(endPath, offset, entryBytes); int firstFreeEntry = GetFirstFreeUefiEntryNumber(); if (firstFreeEntry == -1) { LogHelper.Log("EFIFirmwareService:CreateUefiEntry: Could not find a free Uefi entry:"); throw new FirmwareSetupException(FirmwareSetupErrorCode.FindFreeUefiEntryError, "Could not find a free Uefi entry"); } bool success = SetFirmwareEnvironmentVariable("Boot" + firstFreeEntry.ToString("X4"), UEFI_BOOT_NAMESPACE, entryBytes, (uint)entryBytes.Length); UefiGPTEntry newEntry = null; if (success) { LogHelper.Log("EFIFirmwareService:CreateUefiEntry: Entry Created:"); newEntry = new UefiGPTEntry() { description = description, path = path, partitionNumber = (int)hdPath.part_num, guid = espPartitionInfo.partitionId, number = (ushort)firstFreeEntry }; } return(newEntry); }