From 9f328cab9536d73df697b325fab13dd7eb550522 Mon Sep 17 00:00:00 2001 From: Kevin O'Connor Date: Thu, 24 Oct 2024 19:49:33 -0400 Subject: lib: Move lib/rp2040/elf2uf2 to lib/elf2uf2 Recent versions of the rp2040 sdk no longer contain the elf2uf2 tool. So, move that code to a new dedicated directory. This is in preparation for updating the rp2040 sdk version. Signed-off-by: Kevin O'Connor --- lib/README | 5 + lib/elf2uf2/elf.h | 60 ++++++++ lib/elf2uf2/main.cpp | 350 ++++++++++++++++++++++++++++++++++++++++++++ lib/rp2040/elf2uf2/elf.h | 60 -------- lib/rp2040/elf2uf2/main.cpp | 350 -------------------------------------------- 5 files changed, 415 insertions(+), 410 deletions(-) create mode 100644 lib/elf2uf2/elf.h create mode 100644 lib/elf2uf2/main.cpp delete mode 100644 lib/rp2040/elf2uf2/elf.h delete mode 100644 lib/rp2040/elf2uf2/main.cpp (limited to 'lib') diff --git a/lib/README b/lib/README index 106b2cfc..4e44f2da 100644 --- a/lib/README +++ b/lib/README @@ -111,6 +111,11 @@ version 1.2.0 (bfcbefafc5d2a210551a4d9d80b4303d4ae0adf7). It has been modified so that it can build outside of the pico sdk. See rp2040.patch for the modifications. +The elf2uf2 directory contains code from the pico sdk: + https://github.com/raspberrypi/pico-sdk.git +version 1.2.0 (bfcbefafc5d2a210551a4d9d80b4303d4ae0adf7). Contents +taken from the tools/elf2uf2/ directory. + The rp2040_flash directory contains a light-weight bootsel flash tool. It uses C part of the the `picoboot_connection` directory found in: https://github.com/raspberrypi/picotool.git diff --git a/lib/elf2uf2/elf.h b/lib/elf2uf2/elf.h new file mode 100644 index 00000000..32e3dbb4 --- /dev/null +++ b/lib/elf2uf2/elf.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _ELF_H +#define _ELF_H + +#include + +#define ELF_MAGIC 0x464c457fu + +#define EM_ARM 0x28u + +#define EF_ARM_ABI_FLOAT_HARD 0x00000400u + +#define PT_LOAD 0x00000001u + +#pragma pack(push, 1) +struct elf_header { + uint32_t magic; + uint8_t arch_class; + uint8_t endianness; + uint8_t version; + uint8_t abi; + uint8_t abi_version; + uint8_t _pad[7]; + uint16_t type; + uint16_t machine; + uint32_t version2; +}; + +struct elf32_header { + struct elf_header common; + uint32_t entry; + uint32_t ph_offset; + uint32_t sh_offset; + uint32_t flags; + uint16_t eh_size; + uint16_t ph_entry_size; + uint16_t ph_num; + uint16_t sh_entry_size; + uint16_t sh_num; + uint16_t sh_str_index; +}; + +struct elf32_ph_entry { + uint32_t type; + uint32_t offset; + uint32_t vaddr; + uint32_t paddr; + uint32_t filez; + uint32_t memsz; + uint32_t flags; + uint32_t align; +}; +#pragma pack(pop) + +#endif \ No newline at end of file diff --git a/lib/elf2uf2/main.cpp b/lib/elf2uf2/main.cpp new file mode 100644 index 00000000..b66f082c --- /dev/null +++ b/lib/elf2uf2/main.cpp @@ -0,0 +1,350 @@ +/* + * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include "boot/uf2.h" +#include "elf.h" + +typedef unsigned int uint; + +#define ERROR_ARGS -1 +#define ERROR_FORMAT -2 +#define ERROR_INCOMPATIBLE -3 +#define ERROR_READ_FAILED -4 +#define ERROR_WRITE_FAILED -5 + +static char error_msg[512]; +static bool verbose; + +static int fail(int code, const char *format, ...) { + va_list args; + va_start(args, format); + vsnprintf(error_msg, sizeof(error_msg), format, args); + va_end(args); + return code; +} + +static int fail_read_error() { + return fail(ERROR_READ_FAILED, "Failed to read input file"); +} + +static int fail_write_error() { + return fail(ERROR_WRITE_FAILED, "Failed to write output file"); +} + +// we require 256 (as this is the page size supported by the device) +#define LOG2_PAGE_SIZE 8u +#define PAGE_SIZE (1u << LOG2_PAGE_SIZE) + +struct address_range { + enum type { + CONTENTS, // may have contents + NO_CONTENTS, // must be uninitialized + IGNORE // will be ignored + }; + address_range(uint32_t from, uint32_t to, type type) : from(from), to(to), type(type) {} + address_range() : address_range(0, 0, IGNORE) {} + type type; + uint32_t to; + uint32_t from; +}; + +typedef std::vector address_ranges; + +#define MAIN_RAM_START 0x20000000u +#define MAIN_RAM_END 0x20042000u +#define FLASH_START 0x10000000u +#define FLASH_END 0x15000000u +#define XIP_SRAM_START 0x15000000u +#define XIP_SRAM_END 0x15004000u +#define MAIN_RAM_BANKED_START 0x21000000u +#define MAIN_RAM_BANKED_END 0x21040000u + +const address_ranges rp2040_address_ranges_flash { + address_range(FLASH_START, FLASH_END, address_range::type::CONTENTS), + address_range(MAIN_RAM_START, MAIN_RAM_END, address_range::type::NO_CONTENTS), + address_range(MAIN_RAM_BANKED_START, MAIN_RAM_BANKED_END, address_range::type::NO_CONTENTS) +}; + +const address_ranges rp2040_address_ranges_ram { + address_range(MAIN_RAM_START, MAIN_RAM_END, address_range::type::CONTENTS), + address_range(XIP_SRAM_START, XIP_SRAM_END, address_range::type::CONTENTS), + address_range(0x00000000u, 0x00004000u, address_range::type::IGNORE) // for now we ignore the bootrom if present +}; + +struct page_fragment { + page_fragment(uint32_t file_offset, uint32_t page_offset, uint32_t bytes) : file_offset(file_offset), page_offset(page_offset), bytes(bytes) {} + uint32_t file_offset; + uint32_t page_offset; + uint32_t bytes; +}; + +static int usage() { + fprintf(stderr, "Usage: elf2uf2 (-v) \n"); + return ERROR_ARGS; +} + +static int read_and_check_elf32_header(FILE *in, elf32_header& eh_out) { + if (1 != fread(&eh_out, sizeof(eh_out), 1, in)) { + return fail(ERROR_READ_FAILED, "Unable to read ELF header"); + } + if (eh_out.common.magic != ELF_MAGIC) { + return fail(ERROR_FORMAT, "Not an ELF file"); + } + if (eh_out.common.version != 1 || eh_out.common.version2 != 1) { + return fail(ERROR_FORMAT, "Unrecognized ELF version"); + } + if (eh_out.common.arch_class != 1 || eh_out.common.endianness != 1) { + return fail(ERROR_INCOMPATIBLE, "Require 32 bit little-endian ELF"); + } + if (eh_out.eh_size != sizeof(struct elf32_header)) { + return fail(ERROR_FORMAT, "Invalid ELF32 format"); + } + if (eh_out.common.machine != EM_ARM) { + return fail(ERROR_FORMAT, "Not an ARM executable"); + } + if (eh_out.common.abi != 0) { + return fail(ERROR_INCOMPATIBLE, "Unrecognized ABI"); + } + if (eh_out.flags & EF_ARM_ABI_FLOAT_HARD) { + return fail(ERROR_INCOMPATIBLE, "HARD-FLOAT not supported"); + } + return 0; +} + +int check_address_range(const address_ranges& valid_ranges, uint32_t addr, uint32_t vaddr, uint32_t size, bool uninitialized, address_range &ar) { + for(const auto& range : valid_ranges) { + if (range.from <= addr && range.to >= addr + size) { + if (range.type == address_range::type::NO_CONTENTS && !uninitialized) { + return fail(ERROR_INCOMPATIBLE, "ELF contains memory contents for uninitialized memory"); + } + ar = range; + if (verbose) { + printf("%s segment %08x->%08x (%08x->%08x)\n", uninitialized ? "Uninitialized" : "Mapped", addr, + addr + size, vaddr, vaddr+size); + } + return 0; + } + } + return fail(ERROR_INCOMPATIBLE, "Memory segment %08x->%08x is outside of valid address range for device", addr, addr+size); +} + +int read_and_check_elf32_ph_entries(FILE *in, const elf32_header &eh, const address_ranges& valid_ranges, std::map>& pages) { + if (eh.ph_entry_size != sizeof(elf32_ph_entry)) { + return fail(ERROR_FORMAT, "Invalid ELF32 program header"); + } + if (eh.ph_num) { + std::vector entries(eh.ph_num); + if (eh.ph_num != fread(&entries[0], sizeof(struct elf32_ph_entry), eh.ph_num, in)) { + return fail_read_error(); + } + for(uint i=0;i entry.filez) { + // we have some uninitialized data too + rc = check_address_range(valid_ranges, entry.paddr + entry.filez, entry.vaddr + entry.filez, entry.memsz - entry.filez, true, + ar); + if (rc) return rc; + } + } + } + } + return 0; +} + +int realize_page(FILE *in, const std::vector &fragments, uint8_t *buf, uint buf_len) { + assert(buf_len >= PAGE_SIZE); + for(auto& frag : fragments) { + assert(frag.page_offset >= 0 && frag.page_offset < PAGE_SIZE && frag.page_offset + frag.bytes <= PAGE_SIZE); + if (fseek(in, frag.file_offset, SEEK_SET)) { + return fail_read_error(); + } + if (1 != fread(buf + frag.page_offset, frag.bytes, 1, in)) { + return fail_read_error(); + } + } + return 0; +} + +static bool is_address_valid(const address_ranges& valid_ranges, uint32_t addr) { + for(const auto& range : valid_ranges) { + if (range.from <= addr && range.to > addr) { + return true; + } + } + return false; +} + +static bool is_address_initialized(const address_ranges& valid_ranges, uint32_t addr) { + for(const auto& range : valid_ranges) { + if (range.from <= addr && range.to > addr) { + return address_range::type::CONTENTS == range.type; + } + } + return false; +} + +static bool is_address_mapped(const std::map>& pages, uint32_t addr) { + uint32_t page = addr & ~(PAGE_SIZE - 1); + if (!pages.count(page)) return false; + // todo check actual address within page + return true; +} + +int elf2uf2(FILE *in, FILE *out) { + elf32_header eh; + std::map> pages; + int rc = read_and_check_elf32_header(in, eh); + bool ram_style = false; + address_ranges valid_ranges = {}; + if (!rc) { + ram_style = is_address_initialized(rp2040_address_ranges_ram, eh.entry); + if (verbose) { + if (ram_style) { + printf("Detected RAM binary\n"); + } else { + printf("Detected FLASH binary\n"); + } + } + valid_ranges = ram_style ? rp2040_address_ranges_ram : rp2040_address_ranges_flash; + rc = read_and_check_elf32_ph_entries(in, eh, valid_ranges, pages); + } + if (rc) return rc; + if (pages.empty()) { + return fail(ERROR_INCOMPATIBLE, "The input file has no memory pages"); + } + uint page_num = 0; + if (ram_style) { + uint32_t expected_ep_main_ram = UINT32_MAX; + uint32_t expected_ep_xip_sram = UINT32_MAX; + for(auto& page_entry : pages) { + if ( ((page_entry.first >= MAIN_RAM_START) && (page_entry.first < MAIN_RAM_END)) && (page_entry.first < expected_ep_main_ram) ) { + expected_ep_main_ram = page_entry.first | 0x1; + } else if ( ((page_entry.first >= XIP_SRAM_START) && (page_entry.first < XIP_SRAM_END)) && (page_entry.first < expected_ep_xip_sram) ) { + expected_ep_xip_sram = page_entry.first | 0x1; + } + } + uint32_t expected_ep = (UINT32_MAX != expected_ep_main_ram) ? expected_ep_main_ram : expected_ep_xip_sram; + if (eh.entry == expected_ep_xip_sram) { + return fail(ERROR_INCOMPATIBLE, "B0/B1 Boot ROM does not support direct entry into XIP_SRAM\n"); + } else if (eh.entry != expected_ep) { + return fail(ERROR_INCOMPATIBLE, "A RAM binary should have an entry point at the beginning: %08x (not %08x)\n", expected_ep, eh.entry); + } + static_assert(0 == (MAIN_RAM_START & (PAGE_SIZE - 1)), ""); + // currently don't require this as entry point is now at the start, we don't know where reset vector is +#if 0 + uint8_t buf[PAGE_SIZE]; + rc = realize_page(in, pages[MAIN_RAM_START], buf, sizeof(buf)); + if (rc) return rc; + uint32_t sp = ((uint32_t *)buf)[0]; + uint32_t ip = ((uint32_t *)buf)[1]; + if (!is_address_mapped(pages, ip)) { + return fail(ERROR_INCOMPATIBLE, "Vector table at %08x is invalid: reset vector %08x is not in mapped memory", + MAIN_RAM_START, ip); + } + if (!is_address_valid(valid_ranges, sp - 4)) { + return fail(ERROR_INCOMPATIBLE, "Vector table at %08x is invalid: stack pointer %08x is not in RAM", + MAIN_RAM_START, sp); + } +#endif + } + 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 = PAGE_SIZE; + block.num_blocks = (uint32_t)pages.size(); + block.file_size = RP2040_FAMILY_ID; + block.magic_end = UF2_MAGIC_END; + for(auto& page_entry : pages) { + block.target_addr = page_entry.first; + block.block_no = page_num++; + if (verbose) { + printf("Page %d / %d %08x\n", block.block_no, block.num_blocks, block.target_addr); + } + memset(block.data, 0, sizeof(block.data)); + rc = realize_page(in, page_entry.second, block.data, sizeof(block.data)); + if (rc) return rc; + if (1 != fwrite(&block, sizeof(uf2_block), 1, out)) { + return fail_write_error(); + } + } + return 0; +} + +int main(int argc, char **argv) { + int arg = 1; + if (arg < argc && !strcmp(argv[arg], "-v")) { + verbose = true; + arg++; + } + if (argc < arg + 2) { + return usage(); + } + const char *in_filename = argv[arg++]; + FILE *in = fopen(in_filename, "rb"); + if (!in) { + fprintf(stderr, "Can't open input file '%s'\n", in_filename); + return ERROR_ARGS; + } + const char *out_filename = argv[arg++]; + FILE *out = fopen(out_filename, "wb"); + if (!out) { + fprintf(stderr, "Can't open output file '%s'\n", out_filename); + return ERROR_ARGS; + } + + int rc = elf2uf2(in, out); + fclose(in); + fclose(out); + if (rc) { + remove(out_filename); + if (error_msg[0]) { + fprintf(stderr, "ERROR: %s\n", error_msg); + } + } + return rc; +} diff --git a/lib/rp2040/elf2uf2/elf.h b/lib/rp2040/elf2uf2/elf.h deleted file mode 100644 index 32e3dbb4..00000000 --- a/lib/rp2040/elf2uf2/elf.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef _ELF_H -#define _ELF_H - -#include - -#define ELF_MAGIC 0x464c457fu - -#define EM_ARM 0x28u - -#define EF_ARM_ABI_FLOAT_HARD 0x00000400u - -#define PT_LOAD 0x00000001u - -#pragma pack(push, 1) -struct elf_header { - uint32_t magic; - uint8_t arch_class; - uint8_t endianness; - uint8_t version; - uint8_t abi; - uint8_t abi_version; - uint8_t _pad[7]; - uint16_t type; - uint16_t machine; - uint32_t version2; -}; - -struct elf32_header { - struct elf_header common; - uint32_t entry; - uint32_t ph_offset; - uint32_t sh_offset; - uint32_t flags; - uint16_t eh_size; - uint16_t ph_entry_size; - uint16_t ph_num; - uint16_t sh_entry_size; - uint16_t sh_num; - uint16_t sh_str_index; -}; - -struct elf32_ph_entry { - uint32_t type; - uint32_t offset; - uint32_t vaddr; - uint32_t paddr; - uint32_t filez; - uint32_t memsz; - uint32_t flags; - uint32_t align; -}; -#pragma pack(pop) - -#endif \ No newline at end of file diff --git a/lib/rp2040/elf2uf2/main.cpp b/lib/rp2040/elf2uf2/main.cpp deleted file mode 100644 index b66f082c..00000000 --- a/lib/rp2040/elf2uf2/main.cpp +++ /dev/null @@ -1,350 +0,0 @@ -/* - * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#include -#include -#include -#include -#include -#include -#include "boot/uf2.h" -#include "elf.h" - -typedef unsigned int uint; - -#define ERROR_ARGS -1 -#define ERROR_FORMAT -2 -#define ERROR_INCOMPATIBLE -3 -#define ERROR_READ_FAILED -4 -#define ERROR_WRITE_FAILED -5 - -static char error_msg[512]; -static bool verbose; - -static int fail(int code, const char *format, ...) { - va_list args; - va_start(args, format); - vsnprintf(error_msg, sizeof(error_msg), format, args); - va_end(args); - return code; -} - -static int fail_read_error() { - return fail(ERROR_READ_FAILED, "Failed to read input file"); -} - -static int fail_write_error() { - return fail(ERROR_WRITE_FAILED, "Failed to write output file"); -} - -// we require 256 (as this is the page size supported by the device) -#define LOG2_PAGE_SIZE 8u -#define PAGE_SIZE (1u << LOG2_PAGE_SIZE) - -struct address_range { - enum type { - CONTENTS, // may have contents - NO_CONTENTS, // must be uninitialized - IGNORE // will be ignored - }; - address_range(uint32_t from, uint32_t to, type type) : from(from), to(to), type(type) {} - address_range() : address_range(0, 0, IGNORE) {} - type type; - uint32_t to; - uint32_t from; -}; - -typedef std::vector address_ranges; - -#define MAIN_RAM_START 0x20000000u -#define MAIN_RAM_END 0x20042000u -#define FLASH_START 0x10000000u -#define FLASH_END 0x15000000u -#define XIP_SRAM_START 0x15000000u -#define XIP_SRAM_END 0x15004000u -#define MAIN_RAM_BANKED_START 0x21000000u -#define MAIN_RAM_BANKED_END 0x21040000u - -const address_ranges rp2040_address_ranges_flash { - address_range(FLASH_START, FLASH_END, address_range::type::CONTENTS), - address_range(MAIN_RAM_START, MAIN_RAM_END, address_range::type::NO_CONTENTS), - address_range(MAIN_RAM_BANKED_START, MAIN_RAM_BANKED_END, address_range::type::NO_CONTENTS) -}; - -const address_ranges rp2040_address_ranges_ram { - address_range(MAIN_RAM_START, MAIN_RAM_END, address_range::type::CONTENTS), - address_range(XIP_SRAM_START, XIP_SRAM_END, address_range::type::CONTENTS), - address_range(0x00000000u, 0x00004000u, address_range::type::IGNORE) // for now we ignore the bootrom if present -}; - -struct page_fragment { - page_fragment(uint32_t file_offset, uint32_t page_offset, uint32_t bytes) : file_offset(file_offset), page_offset(page_offset), bytes(bytes) {} - uint32_t file_offset; - uint32_t page_offset; - uint32_t bytes; -}; - -static int usage() { - fprintf(stderr, "Usage: elf2uf2 (-v) \n"); - return ERROR_ARGS; -} - -static int read_and_check_elf32_header(FILE *in, elf32_header& eh_out) { - if (1 != fread(&eh_out, sizeof(eh_out), 1, in)) { - return fail(ERROR_READ_FAILED, "Unable to read ELF header"); - } - if (eh_out.common.magic != ELF_MAGIC) { - return fail(ERROR_FORMAT, "Not an ELF file"); - } - if (eh_out.common.version != 1 || eh_out.common.version2 != 1) { - return fail(ERROR_FORMAT, "Unrecognized ELF version"); - } - if (eh_out.common.arch_class != 1 || eh_out.common.endianness != 1) { - return fail(ERROR_INCOMPATIBLE, "Require 32 bit little-endian ELF"); - } - if (eh_out.eh_size != sizeof(struct elf32_header)) { - return fail(ERROR_FORMAT, "Invalid ELF32 format"); - } - if (eh_out.common.machine != EM_ARM) { - return fail(ERROR_FORMAT, "Not an ARM executable"); - } - if (eh_out.common.abi != 0) { - return fail(ERROR_INCOMPATIBLE, "Unrecognized ABI"); - } - if (eh_out.flags & EF_ARM_ABI_FLOAT_HARD) { - return fail(ERROR_INCOMPATIBLE, "HARD-FLOAT not supported"); - } - return 0; -} - -int check_address_range(const address_ranges& valid_ranges, uint32_t addr, uint32_t vaddr, uint32_t size, bool uninitialized, address_range &ar) { - for(const auto& range : valid_ranges) { - if (range.from <= addr && range.to >= addr + size) { - if (range.type == address_range::type::NO_CONTENTS && !uninitialized) { - return fail(ERROR_INCOMPATIBLE, "ELF contains memory contents for uninitialized memory"); - } - ar = range; - if (verbose) { - printf("%s segment %08x->%08x (%08x->%08x)\n", uninitialized ? "Uninitialized" : "Mapped", addr, - addr + size, vaddr, vaddr+size); - } - return 0; - } - } - return fail(ERROR_INCOMPATIBLE, "Memory segment %08x->%08x is outside of valid address range for device", addr, addr+size); -} - -int read_and_check_elf32_ph_entries(FILE *in, const elf32_header &eh, const address_ranges& valid_ranges, std::map>& pages) { - if (eh.ph_entry_size != sizeof(elf32_ph_entry)) { - return fail(ERROR_FORMAT, "Invalid ELF32 program header"); - } - if (eh.ph_num) { - std::vector entries(eh.ph_num); - if (eh.ph_num != fread(&entries[0], sizeof(struct elf32_ph_entry), eh.ph_num, in)) { - return fail_read_error(); - } - for(uint i=0;i entry.filez) { - // we have some uninitialized data too - rc = check_address_range(valid_ranges, entry.paddr + entry.filez, entry.vaddr + entry.filez, entry.memsz - entry.filez, true, - ar); - if (rc) return rc; - } - } - } - } - return 0; -} - -int realize_page(FILE *in, const std::vector &fragments, uint8_t *buf, uint buf_len) { - assert(buf_len >= PAGE_SIZE); - for(auto& frag : fragments) { - assert(frag.page_offset >= 0 && frag.page_offset < PAGE_SIZE && frag.page_offset + frag.bytes <= PAGE_SIZE); - if (fseek(in, frag.file_offset, SEEK_SET)) { - return fail_read_error(); - } - if (1 != fread(buf + frag.page_offset, frag.bytes, 1, in)) { - return fail_read_error(); - } - } - return 0; -} - -static bool is_address_valid(const address_ranges& valid_ranges, uint32_t addr) { - for(const auto& range : valid_ranges) { - if (range.from <= addr && range.to > addr) { - return true; - } - } - return false; -} - -static bool is_address_initialized(const address_ranges& valid_ranges, uint32_t addr) { - for(const auto& range : valid_ranges) { - if (range.from <= addr && range.to > addr) { - return address_range::type::CONTENTS == range.type; - } - } - return false; -} - -static bool is_address_mapped(const std::map>& pages, uint32_t addr) { - uint32_t page = addr & ~(PAGE_SIZE - 1); - if (!pages.count(page)) return false; - // todo check actual address within page - return true; -} - -int elf2uf2(FILE *in, FILE *out) { - elf32_header eh; - std::map> pages; - int rc = read_and_check_elf32_header(in, eh); - bool ram_style = false; - address_ranges valid_ranges = {}; - if (!rc) { - ram_style = is_address_initialized(rp2040_address_ranges_ram, eh.entry); - if (verbose) { - if (ram_style) { - printf("Detected RAM binary\n"); - } else { - printf("Detected FLASH binary\n"); - } - } - valid_ranges = ram_style ? rp2040_address_ranges_ram : rp2040_address_ranges_flash; - rc = read_and_check_elf32_ph_entries(in, eh, valid_ranges, pages); - } - if (rc) return rc; - if (pages.empty()) { - return fail(ERROR_INCOMPATIBLE, "The input file has no memory pages"); - } - uint page_num = 0; - if (ram_style) { - uint32_t expected_ep_main_ram = UINT32_MAX; - uint32_t expected_ep_xip_sram = UINT32_MAX; - for(auto& page_entry : pages) { - if ( ((page_entry.first >= MAIN_RAM_START) && (page_entry.first < MAIN_RAM_END)) && (page_entry.first < expected_ep_main_ram) ) { - expected_ep_main_ram = page_entry.first | 0x1; - } else if ( ((page_entry.first >= XIP_SRAM_START) && (page_entry.first < XIP_SRAM_END)) && (page_entry.first < expected_ep_xip_sram) ) { - expected_ep_xip_sram = page_entry.first | 0x1; - } - } - uint32_t expected_ep = (UINT32_MAX != expected_ep_main_ram) ? expected_ep_main_ram : expected_ep_xip_sram; - if (eh.entry == expected_ep_xip_sram) { - return fail(ERROR_INCOMPATIBLE, "B0/B1 Boot ROM does not support direct entry into XIP_SRAM\n"); - } else if (eh.entry != expected_ep) { - return fail(ERROR_INCOMPATIBLE, "A RAM binary should have an entry point at the beginning: %08x (not %08x)\n", expected_ep, eh.entry); - } - static_assert(0 == (MAIN_RAM_START & (PAGE_SIZE - 1)), ""); - // currently don't require this as entry point is now at the start, we don't know where reset vector is -#if 0 - uint8_t buf[PAGE_SIZE]; - rc = realize_page(in, pages[MAIN_RAM_START], buf, sizeof(buf)); - if (rc) return rc; - uint32_t sp = ((uint32_t *)buf)[0]; - uint32_t ip = ((uint32_t *)buf)[1]; - if (!is_address_mapped(pages, ip)) { - return fail(ERROR_INCOMPATIBLE, "Vector table at %08x is invalid: reset vector %08x is not in mapped memory", - MAIN_RAM_START, ip); - } - if (!is_address_valid(valid_ranges, sp - 4)) { - return fail(ERROR_INCOMPATIBLE, "Vector table at %08x is invalid: stack pointer %08x is not in RAM", - MAIN_RAM_START, sp); - } -#endif - } - 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 = PAGE_SIZE; - block.num_blocks = (uint32_t)pages.size(); - block.file_size = RP2040_FAMILY_ID; - block.magic_end = UF2_MAGIC_END; - for(auto& page_entry : pages) { - block.target_addr = page_entry.first; - block.block_no = page_num++; - if (verbose) { - printf("Page %d / %d %08x\n", block.block_no, block.num_blocks, block.target_addr); - } - memset(block.data, 0, sizeof(block.data)); - rc = realize_page(in, page_entry.second, block.data, sizeof(block.data)); - if (rc) return rc; - if (1 != fwrite(&block, sizeof(uf2_block), 1, out)) { - return fail_write_error(); - } - } - return 0; -} - -int main(int argc, char **argv) { - int arg = 1; - if (arg < argc && !strcmp(argv[arg], "-v")) { - verbose = true; - arg++; - } - if (argc < arg + 2) { - return usage(); - } - const char *in_filename = argv[arg++]; - FILE *in = fopen(in_filename, "rb"); - if (!in) { - fprintf(stderr, "Can't open input file '%s'\n", in_filename); - return ERROR_ARGS; - } - const char *out_filename = argv[arg++]; - FILE *out = fopen(out_filename, "wb"); - if (!out) { - fprintf(stderr, "Can't open output file '%s'\n", out_filename); - return ERROR_ARGS; - } - - int rc = elf2uf2(in, out); - fclose(in); - fclose(out); - if (rc) { - remove(out_filename); - if (error_msg[0]) { - fprintf(stderr, "ERROR: %s\n", error_msg); - } - } - return rc; -} -- cgit v1.2.3-70-g09d2