From: William Vinnicombe <william.vinnicombe@raspberrypi.com>
Date: Sun, 16 Mar 2025 23:40:26 +0100
Subject: Fix UF2 creation on big-endian systems

Bug: https://github.com/raspberrypi/picotool/issues/104
---
 elf/elf_file.cpp | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

--- a/elf/elf_file.cpp
+++ b/elf/elf_file.cpp
@@ -210,14 +210,14 @@ void elf_file::flatten(void) {
 
     elf_bytes.resize(std::max(eh.ph_offset + sizeof(elf32_ph_entry) * eh.ph_num, elf_bytes.size()));
     auto ph_entries_out = ph_entries;
-    for (auto ph : ph_entries_out) {
+    for (auto &ph : ph_entries_out) {
         ph_le(ph);  // swap to LE for writing
     }
     memcpy(&elf_bytes[eh.ph_offset], &ph_entries_out[0], sizeof(elf32_ph_entry) * eh.ph_num);
 
     elf_bytes.resize(std::max(eh.sh_offset + sizeof(elf32_sh_entry) * eh.sh_num, elf_bytes.size()));
     auto sh_entries_out = sh_entries;
-    for (auto sh : sh_entries_out) {
+    for (auto &sh : sh_entries_out) {
         sh_le(sh);  // swap to LE for writing
     }
     memcpy(&elf_bytes[eh.sh_offset], &sh_entries_out[0], sizeof(elf32_sh_entry) * eh.sh_num);
@@ -245,7 +245,7 @@ void elf_file::read_sh(void) {
     if (eh.sh_num) {
         sh_entries.resize(eh.sh_num);
         read_bytes(eh.sh_offset, sizeof(elf32_sh_entry) * eh.sh_num, &sh_entries[0]);
-        for (auto sh : sh_entries) {
+        for (auto &sh : sh_entries) {
             sh_he(sh);  // swap to Host for processing
         }
     }
@@ -431,7 +431,7 @@ void elf_file::read_ph(void) {
     if (eh.ph_num) {
         ph_entries.resize(eh.ph_num);
         read_bytes(eh.ph_offset, sizeof(elf32_ph_entry) * eh.ph_num, &ph_entries[0]);
-        for (auto ph : ph_entries) {
+        for (auto &ph : ph_entries) {
             ph_he(ph);  // swap to Host for processing
         }
     }
--- a/elf2uf2/elf2uf2.cpp
+++ b/elf2uf2/elf2uf2.cpp
@@ -19,6 +19,8 @@
 #include "errors.h"
 #include "model.h"
 
+#include "portable_endian.h"
+
 #define FLASH_SECTOR_ERASE_SIZE 4096u
 
 static bool g_verbose;
@@ -144,6 +146,31 @@ uf2_block gen_abs_block(uint32_t abs_blo
     return block;
 }
 
+void uf2_he(uf2_block &block) {
+    // Swap to host endianness
+    block.magic_start0 = le32toh(block.magic_start0);
+    block.magic_start1 = le32toh(block.magic_start1);
+    block.flags        = le32toh(block.flags);
+    block.target_addr  = le32toh(block.target_addr);
+    block.payload_size = le32toh(block.payload_size);
+    block.block_no     = le32toh(block.block_no);
+    block.num_blocks   = le32toh(block.num_blocks);
+    block.file_size    = le32toh(block.file_size);
+    block.magic_end    = le32toh(block.magic_end);
+}
+void uf2_le(uf2_block &block) {
+    // Swap to little endianness
+    block.magic_start0 = htole32(block.magic_start0);
+    block.magic_start1 = htole32(block.magic_start1);
+    block.flags        = htole32(block.flags);
+    block.target_addr  = htole32(block.target_addr);
+    block.payload_size = htole32(block.payload_size);
+    block.block_no     = htole32(block.block_no);
+    block.num_blocks   = htole32(block.num_blocks);
+    block.file_size    = htole32(block.file_size);
+    block.magic_end    = htole32(block.magic_end);
+}
+
 bool check_abs_block(uf2_block block) {
     return std::all_of(block.data, block.data + UF2_PAGE_SIZE, [](uint8_t i) { return i == 0xef; }) &&
         block.magic_start0 == UF2_MAGIC_START0 &&
@@ -164,22 +191,23 @@ int pages2uf2(std::map<uint32_t, std::ve
         address_ranges flash_range = address_ranges_flash(model);
         if (is_address_initialized(flash_range, base_addr)) {
             uf2_block block = gen_abs_block(abs_block_loc);
+            uf2_le(block);
             out->write((char*)&block, sizeof(uf2_block));
             if (out->fail()) {
                 fail_write_error();
             }
         }
     }
-    uf2_block block;
     unsigned int page_num = 0;
-    block.magic_start0 = UF2_MAGIC_START0;
-    block.magic_start1 = UF2_MAGIC_START1;
-    block.flags = UF2_FLAG_FAMILY_ID_PRESENT;
-    block.payload_size = UF2_PAGE_SIZE;
-    block.num_blocks = (uint32_t)pages.size();
-    block.file_size = family_id;
-    block.magic_end = UF2_MAGIC_END;
     for(auto& page_entry : pages) {
+        uf2_block block;
+        block.magic_start0 = UF2_MAGIC_START0;
+        block.magic_start1 = UF2_MAGIC_START1;
+        block.flags = UF2_FLAG_FAMILY_ID_PRESENT;
+        block.payload_size = UF2_PAGE_SIZE;
+        block.num_blocks = (uint32_t)pages.size();
+        block.file_size = family_id;
+        block.magic_end = UF2_MAGIC_END;
         block.target_addr = page_entry.first;
         block.block_no = page_num++;
         if (g_verbose) {
@@ -189,6 +217,7 @@ int pages2uf2(std::map<uint32_t, std::ve
         memset(block.data, 0, sizeof(block.data));
         int rc = realize_page(in, page_entry.second, block.data, sizeof(block.data));
         if (rc) return rc;
+        uf2_le(block);
         out->write((char*)&block, sizeof(uf2_block));
         if (out->fail()) {
             fail_write_error();
--- a/main.cpp
+++ b/main.cpp
@@ -2430,6 +2430,7 @@ private:
 
 static void read_and_check_elf32_header(std::shared_ptr<std::iostream>in, elf32_header& eh_out) {
     in->read((char*)&eh_out, sizeof(eh_out));
+    eh_he(eh_out);
     if (in->fail()) {
         fail(ERROR_FORMAT, "'" + settings.filenames[0] +"' is not an ELF file");
     }
@@ -2949,6 +2950,9 @@ void build_rmap_elf(std::shared_ptr<std:
         if (file->fail()) {
             fail_read_error();
         }
+        for (auto &ph : entries) {
+            ph_he(ph);  // swap to Host for processing
+        }
         for (unsigned int i = 0; i < eh.ph_num; i++) {
              elf32_ph_entry &entry = entries[i];
              if (entry.type == PT_LOAD && entry.memsz) {
@@ -2972,6 +2976,7 @@ uint32_t build_rmap_uf2(std::shared_ptr<
     uint32_t next_family_id = 0;
     do {
         file->read((char*)&block, sizeof(uf2_block));
+        uf2_he(block);
         if (file->fail()) {
             if (file->eof()) { file->clear(); break; }
             fail(ERROR_READ_FAILED, "unexpected end of input file");
@@ -4146,6 +4151,7 @@ uint32_t get_family_id(uint8_t file_idx)
         auto file = get_file_idx(ios::in|ios::binary, file_idx);
         uf2_block block;
         file->read((char*)&block, sizeof(block));
+        uf2_he(block);
         #if SUPPORT_RP2350_A2
         // ignore the absolute block
         if (check_abs_block(block)) {
@@ -4588,6 +4594,7 @@ bool save_command::execute(device_map &d
                 assert(size <= PAGE_SIZE);
                 memcpy(block.data, buffer, size);
                 if (size < PAGE_SIZE) memset(block.data + size, 0, PAGE_SIZE - size);
+                uf2_le(block);
                 if (1 != fwrite(&block, sizeof(block), 1, out)) {
                     fail_write_error();
                 }
--- a/elf2uf2/elf2uf2.h
+++ b/elf2uf2/elf2uf2.h
@@ -20,6 +20,9 @@
 #define LOG2_PAGE_SIZE 8u
 #define UF2_PAGE_SIZE (1u << LOG2_PAGE_SIZE)
 
+void uf2_he(uf2_block &block);
+void uf2_le(uf2_block &block);
+
 
 bool check_abs_block(uf2_block block);
 int bin2uf2(std::shared_ptr<std::iostream> in, std::shared_ptr<std::iostream> out, uint32_t address, uint32_t family_id, model_t model, uint32_t abs_block_loc=0, bool verbose=false);
--- a/elf/elf_file.h
+++ b/elf/elf_file.h
@@ -73,4 +73,7 @@ private:
 };
 int rp_check_elf_header(const elf32_header &eh);
 int rp_determine_binary_type(const elf32_header &eh, const std::vector<elf32_ph_entry>& entries, address_ranges flash_range, address_ranges ram_range, bool *ram_style);
-#endif
\ No newline at end of file
+
+void eh_he(elf32_header &eh);
+void ph_he(elf32_ph_entry &ph);
+#endif
