Ignore other blocks when signing with rollback version (#237)

* Ignore first block when signing with rollback version

* Ignore all blocks (except partition tables), not just first block

* Rename ignore_others -> set_others_ignored
diff --git a/bintool/bintool.cpp b/bintool/bintool.cpp
index e75c0b0..5cf7318 100644
--- a/bintool/bintool.cpp
+++ b/bintool/bintool.cpp
@@ -192,6 +192,21 @@
 }
 
 
+void set_block_ignored(elf_file *elf, uint32_t block_addr) {
+    auto seg = elf->segment_from_physical_address(block_addr);
+    if (seg == nullptr) {
+        fail(ERROR_NOT_POSSIBLE, "The ELF file does not contain the block address %x", block_addr);
+    }
+    std::vector<uint8_t> content = elf->content(*seg);
+    uint32_t offset = block_addr + 4 - seg->physical_address();
+    if ((content[offset] & 0x7f) != PICOBIN_BLOCK_ITEM_PARTITION_TABLE) {
+        DEBUG_LOG("setting block at %08x to ignored\n", block_addr);
+        content[offset] = 0x7e;   
+    }
+    elf->content(*seg, content);
+}
+
+
 void set_next_block(elf_file *elf, std::unique_ptr<block> &first_block, uint32_t highest_address) {
     // todo this isn't right, but virtual should be physical for now
     auto seg = elf->segment_from_physical_address(first_block->physical_addr);
@@ -214,6 +229,15 @@
 }
 
 
+void set_block_ignored(std::vector<uint8_t> &bin, uint32_t storage_addr, uint32_t block_addr) {
+    uint32_t offset = block_addr + 4 - storage_addr;
+    if ((bin[offset] & 0x7f) != PICOBIN_BLOCK_ITEM_PARTITION_TABLE) {
+        DEBUG_LOG("setting block at %08x to ignored\n", block_addr);
+        bin[offset] = 0x7e;   
+    }
+}
+
+
 void set_next_block(std::vector<uint8_t> &bin, uint32_t storage_addr, std::unique_ptr<block> &first_block, uint32_t highest_address) {
     // todo this isn't right, but virtual should be physical for now
     uint32_t offset = first_block->physical_addr + first_block->next_block_rel_index * 4 - storage_addr;
@@ -230,7 +254,7 @@
 }
 
 
