diff options
author | Aidan MacDonald <amachronic@protonmail.com> | 2022-02-28 22:11:31 +0000 |
---|---|---|
committer | Aidan MacDonald <amachronic@protonmail.com> | 2022-03-11 11:15:56 -0500 |
commit | cdee5284d46c913859bcb105bf3ea86bcbd6014f (patch) | |
tree | c03b95cbeb3fc81190a9622487bc7d4078520685 | |
parent | 35242c8d98566da64f0f5210e0f580e7bcdb0365 (diff) | |
download | rockbox-cdee5284d46c913859bcb105bf3ea86bcbd6014f.tar.gz rockbox-cdee5284d46c913859bcb105bf3ea86bcbd6014f.zip |
jztool: support new binary header on x1000
Change-Id: If0d3fb3d5b03cf6ed87cbbb8a968ef48edb660f7
-rw-r--r-- | utils/jztool/src/x1000.c | 99 |
1 files changed, 88 insertions, 11 deletions
diff --git a/utils/jztool/src/x1000.c b/utils/jztool/src/x1000.c index f59727a2ca..e4bd466562 100644 --- a/utils/jztool/src/x1000.c +++ b/utils/jztool/src/x1000.c | |||
@@ -25,19 +25,72 @@ | |||
25 | #include <stdbool.h> | 25 | #include <stdbool.h> |
26 | #include <string.h> | 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 | static int run_stage1(jz_usbdev* dev, jz_buffer* buf) | 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 | if(rc < 0) | 81 | if(rc < 0) |
33 | return rc; | 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 | static int run_stage2(jz_usbdev* dev, jz_buffer* buf) | 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 | if(rc < 0) | 94 | if(rc < 0) |
42 | return rc; | 95 | return rc; |
43 | 96 | ||
@@ -45,11 +98,16 @@ static int run_stage2(jz_usbdev* dev, jz_buffer* buf) | |||
45 | if(rc < 0) | 98 | if(rc < 0) |
46 | return rc; | 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 | static int get_file(jz_context* jz, mtar_t* tar, const char* file, | 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 | jz_buffer* buffer = NULL; | 112 | jz_buffer* buffer = NULL; |
55 | const mtar_header_t* h; | 113 | const mtar_header_t* h; |
@@ -57,8 +115,9 @@ static int get_file(jz_context* jz, mtar_t* tar, const char* file, | |||
57 | 115 | ||
58 | rc = mtar_find(tar, file); | 116 | rc = mtar_find(tar, file); |
59 | if(rc != MTAR_ESUCCESS) { | 117 | if(rc != MTAR_ESUCCESS) { |
60 | jz_log(jz, JZ_LOG_ERROR, "can't find %s in boot file, tar error %d", file, rc); | 118 | if(!(flags & F_OPTIONAL)) |
61 | return JZ_ERR_BAD_FILE_FORMAT; | 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 | h = mtar_get_header(tar); | 123 | h = mtar_get_header(tar); |
@@ -73,7 +132,7 @@ static int get_file(jz_context* jz, mtar_t* tar, const char* file, | |||
73 | return JZ_ERR_BAD_FILE_FORMAT; | 132 | return JZ_ERR_BAD_FILE_FORMAT; |
74 | } | 133 | } |
75 | 134 | ||
76 | if(decompress) { | 135 | if(flags & F_DECOMPRESS) { |
77 | uint32_t dst_len; | 136 | uint32_t dst_len; |
78 | jz_buffer* nbuf = jz_ucl_unpack(buffer->data, buffer->size, &dst_len); | 137 | jz_buffer* nbuf = jz_ucl_unpack(buffer->data, buffer->size, &dst_len); |
79 | jz_buffer_free(buffer); | 138 | jz_buffer_free(buffer); |
@@ -139,9 +198,27 @@ int jz_x1000_boot(jz_usbdev* dev, jz_device_type type, const char* filename) | |||
139 | if(rc != JZ_SUCCESS) | 198 | if(rc != JZ_SUCCESS) |
140 | goto error; | 199 | goto error; |
141 | 200 | ||
142 | rc = get_file(dev->jz, &tar, "bootloader.ucl", true, &bootloader); | 201 | /* - A bootloader2.ucl binary should carry the LOAD header to define its |
143 | if(rc != JZ_SUCCESS) | 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 | goto error; | 220 | goto error; |
221 | } | ||
145 | 222 | ||
146 | rc = get_file(dev->jz, &tar, "bootloader-info.txt", false, &info_file); | 223 | rc = get_file(dev->jz, &tar, "bootloader-info.txt", false, &info_file); |
147 | if(rc != JZ_SUCCESS) | 224 | if(rc != JZ_SUCCESS) |