diff --git a/src/gpt.js b/src/gpt.js index 959bd69..d93ad9c 100644 --- a/src/gpt.js +++ b/src/gpt.js @@ -274,8 +274,17 @@ export class GPT { if (partEntry.type === TYPE_EFI_UNUSED) continue; const partSlot = partEntry.name.slice(-2); if (partSlot !== "_a" && partSlot !== "_b") continue; - const bootable = partEntry.name === `boot${partSlot}`; - partEntry.attributes = updateABFlags(partEntry.attributes, partSlot === `_${slot}`, bootable, !bootable); + const isTargetSlot = partSlot === `_${slot}`; + const isBootPartition = partEntry.name === `boot${partSlot}`; + // Active slot: bootable, successful, not unbootable, 7 tries + // Inactive slot: not active, not successful, unbootable, 0 tries + partEntry.attributes = updateABFlags( + partEntry.attributes, + isTargetSlot, // active + isTargetSlot && isBootPartition, // successful (only boot partition) + !isTargetSlot, // unbootable (only inactive slot) + isTargetSlot && isBootPartition ? 7 : 0 // tries remaining + ); } } } @@ -307,7 +316,7 @@ function parseABFlags(attributes) { function updateABFlags(attributes, active, successful, unbootable, triesRemaining = 0) { let ret = attributes; - ret &= ~(AB_PARTITION_ATTR_SLOT_ACTIVE | AB_PARTITION_ATTR_BOOT_SUCCESSFUL | AB_PARTITION_ATTR_UNBOOTABLE | AB_PARTITION_ATTR_TRIES_MASK) << AB_FLAG_OFFSET; + ret &= ~((AB_PARTITION_ATTR_SLOT_ACTIVE | AB_PARTITION_ATTR_BOOT_SUCCESSFUL | AB_PARTITION_ATTR_UNBOOTABLE | AB_PARTITION_ATTR_TRIES_MASK) << AB_FLAG_OFFSET); if (active) ret |= AB_PARTITION_ATTR_SLOT_ACTIVE << AB_FLAG_OFFSET; if (successful) ret |= AB_PARTITION_ATTR_BOOT_SUCCESSFUL << AB_FLAG_OFFSET; diff --git a/src/qdl.js b/src/qdl.js index d432760..5065c0f 100644 --- a/src/qdl.js +++ b/src/qdl.js @@ -220,7 +220,7 @@ export class qdlDevice { const chunkSectors = Math.min(Number(range.end - sector + 1n), maxSectors); const result = await this.firehose.cmdErase(lun, sector, chunkSectors); if (!result) { - logger.error(`Failed to erase sectors chunk ${sectors}-${sectors + BigInt(chunkSectors - 1)}`); + logger.error(`Failed to erase sectors chunk ${sector}-${sector + BigInt(chunkSectors - 1)}`); return false; } sector = sector + BigInt(chunkSectors); @@ -298,7 +298,9 @@ export class qdlDevice { const [found, lun, partition] = await this.detectPartition(name); if (!found) throw new Error(`Partition ${name} not found`); logger.info(`Erasing ${name}...`); - await this.firehose.cmdErase(lun, partition.start, partition.sectors); + if (!await this.firehose.cmdErase(lun, partition.start, partition.sectors)) { + throw new Error(`Failed to erase ${name}`); + } logger.debug(`Erased ${name} ${partition.start}-${partition.end} (${partition.sectors} sectors)`); return true; } @@ -360,18 +362,26 @@ export class qdlDevice { primaryGpt.setActiveSlot(slot); const primaryPartEntries = primaryGpt.buildPartEntries(); - await this.firehose.cmdProgram(lun, primaryGpt.partEntriesStartLba, new Blob([primaryPartEntries])); + if (!await this.firehose.cmdProgram(lun, primaryGpt.partEntriesStartLba, new Blob([primaryPartEntries]))) { + throw new Error(`Failed to write primary partition entries for LUN ${lun}`); + } const primaryHeader = primaryGpt.buildHeader(primaryPartEntries); - await this.firehose.cmdProgram(lun, primaryGpt.currentLba, new Blob([primaryHeader])); + if (!await this.firehose.cmdProgram(lun, primaryGpt.currentLba, new Blob([primaryHeader]))) { + throw new Error(`Failed to write primary GPT header for LUN ${lun}`); + } // Update backup GPT const backupGpt = await this.getGpt(lun, primaryGpt.alternateLba); backupGpt.setActiveSlot(slot); const backupPartEntries = backupGpt.buildPartEntries(); - await this.firehose.cmdProgram(lun, backupGpt.partEntriesStartLba, new Blob([backupPartEntries])); + if (!await this.firehose.cmdProgram(lun, backupGpt.partEntriesStartLba, new Blob([backupPartEntries]))) { + throw new Error(`Failed to write backup partition entries for LUN ${lun}`); + } const backupHeader = backupGpt.buildHeader(backupPartEntries); - await this.firehose.cmdProgram(lun, backupGpt.currentLba, new Blob([backupHeader])); + if (!await this.firehose.cmdProgram(lun, backupGpt.currentLba, new Blob([backupHeader]))) { + throw new Error(`Failed to write backup GPT header for LUN ${lun}`); + } } const activeBootLunId = (slot === "a") ? 1 : 2; @@ -380,6 +390,16 @@ export class qdlDevice { return true; } + /** + * Set the bootable storage drive LUN (1 for slot A, 2 for slot B) + * @param {number} lun + * @returns {Promise} + */ + async setBootableLun(lun) { + await this.firehose.cmdSetBootLunId(lun); + logger.info(`Successfully set bootable LUN to ${lun}`); + } + async reset() { await this.firehose.cmdReset(); return true;