A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd

jztool: support new binary header on x1000

Change-Id: If0d3fb3d5b03cf6ed87cbbb8a968ef48edb660f7

+88 -11
+88 -11
utils/jztool/src/x1000.c
··· 25 25 #include <stdbool.h> 26 26 #include <string.h> 27 27 28 - /* TODO: these functions could be refactored to be CPU-agnostic */ 28 + #define X1000_TCSM_BASE 0xf4000000 29 + 30 + #define X1000_SPL_LOAD_ADDR (X1000_TCSM_BASE + 0x1000) 31 + #define X1000_SPL_EXEC_ADDR (X1000_TCSM_BASE + 0x1800) 32 + 33 + #define X1000_STANDARD_DRAM_BASE 0x80004000 34 + 35 + #define HDR_BEGIN 128 /* header must begin within this many bytes */ 36 + #define HDR_LEN 256 /* header length cannot exceed this */ 37 + 38 + #define MIN(a,b) ((a) < (b) ? (a) : (b)) 39 + 40 + /* search for header value, label must be a 4-character string. 41 + * Returns the found value or 0 if the label wasn't found. */ 42 + static uint32_t search_header(const unsigned char* source, size_t length, 43 + const char* label) 44 + { 45 + size_t search_len = MIN(length, HDR_BEGIN); 46 + if(search_len < 8) 47 + return 0; 48 + search_len -= 7; 49 + 50 + /* find the beginning marker */ 51 + size_t i; 52 + for(i = 8; i < search_len; i += 4) 53 + if(!memcmp(&source[i], "BEGINHDR", 8)) 54 + break; 55 + if(i >= search_len) 56 + return 0; 57 + i += 8; 58 + 59 + /* search within the header */ 60 + search_len = MIN(length, i + HDR_LEN) - 7; 61 + for(; i < search_len; i += 8) { 62 + if(!memcmp(&source[i], "ENDH", 4)) { 63 + break; 64 + } else if(!memcmp(&source[i], label, 4)) { 65 + i += 4; 66 + /* read little-endian value */ 67 + uint32_t ret = source[i]; 68 + ret |= source[i+1] << 8; 69 + ret |= source[i+2] << 16; 70 + ret |= source[i+3] << 24; 71 + return ret; 72 + } 73 + } 74 + 75 + return 0; 76 + } 77 + 29 78 static int run_stage1(jz_usbdev* dev, jz_buffer* buf) 30 79 { 31 - int rc = jz_usb_send(dev, 0xf4001000, buf->size, buf->data); 80 + int rc = jz_usb_send(dev, X1000_SPL_LOAD_ADDR, buf->size, buf->data); 32 81 if(rc < 0) 33 82 return rc; 34 83 35 - return jz_usb_start1(dev, 0xf4001800); 84 + return jz_usb_start1(dev, X1000_SPL_EXEC_ADDR); 36 85 } 37 86 38 87 static int run_stage2(jz_usbdev* dev, jz_buffer* buf) 39 88 { 40 - int rc = jz_usb_send(dev, 0x80004000, buf->size, buf->data); 89 + uint32_t load_addr = search_header(buf->data, buf->size, "LOAD"); 90 + if(!load_addr) 91 + load_addr = X1000_STANDARD_DRAM_BASE; 92 + 93 + int rc = jz_usb_send(dev, load_addr, buf->size, buf->data); 41 94 if(rc < 0) 42 95 return rc; 43 96 ··· 45 98 if(rc < 0) 46 99 return rc; 47 100 48 - return jz_usb_start2(dev, 0x80004000); 101 + return jz_usb_start2(dev, load_addr); 49 102 } 50 103 104 + enum { 105 + F_DECOMPRESS = 0x01, 106 + F_OPTIONAL = 0x02, 107 + }; 108 + 51 109 static int get_file(jz_context* jz, mtar_t* tar, const char* file, 52 - bool decompress, jz_buffer** buf) 110 + unsigned int flags, jz_buffer** buf) 53 111 { 54 112 jz_buffer* buffer = NULL; 55 113 const mtar_header_t* h; ··· 57 115 58 116 rc = mtar_find(tar, file); 59 117 if(rc != MTAR_ESUCCESS) { 60 - jz_log(jz, JZ_LOG_ERROR, "can't find %s in boot file, tar error %d", file, rc); 61 - return JZ_ERR_BAD_FILE_FORMAT; 118 + if(!(flags & F_OPTIONAL)) 119 + jz_log(jz, JZ_LOG_ERROR, "can't find %s in boot file, tar error %d", file, rc); 120 + return JZ_ERR_OPEN_FILE; 62 121 } 63 122 64 123 h = mtar_get_header(tar); ··· 73 132 return JZ_ERR_BAD_FILE_FORMAT; 74 133 } 75 134 76 - if(decompress) { 135 + if(flags & F_DECOMPRESS) { 77 136 uint32_t dst_len; 78 137 jz_buffer* nbuf = jz_ucl_unpack(buffer->data, buffer->size, &dst_len); 79 138 jz_buffer_free(buffer); ··· 139 198 if(rc != JZ_SUCCESS) 140 199 goto error; 141 200 142 - rc = get_file(dev->jz, &tar, "bootloader.ucl", true, &bootloader); 143 - if(rc != JZ_SUCCESS) 201 + /* - A bootloader2.ucl binary should carry the LOAD header to define its 202 + * load address. This name must be used when the load address is not 203 + * equal to 0x80004000 to ensure old jztools will not try to load it. 204 + * 205 + * - The bootloader.ucl name must only be used when the binary loads at 206 + * 0x80004000 and can be booted by old versions of jztool. 207 + */ 208 + const char* bl_files[2] = {"bootloader2.ucl", "bootloader.ucl"}; 209 + for(int i = 0; i < 2; ++i) { 210 + rc = get_file(dev->jz, &tar, bl_files[i], 211 + F_DECOMPRESS|F_OPTIONAL, &bootloader); 212 + if(rc == JZ_SUCCESS) 213 + break; 214 + else if(rc != JZ_ERR_OPEN_FILE) 215 + goto error; 216 + } 217 + 218 + if(rc != JZ_SUCCESS) { 219 + jz_log(dev->jz, JZ_LOG_ERROR, "no bootloader binary found", filename); 144 220 goto error; 221 + } 145 222 146 223 rc = get_file(dev->jz, &tar, "bootloader-info.txt", false, &info_file); 147 224 if(rc != JZ_SUCCESS)