-block place_new_block(elf_file *elf, std::unique_ptr<block> &first_block) {
+block place_new_block(elf_file *elf, std::unique_ptr<block> &first_block, bool set_others_ignored) {
     uint32_t highest_ram_address = 0;
     uint32_t highest_flash_address = 0;
     bool no_flash = false;
@@ -265,8 +289,10 @@
         set_next_block(elf, first_block, highest_address);
         loop_start_rel = -first_block->next_block_rel;
         new_block_addr = first_block->physical_addr + first_block->next_block_rel;
+        if (set_others_ignored) set_block_ignored(elf, first_block->physical_addr);
     } else {
         DEBUG_LOG("There is already a block loop\n");
+        if (set_others_ignored) set_block_ignored(elf, first_block->physical_addr);
         uint32_t next_block_addr = first_block->physical_addr + first_block->next_block_rel;
         while (true) {
             auto segment = elf->segment_from_physical_address(next_block_addr);
@@ -300,6 +326,7 @@
                 break;
             } else {
                 DEBUG_LOG("Continue looping\n");
+                if (set_others_ignored) set_block_ignored(elf, new_first_block->physical_addr);
                 next_block_addr = new_first_block->physical_addr + new_first_block->next_block_rel;
                 new_first_block.reset();
             }
@@ -399,7 +426,7 @@
 }
 
 
-block place_new_block(std::vector<uint8_t> &bin, uint32_t storage_addr, std::unique_ptr<block> &first_block) {
+block place_new_block(std::vector<uint8_t> &bin, uint32_t storage_addr, std::unique_ptr<block> &first_block, bool set_others_ignored) {
     uint32_t highest_ram_address = 0;
     uint32_t highest_flash_address = 0;
     bool no_flash = false;
@@ -431,9 +458,14 @@
         set_next_block(bin, storage_addr, first_block, highest_address);
         loop_start_rel = -first_block->next_block_rel;
         new_block_addr = first_block->physical_addr + first_block->next_block_rel;
+        if (set_others_ignored) set_block_ignored(bin, storage_addr, first_block->physical_addr);
     } else {
         DEBUG_LOG("Ooh, there is already a block loop - lets find it's end\n");
-        new_first_block = get_last_block(bin, storage_addr, first_block);
+        auto all_blocks = get_all_blocks(bin, storage_addr, first_block);
+        for (auto &block : all_blocks) {
+            if (set_others_ignored) set_block_ignored(bin, storage_addr, block->physical_addr);
+        }
+        new_first_block = std::move(all_blocks.back());
         set_next_block(bin, storage_addr, new_first_block, highest_address);
         new_block_addr = new_first_block->physical_addr + new_first_block->next_block_rel;
         loop_start_rel = first_block->physical_addr - new_block_addr;
diff --git a/bintool/bintool.h b/bintool/bintool.h
index c4ddbec..20029ac 100644
--- a/bintool/bintool.h
+++ b/bintool/bintool.h
@@ -22,7 +22,7 @@
 
 // Elfs
 std::unique_ptr<block> find_first_block(elf_file *elf);
-block place_new_block(elf_file *elf, std::unique_ptr<block> &first_block);
+block place_new_block(elf_file *elf, std::unique_ptr<block> &first_block, bool set_others_ignored=false);
 #if HAS_MBEDTLS
     int hash_andor_sign(elf_file *elf, block *new_block, const public_t public_key, const private_t private_key, bool hash_value, bool sign, bool clear_sram = false);
     void encrypt_guts(elf_file *elf, block *new_block, const aes_key_t aes_key, std::vector<uint8_t> &iv_data, std::vector<uint8_t> &enc_data);
@@ -34,7 +34,7 @@
 std::unique_ptr<block> find_first_block(std::vector<uint8_t> bin, uint32_t storage_addr);
 std::unique_ptr<block> get_last_block(std::vector<uint8_t> &bin, uint32_t storage_addr, std::unique_ptr<block> &first_block, get_more_bin_cb more_cb = nullptr);
 std::vector<std::unique_ptr<block>> get_all_blocks(std::vector<uint8_t> &bin, uint32_t storage_addr, std::unique_ptr<block> &first_block, get_more_bin_cb more_cb = nullptr);
-block place_new_block(std::vector<uint8_t> &bin, uint32_t storage_addr, std::unique_ptr<block> &first_block);
+block place_new_block(std::vector<uint8_t> &bin, uint32_t storage_addr, std::unique_ptr<block> &first_block, bool set_others_ignored=false);
 uint32_t calc_checksum(std::vector<uint8_t> bin);
 #if HAS_MBEDTLS
     std::vector<uint8_t> hash_andor_sign(std::vector<uint8_t> bin, uint32_t storage_addr, uint32_t runtime_addr, block *new_block, const public_t public_key, const private_t private_key, bool hash_value, bool sign, bool clear_sram = false);
diff --git a/bintool/metadata.h b/bintool/metadata.h
index a01e048..76aed8b 100644
--- a/bintool/metadata.h
+++ b/bintool/metadata.h
@@ -208,7 +208,7 @@
             }
             if (name.size() > 0) {
                 char size = name.size();
-                assert(size & 0x7f == size);
+                assert((size & 0x7f) == size);
                 std::vector<char> name_vec = {size};
                 for (char c : name) {
                     name_vec.push_back(c);
diff --git a/main.cpp b/main.cpp
index 44e7d91..61617fd 100644
--- a/main.cpp
+++ b/main.cpp
@@ -4914,7 +4914,8 @@
         }
     }
 
-    block new_block = place_new_block(elf, first_block);
+    // Workaround RP2350-E13, which means when using rollback versions, all other blocks must be set as ignored
+    block new_block = place_new_block(elf, first_block, settings.seal.rollback_version);
 
     if (settings.seal.set_tbyb) {
         // Set the TBYB bit on the image_type_item
@@ -5000,7 +5001,8 @@
         }
     }
 
-    block new_block = place_new_block(bin, bin_start, first_block);
+    // Workaround RP2350-E13, which means when using rollback versions, all other blocks must be set as ignored
+    block new_block = place_new_block(bin, bin_start, first_block, settings.seal.rollback_version);
 
     if (settings.seal.major_version || settings.seal.minor_version || settings.seal.rollback_version) {
         std::shared_ptr<version_item> version = new_block.get_item<version_item>();