summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAidan MacDonald <amachronic@protonmail.com>2022-02-28 22:11:31 +0000
committerAidan MacDonald <amachronic@protonmail.com>2022-03-11 11:15:56 -0500
commitcdee5284d46c913859bcb105bf3ea86bcbd6014f (patch)
treec03b95cbeb3fc81190a9622487bc7d4078520685
parent35242c8d98566da64f0f5210e0f580e7bcdb0365 (diff)
downloadrockbox-cdee5284d4.tar.gz
rockbox-cdee5284d4.zip
jztool: support new binary header on x1000
Change-Id: If0d3fb3d5b03cf6ed87cbbb8a968ef48edb660f7
-rw-r--r--utils/jztool/src/x1000.c99
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 @@
#include <stdbool.h>
#include <string.h>
-/* TODO: these functions could be refactored to be CPU-agnostic */
+#define X1000_TCSM_BASE 0xf4000000
+
+#define X1000_SPL_LOAD_ADDR (X1000_TCSM_BASE + 0x1000)
+#define X1000_SPL_EXEC_ADDR (X1000_TCSM_BASE + 0x1800)
+
+#define X1000_STANDARD_DRAM_BASE 0x80004000
+
+#define HDR_BEGIN 128 /* header must begin within this many bytes */
+#define HDR_LEN 256 /* header length cannot exceed this */
+
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+
+/* search for header value, label must be a 4-character string.
+ * Returns the found value or 0 if the label wasn't found. */
+static uint32_t search_header(const unsigned char* source, size_t length,
+ const char* label)
+{
+ size_t search_len = MIN(length, HDR_BEGIN);
+ if(search_len < 8)
+ return 0;
+ search_len -= 7;
+
+ /* find the beginning marker */
+ size_t i;
+ for(i = 8; i < search_len; i += 4)
+ if(!memcmp(&source[i], "BEGINHDR", 8))
+ break;
+ if(i >= search_len)
+ return 0;
+ i += 8;
+
+ /* search within the header */
+ search_len = MIN(length, i + HDR_LEN) - 7;
+ for(; i < search_len; i += 8) {
+ if(!memcmp(&source[i], "ENDH", 4)) {
+ break;
+ } else if(!memcmp(&source[i], label, 4)) {
+ i += 4;
+ /* read little-endian value */
+ uint32_t ret = source[i];
+ ret |= source[i+1] << 8;
+ ret |= source[i+2] << 16;
+ ret |= source[i+3] << 24;
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
static int run_stage1(jz_usbdev* dev, jz_buffer* buf)
{
- int rc = jz_usb_send(dev, 0xf4001000, buf->size, buf->data);
+ int rc = jz_usb_send(dev, X1000_SPL_LOAD_ADDR, buf->size, buf->data);
if(rc < 0)
return rc;
- return jz_usb_start1(dev, 0xf4001800);
+ return jz_usb_start1(dev, X1000_SPL_EXEC_ADDR);
}
static int run_stage2(jz_usbdev* dev, jz_buffer* buf)
{
- int rc = jz_usb_send(dev, 0x80004000, buf->size, buf->data);
+ uint32_t load_addr = search_header(buf->data, buf->size, "LOAD");
+ if(!load_addr)
+ load_addr = X1000_STANDARD_DRAM_BASE;
+
+ int rc = jz_usb_send(dev, load_addr, buf->size, buf->data);
if(rc < 0)
return rc;
@@ -45,11 +98,16 @@ static int run_stage2(jz_usbdev* dev, jz_buffer* buf)
if(rc < 0)
return rc;
- return jz_usb_start2(dev, 0x80004000);
+ return jz_usb_start2(dev, load_addr);
}
+enum {
+ F_DECOMPRESS = 0x01,
+ F_OPTIONAL = 0x02,
+};
+
static int get_file(jz_context* jz, mtar_t* tar, const char* file,
- bool decompress, jz_buffer** buf)
+ unsigned int flags, jz_buffer** buf)
{
jz_buffer* buffer = NULL;
const mtar_header_t* h;
@@ -57,8 +115,9 @@ static int get_file(jz_context* jz, mtar_t* tar, const char* file,
rc = mtar_find(tar, file);
if(rc != MTAR_ESUCCESS) {
- jz_log(jz, JZ_LOG_ERROR, "can't find %s in boot file, tar error %d", file, rc);
- return JZ_ERR_BAD_FILE_FORMAT;
+ if(!(flags & F_OPTIONAL))
+ jz_log(jz, JZ_LOG_ERROR, "can't find %s in boot file, tar error %d", file, rc);
+ return JZ_ERR_OPEN_FILE;
}
h = mtar_get_header(tar);
@@ -73,7 +132,7 @@ static int get_file(jz_context* jz, mtar_t* tar, const char* file,
return JZ_ERR_BAD_FILE_FORMAT;
}
- if(decompress) {
+ if(flags & F_DECOMPRESS) {
uint32_t dst_len;
jz_buffer* nbuf = jz_ucl_unpack(buffer->data, buffer->size, &dst_len);
jz_buffer_free(buffer);
@@ -139,9 +198,27 @@ int jz_x1000_boot(jz_usbdev* dev, jz_device_type type, const char* filename)
if(rc != JZ_SUCCESS)
goto error;
- rc = get_file(dev->jz, &tar, "bootloader.ucl", true, &bootloader);
- if(rc != JZ_SUCCESS)
+ /* - A bootloader2.ucl binary should carry the LOAD header to define its
+ * load address. This name must be used when the load address is not
+ * equal to 0x80004000 to ensure old jztools will not try to load it.
+ *
+ * - The bootloader.ucl name must only be used when the binary loads at
+ * 0x80004000 and can be booted by old versions of jztool.
+ */
+ const char* bl_files[2] = {"bootloader2.ucl", "bootloader.ucl"};
+ for(int i = 0; i < 2; ++i) {
+ rc = get_file(dev->jz, &tar, bl_files[i],
+ F_DECOMPRESS|F_OPTIONAL, &bootloader);
+ if(rc == JZ_SUCCESS)
+ break;
+ else if(rc != JZ_ERR_OPEN_FILE)
+ goto error;
+ }
+
+ if(rc != JZ_SUCCESS) {
+ jz_log(dev->jz, JZ_LOG_ERROR, "no bootloader binary found", filename);
goto error;
+ }
rc = get_file(dev->jz, &tar, "bootloader-info.txt", false, &info_file);
if(rc != JZ_SUCCESS)