summaryrefslogtreecommitdiff
path: root/tools/mkspl-x1000.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/mkspl-x1000.c')
-rw-r--r--tools/mkspl-x1000.c248
1 files changed, 248 insertions, 0 deletions
diff --git a/tools/mkspl-x1000.c b/tools/mkspl-x1000.c
new file mode 100644
index 0000000000..e27fe8e25b
--- /dev/null
+++ b/tools/mkspl-x1000.c
@@ -0,0 +1,248 @@
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 <stddef.h>
23#include <stdint.h>
24#include <stdio.h>
25#include <string.h>
26#include <stdarg.h>
27#include <stdlib.h>
28#include <endian.h> /* TODO: find portable alternative */
29
30#define SPL_HEADER_SIZE 512
31#define SPL_KEY_SIZE 1536
32#define SPL_CODE_OFFSET (SPL_HEADER_SIZE + SPL_KEY_SIZE)
33
34#define SPL_MAX_SIZE (12 * 1024)
35#define SPL_CODE_SIZE (SPL_MAX_SIZE - SPL_CODE_OFFSET)
36
37#define FLASH_TYPE_NAND 0x00
38#define FLASH_TYPE_NOR 0xaa
39
40struct flash_sig {
41 uint8_t magic[8]; /* fixed magic bytes */
42 uint8_t type; /* flash type, either NAND or NOR */
43 uint8_t crc7; /* CRC7 of SPL code */
44 uint8_t ppb; /* pages per block for NAND */
45 uint8_t bpp; /* bytes per page for NAND */
46 uint32_t length; /* total size of SPL, including header/key */
47};
48
49static const uint8_t flash_sig_magic[8] =
50 {0x06, 0x05, 0x04, 0x03, 0x02, 0x55, 0xaa, 0x55};
51
52/* calculate CRC7 used in flash header */
53uint8_t crc7(const uint8_t* buf, size_t len)
54{
55 /* table-based computation of CRC7 */
56 static const uint8_t t[256] = {
57 0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f,
58 0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77,
59 0x19, 0x10, 0x0b, 0x02, 0x3d, 0x34, 0x2f, 0x26,
60 0x51, 0x58, 0x43, 0x4a, 0x75, 0x7c, 0x67, 0x6e,
61 0x32, 0x3b, 0x20, 0x29, 0x16, 0x1f, 0x04, 0x0d,
62 0x7a, 0x73, 0x68, 0x61, 0x5e, 0x57, 0x4c, 0x45,
63 0x2b, 0x22, 0x39, 0x30, 0x0f, 0x06, 0x1d, 0x14,
64 0x63, 0x6a, 0x71, 0x78, 0x47, 0x4e, 0x55, 0x5c,
65 0x64, 0x6d, 0x76, 0x7f, 0x40, 0x49, 0x52, 0x5b,
66 0x2c, 0x25, 0x3e, 0x37, 0x08, 0x01, 0x1a, 0x13,
67 0x7d, 0x74, 0x6f, 0x66, 0x59, 0x50, 0x4b, 0x42,
68 0x35, 0x3c, 0x27, 0x2e, 0x11, 0x18, 0x03, 0x0a,
69 0x56, 0x5f, 0x44, 0x4d, 0x72, 0x7b, 0x60, 0x69,
70 0x1e, 0x17, 0x0c, 0x05, 0x3a, 0x33, 0x28, 0x21,
71 0x4f, 0x46, 0x5d, 0x54, 0x6b, 0x62, 0x79, 0x70,
72 0x07, 0x0e, 0x15, 0x1c, 0x23, 0x2a, 0x31, 0x38,
73 0x41, 0x48, 0x53, 0x5a, 0x65, 0x6c, 0x77, 0x7e,
74 0x09, 0x00, 0x1b, 0x12, 0x2d, 0x24, 0x3f, 0x36,
75 0x58, 0x51, 0x4a, 0x43, 0x7c, 0x75, 0x6e, 0x67,
76 0x10, 0x19, 0x02, 0x0b, 0x34, 0x3d, 0x26, 0x2f,
77 0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c,
78 0x3b, 0x32, 0x29, 0x20, 0x1f, 0x16, 0x0d, 0x04,
79 0x6a, 0x63, 0x78, 0x71, 0x4e, 0x47, 0x5c, 0x55,
80 0x22, 0x2b, 0x30, 0x39, 0x06, 0x0f, 0x14, 0x1d,
81 0x25, 0x2c, 0x37, 0x3e, 0x01, 0x08, 0x13, 0x1a,
82 0x6d, 0x64, 0x7f, 0x76, 0x49, 0x40, 0x5b, 0x52,
83 0x3c, 0x35, 0x2e, 0x27, 0x18, 0x11, 0x0a, 0x03,
84 0x74, 0x7d, 0x66, 0x6f, 0x50, 0x59, 0x42, 0x4b,
85 0x17, 0x1e, 0x05, 0x0c, 0x33, 0x3a, 0x21, 0x28,
86 0x5f, 0x56, 0x4d, 0x44, 0x7b, 0x72, 0x69, 0x60,
87 0x0e, 0x07, 0x1c, 0x15, 0x2a, 0x23, 0x38, 0x31,
88 0x46, 0x4f, 0x54, 0x5d, 0x62, 0x6b, 0x70, 0x79
89 };
90
91 uint8_t crc = 0;
92 while(len--)
93 crc = t[(crc << 1) ^ *buf++];
94 return crc;
95}
96
97void die(const char* msg, ...)
98{
99 va_list ap;
100 va_start(ap, msg);
101 vfprintf(stderr, msg, ap);
102 fprintf(stderr, "\n");
103 va_end(ap);
104 exit(1);
105}
106
107void do_flash(const uint8_t* spl_code,
108 uint32_t spl_length,
109 int flash_type,
110 int pages_per_block,
111 int bytes_per_block,
112 FILE* outfile)
113{
114 /* verify parameters */
115 if(flash_type != FLASH_TYPE_NAND
116 && flash_type != FLASH_TYPE_NOR) {
117 die("invalid flash type");
118 }
119
120 if(pages_per_block < 0 || pages_per_block > 0xff)
121 die("invalid pages_per_block");
122
123 if(bytes_per_block < 0 || bytes_per_block > 0xff)
124 die("invalid bytes_per_block");
125
126 /* fill flash signature */
127 struct flash_sig sig;
128 memcpy(sig.magic, flash_sig_magic, 8);
129 sig.type = flash_type & 0xff;
130 sig.crc7 = crc7(spl_code, spl_length);
131 sig.ppb = pages_per_block & 0xff;
132 sig.bpp = bytes_per_block & 0xff;
133 sig.length = htole32(spl_length + SPL_HEADER_SIZE + SPL_KEY_SIZE);
134
135 /* construct header */
136 uint8_t hdr_buf[SPL_HEADER_SIZE];
137 memset(hdr_buf, 0, SPL_HEADER_SIZE);
138 memcpy(hdr_buf, &sig, sizeof(sig));
139 hdr_buf[sizeof(sig)] = 1; /* ??? used in the FiiO M3K */
140
141 /* create null key */
142 uint8_t null_key[SPL_KEY_SIZE];
143 memset(null_key, 0, SPL_KEY_SIZE);
144
145 /* write everything out */
146 if(fwrite(hdr_buf, SPL_HEADER_SIZE, 1, outfile) != 1)
147 die("error writing output");
148 if(fwrite(null_key, SPL_KEY_SIZE, 1, outfile) != 1)
149 die("error writing output");
150 if(fwrite(spl_code, spl_length, 1, outfile) != 1)
151 die("error writing output");
152}
153
154uint8_t* read_input(const char* filename, uint32_t* rlength, int maxlen)
155{
156 /* open file */
157 FILE* f = fopen(filename, "rb");
158 if(!f)
159 die("cannot open input file: %s", filename);
160
161 /* get size */
162 fseek(f, 0, SEEK_END);
163 int sz = ftell(f);
164
165 /* check size */
166 if(sz < 0)
167 die("error seeking in input file");
168 if(sz > maxlen)
169 die("input is too big (size: %d, max: %d)", sz, maxlen);
170
171 /* allocate buffer */
172 uint8_t* buf = malloc(sz);
173 if(!buf)
174 die("out of memory");
175
176 /* read file data */
177 fseek(f, 0, SEEK_SET);
178 if(fread(buf, sz, 1, f) != 1)
179 die("error reading input file");
180
181 /* close file */
182 fclose(f);
183
184 /* return buffer and size */
185 *rlength = sz;
186 return buf;
187}
188
189int main(int argc, const char* argv[])
190{
191 /* variables */
192 int flash_type = -1;
193 int pages_per_block = -1;
194 int bytes_per_page = -1;
195 uint8_t* spl_code = NULL;
196 uint32_t spl_length = 0;
197 const char* outfile_name = NULL;
198
199 for(int i = 1; i < argc; ++i) {
200 if(strncmp(argv[i], "-type=", 6) == 0) {
201 if(strcmp(argv[i]+6, "nand") == 0)
202 flash_type = FLASH_TYPE_NAND;
203 else if(strcmp(argv[i]+6, "nor") == 0)
204 flash_type = FLASH_TYPE_NOR;
205 else
206 die("invalid type: %s", argv[i]+6);
207 } else if(strncmp(argv[i], "-ppb=", 5) == 0) {
208 pages_per_block = atoi(argv[i]+5);
209 } else if(strncmp(argv[i], "-bpp=", 5) == 0) {
210 bytes_per_page = atoi(argv[i]+5);
211 } else if(spl_code == NULL) {
212 spl_code = read_input(argv[i], &spl_length, SPL_CODE_SIZE);
213 } else if(!outfile_name) {
214 outfile_name = argv[i];
215 } else {
216 die("too many arguments: %s", argv[i]);
217 }
218 }
219
220 if(flash_type < 0)
221 die("must specify -type");
222
223 if(flash_type == FLASH_TYPE_NAND) {
224 if(pages_per_block < 0)
225 die("must specify -ppb with -type nand");
226 if(bytes_per_page < 0)
227 die("must specify -bpp with -type nand");
228 } else {
229 pages_per_block = 0;
230 bytes_per_page = 0;
231 }
232
233 if(spl_code == NULL)
234 die("no input file given");
235
236 if(!outfile_name)
237 die("no output file given");
238
239 FILE* outfile = fopen(outfile_name, "wb");
240 if(!outfile)
241 die("cannot open output file: %s", outfile_name);
242
243 do_flash(spl_code, spl_length, flash_type,
244 pages_per_block, bytes_per_page, outfile);
245
246 fclose(outfile);
247 return 0;
248}