-
Notifications
You must be signed in to change notification settings - Fork 25
/
profile.h
562 lines (463 loc) · 14 KB
/
profile.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
/**
* bcm2-utils
* Copyright (C) 2016 Joseph C. Lehner <[email protected]>
*
* bcm2-utils is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* bcm2-utils is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with bcm2-utils. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef BCM2UTILS_PROFILE_H
#define BCM2UTILS_PROFILE_H
#include <stdbool.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include "asmdef.h"
#define BCM2_PATCH_NUM 4
#define BCM2_INTF_NUM 2
#ifdef __cplusplus
#include <string>
#include <vector>
#include <memory>
#include <map>
extern "C" {
#endif
enum bcm2_cfg_flags
{
BCM2_CFG_ENC_MASK = 0x0f,
BCM2_CFG_ENC_NONE = 0,
BCM2_CFG_ENC_AES256_ECB = 1,
BCM2_CFG_ENC_3DES_ECB = 2,
BCM2_CFG_ENC_MOTOROLA = 3,
BCM2_CFG_ENC_SUB_16x16 = 4,
BCM2_CFG_ENC_XOR = 5,
BCM2_CFG_ENC_DES_ECB = 6,
BCM2_CFG_ENC_AES128_CBC = 7,
BCM2_CFG_PAD_MASK = 0xf0,
BCM2_CFG_PAD_ANSI_X9_23 = 1 << 4,
BCM2_CFG_PAD_PKCS7 = 2 << 4,
BCM2_CFG_PAD_ZEROBLK = 3 << 4,
// similar to ANSI X9.23, but the last byte
// is the padding length, minus one. assuming
// a block size of 8 bytes, and data length of
// 9 bytes, the 7 padding bytes would be
//
// 00 00 00 00 00 00 06
//
BCM2_CFG_PAD_ANSI_ISH = 4 << 4,
BCM2_CFG_PAD_ZERO = 5 << 4,
BCM2_CFG_FMT_MASK = 0xf00,
BCM2_CFG_FMT_GWS_DYNNV = 1 << 8,
BCM2_CFG_FMT_GWS_FULL_ENC = 1 << 9,
BCM2_CFG_FMT_GWS_PAD_OPTIONAL = 1 << 10,
// prepend data length
BCM2_CFG_FMT_GWS_LEN_PREFIX = 1 << 11,
BCM2_CFG_FMT_GWS_CLEN_PREFIX = 1 << 12,
BCM2_CFG_DATA_MASK = 0xf0000,
BCM2_CFG_DATA_USERIF_ALT = 1 << 16,
BCM2_CFG_DATA_USERIF_ALT_SHORT = 1 << 17,
BCM2_CFG_DATA_USERIF_ALT_2 = 1 << 18,
};
enum bcm2_interface
{
BCM2_INTF_NONE = 0,
BCM2_INTF_ALL = ~0,
BCM2_INTF_BLDR = 2,
BCM2_INTF_BFC = 3
};
enum bcm2_mem
{
BCM2_MEM_NONE = 0,
BCM2_MEM_R = 1,
BCM2_MEM_RW = 2
};
enum bcm2_arch
{
BCM2_UNKNOWN = 0,
BCM2_3345 = 0x3345,
BCM2_3368 = 0x3368,
BCM2_3380 = 0x3380,
BCM2_3382 = 0x3382,
BCM2_338221 = 0x338221,
BCM2_3383 = 0x3383,
BCM2_3384 = 0x3384,
BCM2_33843 = 0x33843,
BCM2_3390 = 0x3390,
};
struct bcm2_partition {
// partition name
char name[32];
// offset (absolute, not relative
// to address space begin)
uint32_t offset;
// size
uint32_t size;
// internal partition name (for BFC `/flash/open`)
char altname[32];
};
struct bcm2_patch {
// patch this address...
uint32_t addr;
// ... with this word
uint32_t word;
} __attribute__((packed));
struct bcm2_func {
// address of this function
uint32_t addr;
// mode of this function. interpretation
// depends on actual function.
uint32_t mode;
// patches to be applied to the bootloader
// before using this function.
struct bcm2_patch patch[BCM2_PATCH_NUM];
// return value type
int retv;
// interface(s) this function is valid for
int intf;
};
struct bcm2_addrspace {
// short name to identify the address space. if a
// device has only one flash chip, name it "flash".
// if it has an spi/nand combo, name the spi device
// "nvram", and the nand "flash". always define at
// least one address space called "ram".
char name[16];
// used for memory mapped address space. ignored
// for address spaces named "ram".
enum bcm2_mem mem;
// combination of interface ids from bcm2_interface;
// 0 means all interfaces supported
int intf;
// minimum offset of this address space
uint32_t min;
// size of this address space. can be 0 to disable size
// check
uint32_t size;
// eraseblock size, for flash
uint32_t blocksize;
// 0 = automatic (4 for memory, 1 for everything else)
unsigned alignment;
// partitions within this address space
struct bcm2_partition parts[32];
// read functions to read from this address space (can
// be left blank for ram segment)
struct bcm2_func read[BCM2_INTF_NUM];
// not yet used
struct bcm2_func write[BCM2_INTF_NUM];
// not yet used
struct bcm2_func erase[BCM2_INTF_NUM];
};
struct bcm2_magic {
uint32_t addr;
char data[32];
uint8_t size;
};
struct bcm2_version_addrspace
{
char name[16];
struct bcm2_func open;
struct bcm2_func read;
struct bcm2_func write;
struct bcm2_func erase;
struct bcm2_func close;
};
enum bcm2_type
{
BCM2_TYPE_U32 = 0,
BCM2_TYPE_STR = 1,
BCM2_TYPE_BOOL = BCM2_TYPE_U32,
BCM2_TYPE_NIL = 9,
};
struct bcm2_typed_val
{
char name[32];
union {
uint32_t n;
char s[32];
} val;
enum bcm2_type type;
};
#define BCM2_VAL_U32(name, val) BCM2_TYPED_VAL(name, n, val, BCM2_TYPE_U32)
#define BCM2_VAL_STR(name, str) BCM2_TYPED_VAL(name, s, str, BCM2_TYPE_STR)
#define BCM2_TYPED_VAL(a_name, a_dest, a_val, a_type) \
{ .name = (a_name), .val = { .a_dest = (a_val) }, .type = a_type }
struct bcm2_version {
char version[16];
int intf;
struct bcm2_magic magic;
// address where dump code can be loaded (dump code
// is short, currently around 512 bytes)
uint32_t rwcode;
// location in memory where we can store read images
uint32_t buffer;
// length of buffer (if 0, buffer will be checked
// against "ram" address space)
uint32_t buflen;
// address of a function that behaves like printf:
// printf a0 = format string, a1...aX format args
uint32_t printf;
// address of a function that behaves like scanf:
// a0 = format, a1...aX = args
uint32_t scanf;
// address of a sscanf-like function
// a0 = str, a1 = format, a2...aX = args
uint32_t sscanf;
// address of a getline-like function, minus the stream:
// a0 = buffer, a1 = size
uint32_t getline;
struct bcm2_version_addrspace spaces[8];
struct bcm2_typed_val options[8];
};
struct bcm2_profile {
// short name that is used to select a profile
char name[16];
// pretty device name
char pretty[64];
// little endian MIPS (not supported at the moment)
bool mipsel;
// architecture
enum bcm2_arch arch;
// signature for ProgramStore images
uint16_t pssig;
// signature for compressed bootloader images
uint16_t blsig;
// baudrate of the bootloader console
uint32_t baudrate;
// address mask for uncached mips segment
uint32_t kseg1mask;
// a location in memory with a constant value (ideally a
// bootloader string), which can be used to automatically
// identify the connected device
struct bcm2_magic magic[BCM2_INTF_NUM];
// settings regarding the config dump format
uint32_t cfg_flags;
// a key that is appended to the configuration file data
// before calculating its checksum. specify as a hex string
char cfg_md5key[65];
// default encryption keys for backups without a password
char cfg_defkeys[8][65];
// key derivation function for encrypted configuration files.
// return false if key derivation failed.
bool (*cfg_keyfun)(const char *password, unsigned char *key, size_t size);
// address spaces that can be dumped
struct bcm2_typed_val options[8];
struct bcm2_addrspace spaces[8];
struct bcm2_version versions[8];
};
extern struct bcm2_profile bcm2_profiles[];
struct bcm2_profile *bcm2_profile_find(const char *name);
struct bcm2_addrspace *bcm2_profile_find_addrspace(
struct bcm2_profile *profile, const char *name);
struct bcm2_partition *bcm2_addrspace_find_partition(
struct bcm2_addrspace *addrspace, const char *name);
#ifdef __cplusplus
}
namespace bcm2dump {
class func
{
public:
func(uint32_t addr = 0, uint32_t args = 0, uint32_t intf = 0, uint32_t retv = 0)
: m_addr(addr), m_args(args), m_intf(intf), m_retv(retv) {}
uint32_t addr() const
{ return m_addr; }
uint32_t args() const
{ return m_args; }
uint32_t intf() const
{ return m_intf; }
uint32_t retv() const
{ return m_retv; }
const std::vector<const bcm2_patch*>& patches() const
{ return m_patches; }
std::vector<const bcm2_patch*>& patches()
{ return m_patches; }
private:
uint32_t m_addr;
uint32_t m_args;
uint32_t m_intf;
uint32_t m_retv;
std::vector<const bcm2_patch*> m_patches;
};
class profile;
class version
{
public:
typedef std::map<std::string, uint32_t> u32map;
typedef std::map<std::string, func> funcmap;
version()
: m_p(nullptr), m_prof(nullptr), m_def(nullptr)
{}
version(const bcm2_version* v, const profile* p, const bcm2_version* def)
: m_p(v), m_prof(p), m_def(def ? def : v)
{
parse_codecfg();
parse_functions();
}
std::string name() const
{ return m_p ? (m_p->version[0] ? m_p->version : "any") : ""; }
int intf() const
{ return m_p->intf; }
const bcm2_magic* magic() const
{ return &m_p->magic; }
u32map codecfg() const
{ return m_codecfg; }
uint32_t codecfg(const std::string& str) const
{
auto iter = m_codecfg.find(str);
return iter != m_codecfg.end() ? iter->second : 0;
}
funcmap functions(const std::string& space) const
{
auto iter = m_functions.find(space);
return iter != m_functions.end() ? iter->second : funcmap();
}
bool has_opt(const std::string& name) const
{ return get_opt(name, BCM2_TYPE_NIL); }
uint32_t get_opt_num(const std::string& name) const
{ return get_opt(name, BCM2_TYPE_U32)->val.n; }
uint32_t get_opt_num(const std::string& name, uint32_t def) const
{ return has_opt(name) ? get_opt_num(name) : def; }
std::string get_opt_str(const std::string& name) const
{ return get_opt(name, BCM2_TYPE_STR)->val.s; }
std::string get_opt_str(const std::string& name, const std::string& def) const
{ return has_opt(name) ? get_opt_str(name) : def; }
const bcm2_version* raw() const
{ return m_p; }
private:
void parse_codecfg();
void parse_functions();
const bcm2_typed_val* get_opt(const std::string& name, bcm2_type type) const;
const bcm2_version* m_p;
const profile* m_prof;
const bcm2_version* m_def;
u32map m_codecfg;
std::map<std::string, funcmap> m_functions;
};
class addrspace
{
public:
class part
{
public:
friend class addrspace;
part() : m_p(nullptr) {}
std::string name() const
{ return m_p ? m_p->name : ""; }
uint32_t offset() const
{ return m_p->offset; }
uint32_t size() const
{ return m_p->size; }
uint32_t end() const
{ return offset() + size(); }
std::string altname() const
{ return m_p->altname[0] ? m_p->altname : name(); }
private:
part(const bcm2_partition* p) : m_p(p) {}
const bcm2_partition* m_p;
};
addrspace(const bcm2_addrspace* a, const profile& p);
addrspace() {}
std::string name() const
{ return m_p->name; }
bool is_mem() const
{ return m_p->mem || is_ram(); }
bool is_ram() const
{ return name() == "ram"; }
bool is_writable() const
{ return is_ram() || m_p->mem == BCM2_MEM_RW; }
int interfaces() const
{ return m_p->intf; }
uint32_t min() const
{ return m_p->min; }
uint32_t end() const
{ return m_p->min + m_size; }
uint32_t size() const
{ return m_size; }
unsigned alignment() const
{ return !m_p->alignment ? (is_mem() ? 4 : 1) : m_p->alignment; }
const std::vector<part>& partitions() const
{ return m_partitions; }
const part& partition(const std::string& name) const;
const part& partition(uint32_t offset) const;
func get_read_func(bcm2_interface intf) const;
func get_write_func(bcm2_interface intf) const;
func get_erase_func(bcm2_interface intf) const;
bool check_offset(uint32_t offset, bool exception = true) const
{ return check_range(offset, 0, "", exception); }
uint32_t check_offset(uint32_t offset, const std::string& name) const
{
check_range(offset, 0, name, true);
return offset;
}
uint32_t check_offset(uint32_t offset, const char* name) const
{
return check_offset(offset, std::string(name));
}
bool check_range(uint32_t offset, uint32_t length, bool exception = true) const
{ return check_range(offset, length, "", exception); }
void check_range(uint32_t offset, uint32_t length, const char* name) const
{ check_range(offset, length, name, true); }
void check_range(uint32_t offset, uint32_t length, const std::string& name) const
{ check_range(offset, length, name, true); }
private:
bool check_range(uint32_t offset, uint32_t length, const std::string& name, bool exception) const;
const bcm2_addrspace* m_p = nullptr;
uint32_t m_size = 0;
uint32_t m_kseg1 = 0;
std::string m_profile_name;
std::vector<part> m_partitions;
std::vector<func> m_read_funcs;
std::vector<func> m_write_funcs;
std::vector<func> m_erase_funcs;
};
class profile
{
public:
typedef std::shared_ptr<profile> sp;
virtual ~profile() {}
virtual std::string name() const = 0;
virtual std::string pretty() const = 0;
virtual bool mipsel() const = 0;
virtual unsigned baudrate() const = 0;
virtual uint16_t pssig() const = 0;
virtual uint16_t blsig() const = 0;
virtual uint32_t kseg1() const = 0;
virtual std::vector<const bcm2_magic*> magics() const = 0;
virtual std::vector<version> versions() const = 0;
virtual const version& default_version(int intf) const = 0;
virtual std::vector<addrspace> spaces() const = 0;
virtual const addrspace& space(const std::string& name, bcm2_interface intf) const = 0;
virtual const addrspace& ram() const = 0;
virtual bcm2_arch arch() const = 0;
virtual std::string md5_key() const = 0;
virtual uint32_t cfg_encryption() const = 0;
virtual uint32_t cfg_padding() const = 0;
virtual uint32_t cfg_flags() const = 0;
//virtual std::string encrypt(const std::string& buf, const std::string& key) = 0;
//virtual std::string decrypt(const std::string& buf, const std::string& key) = 0;
virtual std::vector<std::string> default_keys() const = 0;
virtual std::string derive_key(const std::string& pw) const = 0;
void print_to_stdout(bool verbose = false) const;
static const sp& get(const std::string& name);
static const std::vector<profile::sp>& list();
static void parse_opt_override(const std::string& str);
friend class version;
private:
static std::vector<profile::sp> s_profiles;
static std::map<std::string, bcm2_typed_val> s_overrides;
};
uint32_t magic_size(const bcm2_magic* magic);
std::string magic_data(const bcm2_magic* magic);
std::string get_profile_names(unsigned width, unsigned indent);
}
#endif
#endif