From 6d567af392c26c3c6701808555bbef28129eff42 Mon Sep 17 00:00:00 2001 From: Marcus Comstedt Date: Mon, 5 Apr 2021 20:30:56 +0200 Subject: [PATCH] Properly account for Pico being little endian --- .../boot_picoboot/include/boot/picoboot.h | 35 +++++----- src/common/boot_uf2/include/boot/uf2.h | 24 ++++--- .../include/pico/binary_info/structure.h | 58 ++++++++-------- .../pico_platform/include/pico/platform.h | 30 ++++++++ .../pico_platform/include/pico/platform.h | 5 ++ tools/elf2uf2/CMakeLists.txt | 3 +- tools/elf2uf2/elf.h | 69 ++++++++++--------- tools/elf2uf2/main.cpp | 2 +- 8 files changed, 138 insertions(+), 88 deletions(-) diff --git a/src/common/boot_picoboot/include/boot/picoboot.h b/src/common/boot_picoboot/include/boot/picoboot.h index ddfa0aaad..0e4a8aeae 100644 --- a/src/common/boot_picoboot/include/boot/picoboot.h +++ b/src/common/boot_picoboot/include/boot/picoboot.h @@ -66,21 +66,21 @@ enum picoboot_status { PICOBOOT_UNKNOWN_ERROR = 8, }; -struct __packed picoboot_reboot_cmd { - uint32_t dPC; // 0 means reset into bootrom - uint32_t dSP; - uint32_t dDelayMS; +struct __packed __little_endian picoboot_reboot_cmd { + LE(uint32_t) dPC; // 0 means reset into bootrom + LE(uint32_t) dSP; + LE(uint32_t) dDelayMS; }; // used for EXEC, VECTORIZE_FLASH -struct __packed picoboot_address_only_cmd { - uint32_t dAddr; +struct __packed __little_endian picoboot_address_only_cmd { + LE(uint32_t) dAddr; }; // used for READ, WRITE, FLASH_ERASE -struct __packed picoboot_range_cmd { - uint32_t dAddr; - uint32_t dSize; +struct __packed __little_endian picoboot_range_cmd { + LE(uint32_t) dAddr; + LE(uint32_t) dSize; }; enum picoboot_exclusive_type { @@ -94,13 +94,13 @@ struct __packed picoboot_exclusive_cmd { }; // little endian -struct __packed __aligned(4) picoboot_cmd { - uint32_t dMagic; - uint32_t dToken; // an identifier for this token to correlate with a status response +struct __packed __aligned(4) __little_endian picoboot_cmd { + LE(uint32_t) dMagic; + LE(uint32_t) dToken; // an identifier for this token to correlate with a status response uint8_t bCmdId; // top bit set for IN uint8_t bCmdSize; // bytes of actual data in the arg part of this structure - uint16_t _unused; - uint32_t dTransferLength; // length of IN/OUT transfer (or 0) if none + LE(uint16_t) _unused; + LE(uint32_t) dTransferLength; // length of IN/OUT transfer (or 0) if none union { uint8_t args[16]; struct picoboot_reboot_cmd reboot_cmd; @@ -112,13 +112,14 @@ struct __packed __aligned(4) picoboot_cmd { static_assert(32 == sizeof(struct picoboot_cmd), "picoboot_cmd must be 32 bytes big"); -struct __packed __aligned(4) picoboot_cmd_status { - uint32_t dToken; - uint32_t dStatusCode; +struct __packed __aligned(4) __little_endian picoboot_cmd_status { + LE(uint32_t) dToken; + LE(uint32_t) dStatusCode; uint8_t bCmdId; uint8_t bInProgress; uint8_t _pad[6]; }; static_assert(16 == sizeof(struct picoboot_cmd_status), "picoboot_cmd_status must be 16 bytes big"); + #endif diff --git a/src/common/boot_uf2/include/boot/uf2.h b/src/common/boot_uf2/include/boot/uf2.h index a040242bd..2ab75ffb2 100644 --- a/src/common/boot_uf2/include/boot/uf2.h +++ b/src/common/boot_uf2/include/boot/uf2.h @@ -10,6 +10,10 @@ #include #include +#ifndef NO_PICO_PLATFORM +#include "pico/platform.h" +#endif + /** \file uf2.h * \defgroup boot_uf2 boot_uf2 * @@ -27,18 +31,18 @@ #define RP2040_FAMILY_ID 0xe48bff56 -struct uf2_block { +struct uf2_block __little_endian { // 32 byte header - uint32_t magic_start0; - uint32_t magic_start1; - uint32_t flags; - uint32_t target_addr; - uint32_t payload_size; - uint32_t block_no; - uint32_t num_blocks; - uint32_t file_size; // or familyID; + LE(uint32_t) magic_start0; + LE(uint32_t) magic_start1; + LE(uint32_t) flags; + LE(uint32_t) target_addr; + LE(uint32_t) payload_size; + LE(uint32_t) block_no; + LE(uint32_t) num_blocks; + LE(uint32_t) file_size; // or familyID; uint8_t data[476]; - uint32_t magic_end; + LE(uint32_t) magic_end; }; static_assert(sizeof(struct uf2_block) == 512, "uf2_block not sector sized"); diff --git a/src/common/pico_binary_info/include/pico/binary_info/structure.h b/src/common/pico_binary_info/include/pico/binary_info/structure.h index 49d2fd690..743e7d238 100644 --- a/src/common/pico_binary_info/include/pico/binary_info/structure.h +++ b/src/common/pico_binary_info/include/pico/binary_info/structure.h @@ -17,6 +17,10 @@ extern "C" { #include +#ifndef NO_PICO_PLATFORM +#include "pico/platform.h" +#endif + #ifndef __packed #define __packed __attribute__((packed)) #endif @@ -59,63 +63,63 @@ typedef struct _binary_info_core binary_info_t; #if PICO_ON_DEVICE #define bi_ptr_of(x) x * #else -#define bi_ptr_of(x) uint32_t +#define bi_ptr_of(x) LE(uint32_t) #endif -typedef struct __packed _binary_info_core { - uint16_t type; - uint16_t tag; +typedef struct __packed __little_endian _binary_info_core { + LE(uint16_t) type; + LE(uint16_t) tag; } binary_info_core_t; -typedef struct __packed _binary_info_raw_data { +typedef struct __packed __little_endian _binary_info_raw_data { struct _binary_info_core core; uint8_t bytes[1]; } binary_info_raw_data_t; -typedef struct __packed _binary_info_sized_data { +typedef struct __packed __little_endian _binary_info_sized_data { struct _binary_info_core core; - uint32_t length; + LE(uint32_t) length; uint8_t bytes[1]; } binary_info_sized_data_t; -typedef struct __packed _binary_info_list_zero_terminated { +typedef struct __packed __little_endian _binary_info_list_zero_terminated { struct _binary_info_core core; bi_ptr_of(binary_info_t) list; } binary_info_list_zero_terminated_t; -typedef struct __packed _binary_info_id_and_int { +typedef struct __packed __little_endian _binary_info_id_and_int { struct _binary_info_core core; - uint32_t id; - int32_t value; + LE(uint32_t) id; + LE(int32_t) value; } binary_info_id_and_int_t; -typedef struct __packed _binary_info_id_and_string { +typedef struct __packed __little_endian _binary_info_id_and_string { struct _binary_info_core core; - uint32_t id; + LE(uint32_t) id; bi_ptr_of(const char) value; } binary_info_id_and_string_t; -typedef struct __packed _binary_info_block_device { +typedef struct __packed __little_endian _binary_info_block_device { struct _binary_info_core core; bi_ptr_of(const char) name; // optional static name (independent of what is formatted) - uint32_t address; - uint32_t size; + LE(uint32_t) address; + LE(uint32_t) size; bi_ptr_of(binary_info_t) extra; // additional info - uint16_t flags; + LE(uint16_t) flags; } binary_info_block_device_t; #define BI_PINS_ENCODING_RANGE 1 #define BI_PINS_ENCODING_MULTI 2 -typedef struct __packed _binary_info_pins_with_func { +typedef struct __packed __little_endian _binary_info_pins_with_func { struct _binary_info_core core; // p4_5 : p3_5 : p2_5 : p1_5 : p0_5 : func_4 : 001_3 //individual pins p0,p1,p2,p3,p4 ... if fewer than 5 then duplicate p // phi_5 : plo_5 : func_4 : 010_3 // pin range plo-phi inclusive - uint32_t pin_encoding; + LE(uint32_t) pin_encoding; } binary_info_pins_with_func_t; -typedef struct __packed _binary_info_pins_with_name { +typedef struct __packed __little_endian _binary_info_pins_with_name { struct _binary_info_core core; - uint32_t pin_mask; + LE(uint32_t) pin_mask; bi_ptr_of(const char) label; } binary_info_pins_with_name_t; @@ -124,12 +128,12 @@ typedef struct __packed _binary_info_pins_with_name { #define BI_NAMED_GROUP_SORT_ALPHA 0x0004 // default is no sort #define BI_NAMED_GROUP_ADVANCED 0x0008 // if set, then only shown in say info -a -typedef struct __packed _binary_info_named_group { +typedef struct __packed __little_endian _binary_info_named_group { struct _binary_info_core core; - uint32_t parent_id; - uint16_t flags; - uint16_t group_tag; - uint32_t group_id; + LE(uint32_t) parent_id; + LE(uint16_t) flags; + LE(uint16_t) group_tag; + LE(uint32_t) group_id; bi_ptr_of(const char) label; } binary_info_named_group_t; @@ -148,4 +152,4 @@ enum { #ifdef __cplusplus } #endif -#endif \ No newline at end of file +#endif diff --git a/src/host/pico_platform/include/pico/platform.h b/src/host/pico_platform/include/pico/platform.h index da060a6a2..658360cdc 100644 --- a/src/host/pico_platform/include/pico/platform.h +++ b/src/host/pico_platform/include/pico/platform.h @@ -136,4 +136,34 @@ static inline void __compiler_memory_barrier(void) { #ifdef __cplusplus } #endif + +#if defined(_MSC_VER) || __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +// Host byteorder is LE, use default scalar storage order for LE structs +#define LE(x) x +#define __little_endian +#elif !defined(__cplusplus) +// Host byteorder is BE, need to explicitly set little endian sso +#define LE(x) x +#define __little_endian __attribute__((scalar_storage_order("little-endian"))) +#else +// scalar_storage_order attribute is not supported for C++, need to do this +// the hard way. :-) +template struct little_endian { + uint8_t v[sizeof(T)]; + inline little_endian& operator= (const T& x) { + for (unsigned i = 0; i < sizeof(T); i++) + v[i] = x >> 8*i; + return *this; + }; + inline operator T() const { + T x = v[0]; + for (unsigned i = 1; i < sizeof(T); i++) + x |= v[i] << 8*i; + return x; + } +}; +#define LE(x) little_endian +#define __little_endian +#endif + #endif diff --git a/src/rp2_common/pico_platform/include/pico/platform.h b/src/rp2_common/pico_platform/include/pico/platform.h index e17dbca87..cb429cf47 100644 --- a/src/rp2_common/pico_platform/include/pico/platform.h +++ b/src/rp2_common/pico_platform/include/pico/platform.h @@ -172,4 +172,9 @@ extern uint __get_current_exception(void); #ifdef __cplusplus } #endif + +/* Pico is native LE */ +#define LE(x) x +#define __little_endian + #endif diff --git a/tools/elf2uf2/CMakeLists.txt b/tools/elf2uf2/CMakeLists.txt index 070e114ef..dbeade1a7 100644 --- a/tools/elf2uf2/CMakeLists.txt +++ b/tools/elf2uf2/CMakeLists.txt @@ -4,6 +4,7 @@ project(elf2uf2) set(CMAKE_CXX_STANDARD 14) add_subdirectory(../../src/common/boot_uf2 boot_uf2_headers) +add_subdirectory(../../src/host/pico_platform pico_platform) add_executable(elf2uf2 main.cpp) -target_link_libraries(elf2uf2 boot_uf2_headers) \ No newline at end of file +target_link_libraries(elf2uf2 boot_uf2_headers pico_platform_headers) \ No newline at end of file diff --git a/tools/elf2uf2/elf.h b/tools/elf2uf2/elf.h index 32e3dbb40..02afc2bfb 100644 --- a/tools/elf2uf2/elf.h +++ b/tools/elf2uf2/elf.h @@ -9,6 +9,10 @@ #include +#ifndef NO_PICO_PLATFORM +#include "pico/platform.h" +#endif + #define ELF_MAGIC 0x464c457fu #define EM_ARM 0x28u @@ -17,44 +21,45 @@ #define PT_LOAD 0x00000001u +/* Note, only little endian ELFs handled */ #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 elf_header __little_endian { + LE(uint32_t) magic; + uint8_t arch_class; + uint8_t endianness; + uint8_t version; + uint8_t abi; + uint8_t abi_version; + uint8_t _pad[7]; + LE(uint16_t) type; + LE(uint16_t) machine; + LE(uint32_t) version2; }; -struct elf32_header { +struct elf32_header __little_endian { 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; + LE(uint32_t) entry; + LE(uint32_t) ph_offset; + LE(uint32_t) sh_offset; + LE(uint32_t) flags; + LE(uint16_t) eh_size; + LE(uint16_t) ph_entry_size; + LE(uint16_t) ph_num; + LE(uint16_t) sh_entry_size; + LE(uint16_t) sh_num; + LE(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; +struct elf32_ph_entry __little_endian { + LE(uint32_t) type; + LE(uint32_t) offset; + LE(uint32_t) vaddr; + LE(uint32_t) paddr; + LE(uint32_t) filez; + LE(uint32_t) memsz; + LE(uint32_t) flags; + LE(uint32_t) align; }; #pragma pack(pop) -#endif \ No newline at end of file +#endif diff --git a/tools/elf2uf2/main.cpp b/tools/elf2uf2/main.cpp index 07cd107a4..55ec97769 100644 --- a/tools/elf2uf2/main.cpp +++ b/tools/elf2uf2/main.cpp @@ -300,7 +300,7 @@ int elf2uf2(FILE *in, FILE *out) { 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); + printf("Page %d / %d %08x\n", static_cast(block.block_no), static_cast(block.num_blocks), static_cast(block.target_addr)); } memset(block.data, 0, sizeof(block.data)); rc = realize_page(in, page_entry.second, block.data, sizeof(block.data));