diff options
author | Dominik Riebeling <Dominik.Riebeling@gmail.com> | 2021-12-15 21:04:28 +0100 |
---|---|---|
committer | Dominik Riebeling <Dominik.Riebeling@gmail.com> | 2021-12-24 18:05:53 +0100 |
commit | c876d3bbefe0dc00c27ca0c12d29da5874946962 (patch) | |
tree | 69f468a185a369b01998314bc3ecc19b70f4fcaa /utils/jztool/src/x1000.c | |
parent | 6c6f0757d7a902feb293be165d1490c42bc8e7ad (diff) | |
download | rockbox-c876d3bbefe0dc00c27ca0c12d29da5874946962.tar.gz rockbox-c876d3bbefe0dc00c27ca0c12d29da5874946962.zip |
rbutil: Merge rbutil with utils folder.
rbutil uses several components from the utils folder, and can be
considered part of utils too. Having it in a separate folder is an
arbitrary split that doesn't help anymore these days, so merge them.
This also allows other utils to easily use libtools.make without the
need to navigate to a different folder.
Change-Id: I3fc2f4de19e3e776553efb5dea5f779dfec0dc21
Diffstat (limited to 'utils/jztool/src/x1000.c')
-rw-r--r-- | utils/jztool/src/x1000.c | 180 |
1 files changed, 180 insertions, 0 deletions
diff --git a/utils/jztool/src/x1000.c b/utils/jztool/src/x1000.c new file mode 100644 index 0000000000..f59727a2ca --- /dev/null +++ b/utils/jztool/src/x1000.c | |||
@@ -0,0 +1,180 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2021 Aidan MacDonald | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | #include "jztool.h" | ||
23 | #include "jztool_private.h" | ||
24 | #include "microtar-stdio.h" | ||
25 | #include <stdbool.h> | ||
26 | #include <string.h> | ||
27 | |||
28 | /* TODO: these functions could be refactored to be CPU-agnostic */ | ||
29 | static int run_stage1(jz_usbdev* dev, jz_buffer* buf) | ||
30 | { | ||
31 | int rc = jz_usb_send(dev, 0xf4001000, buf->size, buf->data); | ||
32 | if(rc < 0) | ||
33 | return rc; | ||
34 | |||
35 | return jz_usb_start1(dev, 0xf4001800); | ||
36 | } | ||
37 | |||
38 | static int run_stage2(jz_usbdev* dev, jz_buffer* buf) | ||
39 | { | ||
40 | int rc = jz_usb_send(dev, 0x80004000, buf->size, buf->data); | ||
41 | if(rc < 0) | ||
42 | return rc; | ||
43 | |||
44 | rc = jz_usb_flush_caches(dev); | ||
45 | if(rc < 0) | ||
46 | return rc; | ||
47 | |||
48 | return jz_usb_start2(dev, 0x80004000); | ||
49 | } | ||
50 | |||
51 | static int get_file(jz_context* jz, mtar_t* tar, const char* file, | ||
52 | bool decompress, jz_buffer** buf) | ||
53 | { | ||
54 | jz_buffer* buffer = NULL; | ||
55 | const mtar_header_t* h; | ||
56 | int rc; | ||
57 | |||
58 | rc = mtar_find(tar, file); | ||
59 | 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; | ||
62 | } | ||
63 | |||
64 | h = mtar_get_header(tar); | ||
65 | buffer = jz_buffer_alloc(h->size, NULL); | ||
66 | if(!buffer) | ||
67 | return JZ_ERR_OUT_OF_MEMORY; | ||
68 | |||
69 | rc = mtar_read_data(tar, buffer->data, buffer->size); | ||
70 | if(rc < 0 || (unsigned)rc != buffer->size) { | ||
71 | jz_buffer_free(buffer); | ||
72 | jz_log(jz, JZ_LOG_ERROR, "can't read %s in boot file, tar error %d", file, rc); | ||
73 | return JZ_ERR_BAD_FILE_FORMAT; | ||
74 | } | ||
75 | |||
76 | if(decompress) { | ||
77 | uint32_t dst_len; | ||
78 | jz_buffer* nbuf = jz_ucl_unpack(buffer->data, buffer->size, &dst_len); | ||
79 | jz_buffer_free(buffer); | ||
80 | if(!nbuf) { | ||
81 | jz_log(jz, JZ_LOG_ERROR, "error decompressing %s in boot file", file); | ||
82 | return JZ_ERR_BAD_FILE_FORMAT; | ||
83 | } | ||
84 | |||
85 | /* for simplicity just forget original size of buffer */ | ||
86 | nbuf->size = dst_len; | ||
87 | buffer = nbuf; | ||
88 | } | ||
89 | |||
90 | *buf = buffer; | ||
91 | return JZ_SUCCESS; | ||
92 | } | ||
93 | |||
94 | static int show_version(jz_context* jz, jz_buffer* info_file) | ||
95 | { | ||
96 | /* Extract the version string and log it for informational purposes */ | ||
97 | char* boot_version = (char*)info_file->data; | ||
98 | char* endpos = memchr(boot_version, '\n', info_file->size); | ||
99 | if(!endpos) { | ||
100 | jz_log(jz, JZ_LOG_ERROR, "invalid metadata in boot file"); | ||
101 | return JZ_ERR_BAD_FILE_FORMAT; | ||
102 | } | ||
103 | |||
104 | *endpos = 0; | ||
105 | jz_log(jz, JZ_LOG_NOTICE, "Rockbox bootloader version: %s", boot_version); | ||
106 | return JZ_SUCCESS; | ||
107 | } | ||
108 | |||
109 | /** \brief Load the Rockbox bootloader on an X1000 device | ||
110 | * \param dev USB device freshly returned by jz_usb_open() | ||
111 | * \param filename Path to the "bootloader.target" file | ||
112 | * \return either JZ_SUCCESS or an error code | ||
113 | */ | ||
114 | int jz_x1000_boot(jz_usbdev* dev, jz_device_type type, const char* filename) | ||
115 | { | ||
116 | const jz_device_info* dev_info; | ||
117 | char spl_filename[32]; | ||
118 | jz_buffer* spl = NULL, *bootloader = NULL, *info_file = NULL; | ||
119 | mtar_t tar; | ||
120 | int rc; | ||
121 | |||
122 | /* In retrospect using a model-dependent archive format was not a good | ||
123 | * idea, but it's not worth fixing just yet... */ | ||
124 | dev_info = jz_get_device_info(type); | ||
125 | if(!dev_info) | ||
126 | return JZ_ERR_OTHER; | ||
127 | /* use of sprintf is safe since file_ext is short */ | ||
128 | sprintf(spl_filename, "spl.%s", dev_info->file_ext); | ||
129 | |||
130 | /* Now open the archive */ | ||
131 | rc = mtar_open(&tar, filename, "rb"); | ||
132 | if(rc != MTAR_ESUCCESS) { | ||
133 | jz_log(dev->jz, JZ_LOG_ERROR, "cannot open file %s (tar error: %d)", filename, rc); | ||
134 | return JZ_ERR_OPEN_FILE; | ||
135 | } | ||
136 | |||
137 | /* Extract all necessary files */ | ||
138 | rc = get_file(dev->jz, &tar, spl_filename, false, &spl); | ||
139 | if(rc != JZ_SUCCESS) | ||
140 | goto error; | ||
141 | |||
142 | rc = get_file(dev->jz, &tar, "bootloader.ucl", true, &bootloader); | ||
143 | if(rc != JZ_SUCCESS) | ||
144 | goto error; | ||
145 | |||
146 | rc = get_file(dev->jz, &tar, "bootloader-info.txt", false, &info_file); | ||
147 | if(rc != JZ_SUCCESS) | ||
148 | goto error; | ||
149 | |||
150 | /* Display the version string */ | ||
151 | rc = show_version(dev->jz, info_file); | ||
152 | if(rc != JZ_SUCCESS) | ||
153 | goto error; | ||
154 | |||
155 | /* Stage1 boot of SPL to set up hardware */ | ||
156 | rc = run_stage1(dev, spl); | ||
157 | if(rc != JZ_SUCCESS) | ||
158 | goto error; | ||
159 | |||
160 | /* Need a bit of time for SPL to handle init */ | ||
161 | jz_sleepms(500); | ||
162 | |||
163 | /* Stage2 boot into the bootloader's recovery menu | ||
164 | * User has to take manual action from there */ | ||
165 | rc = run_stage2(dev, bootloader); | ||
166 | if(rc != JZ_SUCCESS) | ||
167 | goto error; | ||
168 | |||
169 | rc = JZ_SUCCESS; | ||
170 | |||
171 | error: | ||
172 | if(spl) | ||
173 | jz_buffer_free(spl); | ||
174 | if(bootloader) | ||
175 | jz_buffer_free(bootloader); | ||
176 | if(info_file) | ||
177 | jz_buffer_free(info_file); | ||
178 | mtar_close(&tar); | ||
179 | return rc; | ||
180 | } | ||