summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--utils/nwztools/emmctools/Makefile20
-rw-r--r--utils/nwztools/emmctools/emmctool.c242
-rw-r--r--utils/nwztools/emmctools/misc.c53
-rw-r--r--utils/nwztools/emmctools/misc.h50
-rw-r--r--utils/nwztools/emmctools/nvp.c546
-rw-r--r--utils/nwztools/emmctools/nvp.h93
6 files changed, 1004 insertions, 0 deletions
diff --git a/utils/nwztools/emmctools/Makefile b/utils/nwztools/emmctools/Makefile
new file mode 100644
index 0000000000..953757fdab
--- /dev/null
+++ b/utils/nwztools/emmctools/Makefile
@@ -0,0 +1,20 @@
1DEFINES=
2CC=gcc
3LD=gcc
4CFLAGS=-g -std=c99 -W -Wall $(DEFINES)
5LDFLAGS=
6BINS=emmctool
7
8all: $(BINS)
9
10%.o: %.c
11 $(CC) $(CFLAGS) -c -o $@ $<
12
13emmctool: emmctool.o misc.o nvp.o
14 $(LD) -o $@ $^ $(LDFLAGS)
15
16clean:
17 rm -fr *.o
18
19veryclean:
20 rm -rf $(BINS)
diff --git a/utils/nwztools/emmctools/emmctool.c b/utils/nwztools/emmctools/emmctool.c
new file mode 100644
index 0000000000..8fa7b0907b
--- /dev/null
+++ b/utils/nwztools/emmctools/emmctool.c
@@ -0,0 +1,242 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2012 Amaury Pouly
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#include <stdio.h>
22#include <stdint.h>
23#include <stdbool.h>
24#include <stdlib.h>
25#include <string.h>
26#include <getopt.h>
27#include <stdarg.h>
28#include <ctype.h>
29#include "misc.h"
30#include <sys/stat.h>
31#include <openssl/md5.h>
32#include "nvp.h"
33
34bool g_debug = false;
35char *g_out_prefix = NULL;
36FILE *g_in_file = NULL;
37bool g_force = false;
38
39#define let_the_force_flow(x) do { if(!g_force) return x; } while(0)
40#define continue_the_force(x) if(x) let_the_force_flow(x)
41
42#define check_field(v_exp, v_have, str_ok, str_bad) \
43 if((v_exp) != (v_have)) \
44 { cprintf(RED, str_bad); let_the_force_flow(__LINE__); } \
45 else { cprintf(RED, str_ok); }
46
47#define errorf(...) do { cprintf(GREY, __VA_ARGS__); return __LINE__; } while(0)
48
49static void print_hex(void *p, int size, int unit)
50{
51 uint8_t *p8 = p;
52 uint16_t *p16 = p;
53 uint32_t *p32 = p;
54 for(int i = 0; i < size; i += unit, p8++, p16++, p32++)
55 {
56 if(i != 0 && (i % 16) == 0)
57 printf("\n");
58 if(unit == 1)
59 printf(" %02x", *p8);
60 else if(unit == 2)
61 printf(" %04x", *p16);
62 else
63 printf(" %08x", *p32);
64 }
65}
66
67#define SECTOR 512u
68#define EMMC_MINIBOOT_START 0
69#define EMMC_MINIBOOT_SIZE (8 * SECTOR)
70#define EMMC_UBOOT_START (8 * SECTOR)
71#define EMMC_FU_LINUX_START (512 * SECTOR)
72#define EMMC_LINUX_START (66048 * SECTOR)
73#define EMMC_NVP_START ((512 + 32768) * SECTOR)
74#define EMMC_NVP_SIZE (30720 * SECTOR)
75
76#define print_entry(begin, end, ...) \
77 do{ cprintf(YELLOW, " %08x %08x ", begin, end); cprintf(GREEN, __VA_ARGS__); } while(0)
78
79static int read(uint32_t offset, uint32_t size, void *buf)
80{
81 if(fseek(g_in_file, offset, SEEK_SET))
82 errorf("Cannot seek in file: %m\n");
83 if(fread(buf, size, 1, g_in_file) != 1)
84 errorf("Cannot read in file: %m\n");
85 return 0;
86}
87
88static int nvp_read(uint32_t offset, uint32_t size, void *buf)
89{
90 if(offset + size > EMMC_NVP_SIZE)
91 errorf("nvp read out of nvp area\n");
92 return read(offset + EMMC_NVP_START, size, buf);
93}
94
95// returns size or 0
96static uint32_t do_image(uint32_t start, const char *name)
97{
98 uint32_t size;
99 int ret = read(start, sizeof(size), &size);
100 if(ret) return ret;
101 /* actual uboot size contains 4 bytes for the size, 4 for the crc pad and
102 * must be ronded to the next sector */
103 size = ROUND_UP(size + 8, SECTOR);
104
105 print_entry(start, start + size, name);
106
107 /* Check U-Boot crc (must be 0) */
108 uint32_t crc_buffer[SECTOR / 4];
109 uint32_t crc = 0;
110 uint32_t pos = start + 4;
111 uint32_t rem_size = size - 4;
112 while(rem_size)
113 {
114 ret = read(pos, SECTOR, crc_buffer);
115 if(ret) return ret;
116 uint32_t sz = MIN(rem_size, SECTOR);
117 for(unsigned i = 0; i < sz / 4; i++)
118 crc ^= crc_buffer[i];
119 pos += sz;
120 rem_size -= sz;
121 }
122
123 if(crc == 0)
124 {
125 cprintf(RED, " (CRC Ok)\n");
126 return size;
127 }
128 else
129 {
130 cprintf(RED, " (CRC Mismatch)\n");
131 return 0;
132 }
133}
134
135static int do_emmc(void)
136{
137 cprintf(BLUE, "eMMC map\n");
138 cprintf(RED, " begin end comment\n");
139
140 print_entry(EMMC_MINIBOOT_START, EMMC_MINIBOOT_START + EMMC_MINIBOOT_SIZE, "eMMC Mini Boot\n");
141
142 uint32_t uboot_size = do_image(EMMC_UBOOT_START, "U-Boot");
143 if(!uboot_size)
144 return 1;
145
146 uint32_t fulinux_start = EMMC_UBOOT_START + uboot_size;
147 uint32_t fulinux_size = do_image(fulinux_start, "FU Linux");
148 if(!fulinux_size)
149 return 1;
150
151 uint32_t fu_initrd_size = do_image(EMMC_FU_LINUX_START, "FU initrd");
152 if(!fu_initrd_size)
153 return 1;
154
155 print_entry(EMMC_NVP_START, EMMC_NVP_START + EMMC_NVP_SIZE, "NVP\n");
156
157 uint32_t linux_size = do_image(EMMC_LINUX_START, "Linux");
158 if(!linux_size)
159 return 1;
160
161 int ret = nvp_info();
162 continue_the_force(ret);
163
164 return 0;
165}
166
167static void usage(void)
168{
169 printf("Usage: emmctool [options] img\n");
170 printf("Options:\n");
171 printf(" -o <prefix>\tSet output prefix\n");
172 printf(" -f/--force\tForce to continue on errors\n");
173 printf(" -?/--help\tDisplay this message\n");
174 printf(" -d/--debug\tDisplay debug messages\n");
175 printf(" -c/--no-color\tDisable color output\n");
176 exit(1);
177}
178
179int main(int argc, char **argv)
180{
181 while(1)
182 {
183 static struct option long_options[] =
184 {
185 {"help", no_argument, 0, '?'},
186 {"debug", no_argument, 0, 'd'},
187 {"no-color", no_argument, 0, 'c'},
188 {"force", no_argument, 0, 'f'},
189 {0, 0, 0, 0}
190 };
191
192 int c = getopt_long(argc, argv, "?dcfo:", long_options, NULL);
193 if(c == -1)
194 break;
195 switch(c)
196 {
197 case -1:
198 break;
199 case 'c':
200 enable_color(false);
201 break;
202 case 'd':
203 g_debug = true;
204 break;
205 case 'f':
206 g_force = true;
207 break;
208 case '?':
209 usage();
210 break;
211 case 'o':
212 g_out_prefix = optarg;
213 break;
214 default:
215 abort();
216 }
217 }
218
219 if(argc - optind != 1)
220 {
221 usage();
222 return 1;
223 }
224
225 g_in_file = fopen(argv[optind], "rb");
226 if(g_in_file == NULL)
227 {
228 perror("Cannot open boot file");
229 return 1;
230 }
231
232 int ret = nvp_init(EMMC_NVP_SIZE, &nvp_read, g_debug);
233 if(ret) return ret;
234 ret = do_emmc();
235
236 fclose(g_in_file);
237
238 color(OFF);
239
240 return ret;
241}
242
diff --git a/utils/nwztools/emmctools/misc.c b/utils/nwztools/emmctools/misc.c
new file mode 100644
index 0000000000..108235e7fd
--- /dev/null
+++ b/utils/nwztools/emmctools/misc.c
@@ -0,0 +1,53 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2010 Amaury Pouly
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#include <stdlib.h>
22#include <stdio.h>
23#include <time.h>
24#include <ctype.h>
25#include "misc.h"
26
27char OFF[] = { 0x1b, 0x5b, 0x31, 0x3b, '0', '0', 0x6d, '\0' };
28
29char GREY[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '0', 0x6d, '\0' };
30char RED[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '1', 0x6d, '\0' };
31char GREEN[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '2', 0x6d, '\0' };
32char YELLOW[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '3', 0x6d, '\0' };
33char BLUE[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '4', 0x6d, '\0' };
34
35static bool g_color_enable = true;
36
37void *xmalloc(size_t s)
38{
39 void * r = malloc(s);
40 if(!r) bugp("malloc");
41 return r;
42}
43
44void enable_color(bool enable)
45{
46 g_color_enable = enable;
47}
48
49void color(color_t c)
50{
51 if(g_color_enable)
52 printf("%s", (char *)c);
53}
diff --git a/utils/nwztools/emmctools/misc.h b/utils/nwztools/emmctools/misc.h
new file mode 100644
index 0000000000..035b0ef8c1
--- /dev/null
+++ b/utils/nwztools/emmctools/misc.h
@@ -0,0 +1,50 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2010 Amaury Pouly
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#ifndef __MISC_H__
22#define __MISC_H__
23
24#include <stdbool.h>
25#include <stdio.h>
26
27#define _STR(a) #a
28#define STR(a) _STR(a)
29
30#define bug(...) do { fprintf(stderr,"["__FILE__":"STR(__LINE__)"]ERROR: "__VA_ARGS__); exit(1); } while(0)
31#define bugp(...) do { fprintf(stderr, __VA_ARGS__); perror(" "); exit(1); } while(0)
32
33#define ROUND_UP(val, round) ((((val) + (round) - 1) / (round)) * (round))
34
35typedef char color_t[];
36
37extern color_t OFF, GREY, RED, GREEN, YELLOW, BLUE;
38void *xmalloc(size_t s);
39void color(color_t c);
40void enable_color(bool enable);
41
42#ifndef MIN
43#define MIN(a,b) ((a) < (b) ? (a) : (b))
44#endif
45
46#define cprintf(col, ...) do {color(col); printf(__VA_ARGS__); }while(0)
47
48#define cprintf_field(str1, ...) do{ cprintf(GREEN, str1); cprintf(YELLOW, __VA_ARGS__); }while(0)
49
50#endif /* __MISC_H__ */
diff --git a/utils/nwztools/emmctools/nvp.c b/utils/nwztools/emmctools/nvp.c
new file mode 100644
index 0000000000..46515f74db
--- /dev/null
+++ b/utils/nwztools/emmctools/nvp.c
@@ -0,0 +1,546 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2012 Amaury Pouly
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#include "nvp.h"
22#include <string.h>
23#include <stdlib.h>
24#include <ctype.h>
25
26static struct nvp_zone_info_entry_t nvp_zone_ubt[] =
27{
28 {0x18, 0, 1, 4, 0, 0, 0, 0, "system information"},
29 {0x17, 1, 1, 0x20, 0, 0, 0, 0, "u-boot password"},
30 {9, 2, 1, 4, 0, 0, 0, 0, "firmware update flag"},
31 {0xA, 3, 1, 4, 0, 0, 0, 0, "beep ok flag"},
32 {0x22, 4, 1, 0x10, 0, 0, 0, 0, "rtc alarm"},
33 {0x50, 5, 1, 4, 0, 0, 0, 0, "hold mode"}
34};
35
36static struct nvp_zone_info_entry_t nvp_zone_sys[] =
37{
38 {0x10, 1, 1, 0x40, 0, 0, 0, 0, "model id"},
39 {4, 2, 1, 0x10, 0, 0, 0, 0, "serial number"},
40 {0xB, 3, 1, 0x20, 0, 0, 0, 0, "ship information"},
41 {0x44, 4, 1, 4, 0, 0, 0, 0, "color variation"},
42 {0x1A, 5, 1, 5, 0, 0, 0, 0, "product code"},
43 {0x1D, 6, 1, 8, 0, 0, 0, 0, "update file name"},
44 {0x20, 7, 1, 0x40, 0, 0, 0, 0, "key and signature"},
45 {0x11, 8, 1, 4, 0, 0, 0, 0, "test mode flag"},
46 {0x12, 9, 1, 4, 0, 0, 0, 0, "getty mode flag"},
47 {0x46, 0xA, 1, 4, 0, 0, 0, 0, "disable iptable flag"},
48 {0x1E, 0xB, 1, 0x40, 0, 0, 0, 0, "sound driver parameter"},
49 {0x1F, 0xC, 1, 0x40, 0, 0, 0, 0, "noise cancel driver parameter"},
50 {0x4D, 0xD, 1, 6, 0, 0, 0, 0, "wifi mac address"},
51 {0x4B, 0xE, 1, 4, 0, 0, 0, 0, "wifi protected setup"},
52 {0x52, 0xF, 1, 0x10, 0, 0, 0, 0, "fm parameter"},
53 {0x53, 0x10, 1, 4, 0, 0, 0, 0, "speaker ship info"},
54 {0x54, 0x11, 1, 4, 0, 0, 0, 0, "mass storage class mode"},
55 {0x19, 0x12, 1, 4, 0, 0, 0, 0, "exception monitor mode"},
56 {0x1B, 0x13, 1, 4, 0, 0, 0, 0, "battery calibration"},
57 {0x56, 0x14, 1, 0x200, 0, 0, 0, 0, "bluetooth pskey"}
58};
59
60static struct nvp_zone_info_entry_t nvp_zone_app[] =
61{
62 {5, 0, 8, 0x1000, 0, 0, 0, 0, "application parameter"},
63 {7, 0x40, 1, 0x14, 0, 0, 0, 0, "secure clock"},
64 {0xC, 0x41, 1, 0xA0, 0, 0, 0, 0, "aad icv"},
65 {0xD, 0x42, 2, 0x208, 0, 0, 0, 0, "empr key"},
66 {0x4C, 0x44, 1, 0x10, 0, 0, 0, 0, "slacker time"},
67 {0x15, 0x45, 1, 4, 0, 0, 0, 0, "key mode (debug/release)"},
68 {0x47, 0x46, 1, 0x40, 0, 0, 0, 0, "marlin time"},
69 {0x48, 0x47, 0x20, 0x4000, 0, 0, 0, 0, "marlin crl"},
70 {0x59, 0x76, 1, 0x200, 0, 0, 0, 0, "btmw factory pair info"},
71 {0x58, 0x77, 1, 0x200, 0, 0, 0, 0, "btmw factory scdb"},
72 {0x57, 0x78, 1, 4, 0, 0, 0, 0, "btmw log mode flag"},
73 {0x55, 0x79, 1, 4, 0, 0, 0, 0, "europe vol regulation flag"},
74 {8, 0x7A, 1, 8, 0, 0, 0, 0, "middleware parameter"},
75 {0x16, 0x7B, 1, 4, 0, 0, 0, 0, "quick shutdown flag"},
76 {0x45, 0x7C, 1, 4, 0, 0, 0, 0, "time out to sleep"},
77 {0x4E, 0x7D, 1, 4, 0, 0, 0, 0, "application debug mode flag"},
78 {0x4F, 0x7E, 1, 4, 0, 0, 0, 0, "browser log mode flag"}
79};
80
81static struct nvp_zone_info_entry_t nvp_zone_drm[] =
82{
83 {3, 1, 2, 0x2C0, 0, 0, 0, 0, "aad key"},
84 {0x1C, 6, 1, 0x40, 0, 0, 0, 0, "wmt key"},
85 {0x51, 9, 0x11, 0x2020, 0, 0, 0, 0, "slacker id file"},
86 {0x49, 0x1A, 0x41, 0x8100, 0, 0, 0, 0, "marlin device key"},
87 {0x21, 0x5B, 1, 0x40, 0, 0, 0, 0, "starfish id"},
88 {0x23, 0x5C, 4, 0x800, 0, 0, 0, 0, "bluetooth address"}
89};
90
91static struct nvp_zone_info_entry_t nvp_zone_ekb[] =
92{
93 {0xE, 0, 0x20, 0x4000, 0, 0, 0, 0, "EKB 0"},
94 {0xF, 0x20, 0x20, 0x4000, 0, 0, 0, 0, "EKB 1"},
95 {0x4A, 0x40, 0x30, 0x6000, 0, 0, 0, 0, "marlin user key"}
96};
97
98static struct nvp_zone_info_entry_t nvp_zone_emp[] =
99{
100 {0x24, 0, 2, 0x400, 0, 0, 0, 0, "EMPR 0"},
101 {0x25, 2, 2, 0x400, 0, 0, 0, 0, "EMPR 1"},
102 {0x26, 4, 2, 0x400, 0, 0, 0, 0, "EMPR 2"},
103 {0x27, 6, 2, 0x400, 0, 0, 0, 0, "EMPR 3"},
104 {0x28, 8, 2, 0x400, 0, 0, 0, 0, "EMPR 4"},
105 {0x29, 0xA, 2, 0x400, 0, 0, 0, 0, "EMPR 5"},
106 {0x2A, 0xC, 2, 0x400, 0, 0, 0, 0, "EMPR 6"},
107 {0x2B, 0xE, 2, 0x400, 0, 0, 0, 0, "EMPR 7"},
108 {0x2C, 0x10, 2, 0x400, 0, 0, 0, 0, "EMPR 8"},
109 {0x2D, 0x12, 2, 0x400, 0, 0, 0, 0, "EMPR 9"},
110 {0x2E, 0x14, 2, 0x400, 0, 0, 0, 0, "EMPR 10"},
111 {0x2F, 0x16, 2, 0x400, 0, 0, 0, 0, "EMPR 11"},
112 {0x30, 0x18, 2, 0x400, 0, 0, 0, 0, "EMPR 12"},
113 {0x31, 0x1A, 2, 0x400, 0, 0, 0, 0, "EMPR 13"},
114 {0x32, 0x1C, 2, 0x400, 0, 0, 0, 0, "EMPR 14"},
115 {0x33, 0x1E, 2, 0x400, 0, 0, 0, 0, "EMPR 15"},
116 {0x34, 0x20, 2, 0x400, 0, 0, 0, 0, "EMPR 16"},
117 {0x35, 0x22, 2, 0x400, 0, 0, 0, 0, "EMPR 17"},
118 {0x36, 0x24, 2, 0x400, 0, 0, 0, 0, "EMPR 18"},
119 {0x37, 0x26, 2, 0x400, 0, 0, 0, 0, "EMPR 19"},
120 {0x38, 0x28, 2, 0x400, 0, 0, 0, 0, "EMPR 20"},
121 {0x39, 0x2A, 2, 0x400, 0, 0, 0, 0, "EMPR 21"},
122 {0x3A, 0x2C, 2, 0x400, 0, 0, 0, 0, "EMPR 22"},
123 {0x3B, 0x2E, 2, 0x400, 0, 0, 0, 0, "EMPR 23"},
124 {0x3C, 0x30, 2, 0x400, 0, 0, 0, 0, "EMPR 24"},
125 {0x3D, 0x32, 2, 0x400, 0, 0, 0, 0, "EMPR 25"},
126 {0x3E, 0x34, 2, 0x400, 0, 0, 0, 0, "EMPR 26"},
127 {0x3F, 0x36, 2, 0x400, 0, 0, 0, 0, "EMPR 27"},
128 {0x40, 0x38, 2, 0x400, 0, 0, 0, 0, "EMPR 28"},
129 {0x41, 0x3A, 2, 0x400, 0, 0, 0, 0, "EMPR 29"},
130 {0x42, 0x3C, 2, 0x400, 0, 0, 0, 0, "EMPR 30"},
131 {0x43, 0x3E, 2, 0x400, 0, 0, 0, 0, "EMPR 31"}
132};
133
134static struct nvp_zone_info_entry_t nvp_zone_bti[] =
135{
136 {1, 0, 0x20, 0x40000, 0, 0, 0, 0, "boot image"}
137};
138
139static struct nvp_zone_info_entry_t nvp_zone_hdi[] =
140{
141 {2, 0, 0x20, 0x40000, 0, 0, 0, 0, "hold image"}
142};
143
144static struct nvp_zone_info_entry_t nvp_zone_lbi[] =
145{
146 {0x14, 0, 0x20, 0x40000, 0, 0, 0, 0, "low battery image"}
147};
148
149static struct nvp_zone_info_entry_t nvp_zone_upi[] =
150{
151 {0x13, 0, 0x20, 0x40000, 0, 0, 0, 0, "update image"}
152};
153
154static struct nvp_zone_info_entry_t nvp_zone_eri[] =
155{
156 {6, 0, 0x20, 0x40000, 0, 0, 0, 0, "update error image"}
157};
158
159struct nvp_area_info_entry_t nvp_area_info[NVP_NR_AREAS] =
160{
161 {2, nvp_zone_ubt, 6, 0, 0, 0, 0, "u-boot parameter"},
162 {2, nvp_zone_sys, 0x14, 0, 0, 0, 0, "system parameter"},
163 {2, nvp_zone_app, 0x11, 0, 0, 0, 0, "application parameter"},
164 {2, nvp_zone_drm, 6, 0, 0, 0, 0, "drm data"},
165 {2, nvp_zone_ekb, 3, 0, 0, 0, 0, "ekb data"},
166 {2, nvp_zone_emp, 0x20, 0, 0, 0, 0, "empr data"},
167 {2, 0, 0, 0, 0, 0, 0, "reserved"},
168 {2, 0, 0, 0, 0, 0, 0, "reserved"},
169 {1, nvp_zone_bti, 1, 0, 0, 0, 0, "boot image"},
170 {1, nvp_zone_hdi, 1, 0, 0, 0, 0, "hold image"},
171 {1, nvp_zone_lbi, 1, 0, 0, 0, 0, "low battery image"},
172 {1, nvp_zone_upi, 1, 0, 0, 0, 0, "update image"},
173 {1, nvp_zone_eri, 1, 0, 0, 0, 0, "update error image"},
174 {1, 0, 0, 0, 0, 0, 0, "reserved"},
175 {1, 0, 0, 0, 0, 0, 0, "reserved"},
176 {1, 0, 0, 0, 0, 0, 0, "reserved"}
177};
178
179static int nr_nodes;
180static struct nvp_node_info_t *node_info;
181static nvp_read_fn_t nvp_read;
182static int nvp_size;
183static int nr_sectors;
184static int nr_clusters;
185static uint8_t *nvp_table;
186static uint8_t *nvp_shadow;
187static uint16_t *nvp_bitmap;
188
189int nvp_get_cluster_status(int cluster)
190{
191 if(cluster <= 3 || cluster >= nr_clusters)
192 {
193 cprintf(GREY, "invalid cluster number: cluster=%d\n", cluster);
194 return -1;
195 }
196 return nvp_bitmap[cluster];
197}
198
199int nvp_set_cluster_status(int cluster, int status)
200{
201 if(cluster <= 3 || cluster >= nr_clusters)
202 {
203 cprintf(GREY, "invalid cluster number: cluster=%d\n", cluster);
204 return -1;
205 }
206 nvp_bitmap[cluster] = status;
207 return 0;
208}
209
210int nvp_get_sector_status(int sector)
211{
212 if(sector <= 3 || sector >= nr_sectors)
213 {
214 cprintf(GREY, "invalid sector number: sector=%d\n", sector);
215 return -1;
216 }
217 return (nvp_bitmap[sector >> 4] >> (sector & 0xf)) & 0x1;
218}
219
220int nvp_set_sector_status(int sector, int status)
221{
222 if(sector <= 3 || sector >= nr_sectors)
223 {
224 cprintf(GREY, "invalid sector number: sector=%d\n", sector);
225 return -1;
226 }
227 if(status)
228 nvp_bitmap[sector >> 4] |= 1 << (sector & 0xf);
229 else
230 nvp_bitmap[sector >> 4] &= ~(1 << (sector & 0xf));
231 return 0;
232}
233
234int nvp_get_cluster_number(int shadow, int area, int zone, int index)
235{
236 int start = nvp_area_info[area].zone_info[zone].start;
237 int count = nvp_area_info[area].zone_info[zone].count;
238 if(index >= count)
239 {
240 cprintf(GREY, "invalid index: index=%d\n", index);
241 return -1;
242 }
243 uint8_t *ptr = shadow ? nvp_shadow : nvp_table;
244 uint16_t cluster = *(uint16_t *)&ptr[area * NVP_AREA_TABLE_SIZE + (start + index) * 2];
245 if(cluster == 0)
246 return 0;
247 if(cluster <= 3 || cluster >= nr_clusters)
248 {
249 cprintf(GREY, "invalid cluster: shadow=%d area=%d zone=%d index=%d cluster=%d\n",
250 shadow, area, zone, index, cluster);
251 return -1;
252 }
253 return cluster;
254}
255
256int nvp_get_sector_number(int shadow, int area, int zone, int index)
257{
258 int start = nvp_area_info[area].zone_info[zone].start;
259 int count = nvp_area_info[area].zone_info[zone].count;
260 if(index >= count)
261 {
262 cprintf(GREY, "invalid index: index=%d\n", index);
263 return -1;
264 }
265 uint8_t *ptr = shadow ? nvp_shadow : nvp_table;
266 uint32_t sector = *(uint32_t *)&ptr[area * NVP_AREA_TABLE_SIZE + (start + index) * 4];
267 if(sector == 0)
268 return 0;
269 if(sector <= 0x3f || sector >= (unsigned)nr_sectors)
270 {
271 cprintf(GREY, "invalid sector: shadow=%d area=%d zone=%d index=%d sector=%d\n",
272 shadow, area, zone, index, sector);
273 return -1;
274 }
275 return sector;
276}
277
278int nvp_read_data(int shadow, int area, int zone, int offset, void *buf, int size)
279{
280 int large = nvp_area_info[area].kind == NVP_AREA_LARGE_KIND;
281 int unit_size = large ? NVP_LARGE_AREA_SIZE : NVP_SMALL_AREA_SIZE;
282
283 while(size > 0)
284 {
285 int index = offset / unit_size;
286 int unit_offset = offset % unit_size;
287 int sec_cluster = large ?
288 nvp_get_cluster_number(shadow, area, zone, index) :
289 nvp_get_sector_number(shadow, area, zone, index);
290 if(sec_cluster == 0)
291 return -1;
292 //cprintf(GREY, "[sec_cluster=%d]", sec_cluster);
293 int read = MIN(size, unit_size - unit_offset);
294 int ret = nvp_read(sec_cluster * unit_size, read, buf);
295 if(ret)
296 return ret;
297 buf += read;
298 offset += read;
299 size -= read;
300 }
301 return 0;
302}
303
304struct nvp_node_info_t nvp_get_node_info(int node)
305{
306 return node_info[node];
307}
308
309int nvp_get_node_size(int node)
310{
311 struct nvp_node_info_t i = nvp_get_node_info(node);
312 return nvp_area_info[i.area].zone_info[i.zone].size;
313}
314
315const char *nvp_get_node_name(int node)
316{
317 struct nvp_node_info_t i = nvp_get_node_info(node);
318 return nvp_area_info[i.area].zone_info[i.zone].name;
319}
320
321const char *nvp_get_area_name(int area)
322{
323 return nvp_area_info[area].name;
324}
325
326int nvp_read_node(int node, int offset, void *buffer, int size)
327{
328 struct nvp_node_info_t i = nvp_get_node_info(node);
329 return nvp_read_data(0, i.area, i.zone, offset, buffer, size);
330}
331
332int nvp_init(int size, nvp_read_fn_t read, bool debug)
333{
334 nvp_read = read;
335 nvp_size = size;
336 nr_sectors = nvp_size / NVP_SECTOR_SIZE;
337 nr_clusters = (nr_sectors + NVP_SECTOR_PER_CLUSTER) / NVP_SECTOR_PER_CLUSTER;
338 // check that the tables are consistent and compute the number of nodes
339 if(debug)
340 cprintf(BLUE, "NVP Debug\n");
341 for(int i = 0; i < NVP_NR_AREAS; i++)
342 {
343 if(debug)
344 {
345 cprintf(RED, " %s Area: ", nvp_area_info[i].kind == NVP_AREA_SMALL_KIND ? "Small" : "Large");
346 cprintf(GREEN, "%s\n", nvp_area_info[i].name);
347 }
348 if(nvp_area_info[i].zone_info == NULL)
349 continue;
350
351 struct nvp_zone_info_entry_t *zones = nvp_area_info[i].zone_info;
352 int nr_zones = nvp_area_info[i].nr_zones;
353 int kind = nvp_area_info[i].kind;
354 if(kind != NVP_AREA_SMALL_KIND && kind != NVP_AREA_LARGE_KIND)
355 continue;
356
357 uint32_t bitmap[256];
358 memset(bitmap, 0, sizeof(bitmap));
359
360 for(int j = 0; j < nr_zones; j++)
361 {
362 if(debug)
363 {
364 cprintf_field(" Zone ", "%s", zones[j].name);
365 cprintf_field(" Node ", "%d", zones[j].node);
366 cprintf_field(" Start ", "%#x", zones[j].start);
367 cprintf_field(" Count ", "%#x", zones[j].count);
368 cprintf_field(" Size ", "%#x\n", zones[j].size);
369 }
370
371 if(kind == NVP_AREA_LARGE_KIND)
372 {
373 if(zones[j].start >= NVP_LARGE_AREA_MAX_CLUSTER ||
374 zones[j].start + zones[j].count > NVP_LARGE_AREA_MAX_CLUSTER)
375 {
376 cprintf(GREY, "Bad zone start/count\n");
377 return 95;
378 }
379 if(zones[j].size > zones[j].count * NVP_LARGE_AREA_SIZE)
380 {
381 cprintf(GREY, "Bad zone size\n");
382 return 96;
383 }
384 }
385 else
386 {
387 if(zones[j].start >= NVP_SMALL_AREA_MAX_CLUSTER ||
388 zones[j].start + zones[j].count > NVP_SMALL_AREA_MAX_CLUSTER)
389 {
390 cprintf(GREY, "Bad zone start/count\n");
391 return 97;
392 }
393 if(zones[j].size > zones[j].count * NVP_SMALL_AREA_SIZE)
394 {
395 cprintf(GREY, "Bad zone size\n");
396 return 98;
397 }
398 }
399
400 nr_nodes++;
401
402 for(int k = 0; k < zones[j].count; k++)
403 {
404 if(bitmap[zones[j].start + k])
405 {
406 cprintf(GREY, "Zone overlap !\n");
407 return 99;
408 }
409 bitmap[zones[j].start + k] = 0xffffffff;
410 }
411 }
412 }
413
414 // build node table
415 nr_nodes++; // nodes start at 1 ?!
416 node_info = malloc(nr_nodes * sizeof(struct nvp_node_info_t));
417 memset(node_info, 0xff, nr_nodes * sizeof(struct nvp_node_info_t));
418
419 for(int i = 0; i < NVP_NR_AREAS; i++)
420 {
421 if(nvp_area_info[i].zone_info == NULL)
422 continue;
423
424 struct nvp_zone_info_entry_t *zones = nvp_area_info[i].zone_info;
425 int nr_zones = nvp_area_info[i].nr_zones;
426 int kind = nvp_area_info[i].kind;
427 if(kind != NVP_AREA_SMALL_KIND && kind != NVP_AREA_LARGE_KIND)
428 continue;
429
430 for(int j = 0; j < nr_zones; j++)
431 {
432 int node = zones[j].node;
433 if(node >= nr_nodes)
434 {
435 cprintf(GREY, "Node out of bounds !\n");
436 return 89;
437 }
438 if(node_info[node].area != -1 && node_info[node].zone != -1)
439 {
440 cprintf(GREY, "Node overlap: area=%d zone=%d node=%d to area=%d zone=%d !\n",
441 i, j, node, node_info[node].area, node_info[node].zone);
442 return 88;
443 }
444 node_info[node].area = i;
445 node_info[node].zone = j;
446 }
447 }
448
449 // load allocation table
450 nvp_table = malloc(NVP_CLUSTER_SIZE);
451 int ret = nvp_read(NVP_TABLE_SECTOR * NVP_SECTOR_SIZE, NVP_CLUSTER_SIZE, nvp_table);
452 if(ret) return ret;
453
454 // init shadow table
455 nvp_shadow = malloc(NVP_CLUSTER_SIZE);
456 memset(nvp_shadow, 0, NVP_CLUSTER_SIZE);
457
458 // init bitmap
459 nvp_bitmap = malloc(sizeof(uint16_t) * nr_clusters);
460 memset(nvp_bitmap, 0, sizeof(uint16_t) * nr_clusters);
461
462 // read map
463 for(int i = 0; i < NVP_NR_AREAS; i++)
464 {
465 if(nvp_area_info[i].zone_info == NULL)
466 continue;
467 int kind = nvp_area_info[i].kind;
468 if(kind != NVP_AREA_SMALL_KIND && kind != NVP_AREA_LARGE_KIND)
469 continue;
470
471 if(kind == NVP_AREA_LARGE_KIND)
472 {
473 for(int cluster = 0; cluster < NVP_LARGE_AREA_MAX_CLUSTER; cluster++)
474 {
475 uint16_t entry = *(uint16_t *)&nvp_table[i * NVP_AREA_TABLE_SIZE + cluster * 2];
476 if(entry == 0)
477 continue;
478 if(nvp_get_cluster_status(entry) != 0)
479 {
480 cprintf(GREY, "cluster already used: area=%d cluster=%d entry=%d\n", i, cluster, entry);
481 return 78;
482 }
483 nvp_set_cluster_status(entry, 0xffff);
484 }
485 }
486 else
487 {
488 for(int cluster = 0; cluster < NVP_SMALL_AREA_MAX_CLUSTER; cluster++)
489 {
490 uint32_t entry = *(uint32_t *)&nvp_table[i * NVP_AREA_TABLE_SIZE + cluster * 4];
491 if(entry == 0)
492 continue;
493 if(nvp_get_sector_status(entry) != 0)
494 {
495 cprintf(GREY, "sector already used: area=%d cluster=%d entry=%d\n", i, cluster, entry);
496 return 76;
497 }
498 nvp_set_sector_status(entry, 1);
499 }
500 }
501 }
502
503 return 0;
504}
505
506int nvp_info(void)
507{
508 uint32_t version;
509 int ret = nvp_read(0, sizeof(version), &version);
510 if(ret) return ret;
511
512 cprintf(BLUE, "NVP\n");
513 cprintf_field(" Version: ", "%x\n", version);
514
515 for(int i = 0; i < NVP_NR_AREAS; i++)
516 {
517 cprintf(RED, " Area: ");
518 cprintf(GREEN, "%s\n", nvp_area_info[i].name);
519 if(nvp_area_info[i].zone_info == NULL)
520 continue;
521
522 struct nvp_zone_info_entry_t *zones = nvp_area_info[i].zone_info;
523 int nr_zones = nvp_area_info[i].nr_zones;
524
525 for(int j = 0; j < nr_zones; j++)
526 {
527 cprintf_field(" Zone ", "%s", zones[j].name);
528 cprintf(BLUE, " ->");
529 uint8_t buf[0x20];
530 int ret = nvp_read_data(0, i, j, 0, buf, MIN(0x20, zones[j].size));
531 if(ret)
532 {
533 cprintf(RED, " No data\n");
534 continue;
535 }
536 for(int i = 0; i < MIN(0x20, zones[j].size); i++)
537 cprintf(YELLOW, " %02x", buf[i]);
538 cprintf(BLUE, " -> ");
539 for(int i = 0; i < MIN(0x20, zones[j].size); i++)
540 cprintf(YELLOW, "%c", isprint(buf[i]) ? buf[i] : '.');
541 printf("\n");
542 }
543 }
544
545 return 0;
546} \ No newline at end of file
diff --git a/utils/nwztools/emmctools/nvp.h b/utils/nwztools/emmctools/nvp.h
new file mode 100644
index 0000000000..1eff36c19e
--- /dev/null
+++ b/utils/nwztools/emmctools/nvp.h
@@ -0,0 +1,93 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2012 Amaury Pouly
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#ifndef __NVP_H__
22#define __NVP_H__
23
24#include <stdint.h>
25#include <stdbool.h>
26#include "misc.h"
27
28#define NVP_AREA_LARGE_KIND 1
29#define NVP_AREA_SMALL_KIND 2
30
31#define NVP_SMALL_AREA_MAX_CLUSTER 128
32#define NVP_LARGE_AREA_MAX_CLUSTER 256
33#define NVP_AREA_TABLE_SIZE 512
34
35#define NVP_SECTOR_SIZE 512
36#define NVP_TABLE_SECTOR 16
37#define NVP_DATA_SECTOR_MIN 64
38#define NVP_DATA_SECTOR_MAX 32767
39#define NVP_SECTOR_PER_CLUSTER 16
40#define NVP_CLUSTER_SIZE (NVP_SECTOR_SIZE * NVP_SECTOR_PER_CLUSTER)
41
42#define NVP_LARGE_AREA_SIZE NVP_CLUSTER_SIZE
43#define NVP_SMALL_AREA_SIZE NVP_SECTOR_SIZE
44
45struct nvp_zone_info_entry_t
46{
47 int node;
48 int start; // in 4 unit
49 int count; // in 512 unit for kind 2 and in 8192 for kind 1
50 int size;
51 int res0, res1, res2, res3;
52 const char *name;
53};
54
55struct nvp_area_info_entry_t
56{
57 int kind;
58 struct nvp_zone_info_entry_t *zone_info;
59 int nr_zones;
60 int res0, res1, res2, res3;
61 const char *name;
62};
63
64struct nvp_node_info_t
65{
66 int area;
67 int zone;
68};
69
70#define NVP_NR_AREAS 16
71
72extern struct nvp_area_info_entry_t nvp_area_info[NVP_NR_AREAS];
73
74typedef int (*nvp_read_fn_t)(uint32_t offset, uint32_t size, void *buf);
75
76int nvp_init(int nvp_size, nvp_read_fn_t read, bool debug);
77struct nvp_node_info_t nvp_get_node_info(int node);
78int nvp_get_node_size(int node);
79const char *nvp_get_node_name(int node);
80const char *nvp_get_area_name(int node);
81int nvp_read_node(int node, int offset, void *buffer, int size);
82
83int nvp_info(void);
84
85int nvp_get_cluster_status(int cluster);
86int nvp_set_cluster_status(int cluster, int status);
87int nvp_get_sector_status(int sector);
88int nvp_set_sector_status(int sector, int status);
89int nvp_get_cluster_number(int shadow, int area, int zone, int index);
90int nvp_get_sector_number(int shadow, int area, int zone, int index);
91int nvp_read_data(int shadow, int area, int zone, int offset, void *buffer, int size);
92
93#endif /* __NVP_H__ */