diff options
Diffstat (limited to 'utils/nwztools/emmctools')
-rw-r--r-- | utils/nwztools/emmctools/Makefile | 20 | ||||
-rw-r--r-- | utils/nwztools/emmctools/emmctool.c | 242 | ||||
-rw-r--r-- | utils/nwztools/emmctools/misc.c | 53 | ||||
-rw-r--r-- | utils/nwztools/emmctools/misc.h | 50 | ||||
-rw-r--r-- | utils/nwztools/emmctools/nvp.c | 546 | ||||
-rw-r--r-- | utils/nwztools/emmctools/nvp.h | 93 |
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 @@ | |||
1 | DEFINES= | ||
2 | CC=gcc | ||
3 | LD=gcc | ||
4 | CFLAGS=-g -std=c99 -W -Wall $(DEFINES) | ||
5 | LDFLAGS= | ||
6 | BINS=emmctool | ||
7 | |||
8 | all: $(BINS) | ||
9 | |||
10 | %.o: %.c | ||
11 | $(CC) $(CFLAGS) -c -o $@ $< | ||
12 | |||
13 | emmctool: emmctool.o misc.o nvp.o | ||
14 | $(LD) -o $@ $^ $(LDFLAGS) | ||
15 | |||
16 | clean: | ||
17 | rm -fr *.o | ||
18 | |||
19 | veryclean: | ||
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 | |||
34 | bool g_debug = false; | ||
35 | char *g_out_prefix = NULL; | ||
36 | FILE *g_in_file = NULL; | ||
37 | bool 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 | |||
49 | static 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 | |||
79 | static 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 | |||
88 | static 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 | ||
96 | static 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 | |||
135 | static 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 | |||
167 | static 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 | |||
179 | int 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 | |||
27 | char OFF[] = { 0x1b, 0x5b, 0x31, 0x3b, '0', '0', 0x6d, '\0' }; | ||
28 | |||
29 | char GREY[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '0', 0x6d, '\0' }; | ||
30 | char RED[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '1', 0x6d, '\0' }; | ||
31 | char GREEN[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '2', 0x6d, '\0' }; | ||
32 | char YELLOW[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '3', 0x6d, '\0' }; | ||
33 | char BLUE[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '4', 0x6d, '\0' }; | ||
34 | |||
35 | static bool g_color_enable = true; | ||
36 | |||
37 | void *xmalloc(size_t s) | ||
38 | { | ||
39 | void * r = malloc(s); | ||
40 | if(!r) bugp("malloc"); | ||
41 | return r; | ||
42 | } | ||
43 | |||
44 | void enable_color(bool enable) | ||
45 | { | ||
46 | g_color_enable = enable; | ||
47 | } | ||
48 | |||
49 | void 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 | |||
35 | typedef char color_t[]; | ||
36 | |||
37 | extern color_t OFF, GREY, RED, GREEN, YELLOW, BLUE; | ||
38 | void *xmalloc(size_t s); | ||
39 | void color(color_t c); | ||
40 | void 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 | |||
26 | static 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 | |||
36 | static 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 | |||
60 | static 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 | |||
81 | static 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 | |||
91 | static 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 | |||
98 | static 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 | |||
134 | static struct nvp_zone_info_entry_t nvp_zone_bti[] = | ||
135 | { | ||
136 | {1, 0, 0x20, 0x40000, 0, 0, 0, 0, "boot image"} | ||
137 | }; | ||
138 | |||
139 | static struct nvp_zone_info_entry_t nvp_zone_hdi[] = | ||
140 | { | ||
141 | {2, 0, 0x20, 0x40000, 0, 0, 0, 0, "hold image"} | ||
142 | }; | ||
143 | |||
144 | static struct nvp_zone_info_entry_t nvp_zone_lbi[] = | ||
145 | { | ||
146 | {0x14, 0, 0x20, 0x40000, 0, 0, 0, 0, "low battery image"} | ||
147 | }; | ||
148 | |||
149 | static struct nvp_zone_info_entry_t nvp_zone_upi[] = | ||
150 | { | ||
151 | {0x13, 0, 0x20, 0x40000, 0, 0, 0, 0, "update image"} | ||
152 | }; | ||
153 | |||
154 | static struct nvp_zone_info_entry_t nvp_zone_eri[] = | ||
155 | { | ||
156 | {6, 0, 0x20, 0x40000, 0, 0, 0, 0, "update error image"} | ||
157 | }; | ||
158 | |||
159 | struct 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 | |||
179 | static int nr_nodes; | ||
180 | static struct nvp_node_info_t *node_info; | ||
181 | static nvp_read_fn_t nvp_read; | ||
182 | static int nvp_size; | ||
183 | static int nr_sectors; | ||
184 | static int nr_clusters; | ||
185 | static uint8_t *nvp_table; | ||
186 | static uint8_t *nvp_shadow; | ||
187 | static uint16_t *nvp_bitmap; | ||
188 | |||
189 | int 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 | |||
199 | int 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 | |||
210 | int 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 | |||
220 | int 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 | |||
234 | int 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 | |||
256 | int 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 | |||
278 | int 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 | |||
304 | struct nvp_node_info_t nvp_get_node_info(int node) | ||
305 | { | ||
306 | return node_info[node]; | ||
307 | } | ||
308 | |||
309 | int 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 | |||
315 | const 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 | |||
321 | const char *nvp_get_area_name(int area) | ||
322 | { | ||
323 | return nvp_area_info[area].name; | ||
324 | } | ||
325 | |||
326 | int 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 | |||
332 | int 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 | |||
506 | int 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 | |||
45 | struct 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 | |||
55 | struct 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 | |||
64 | struct nvp_node_info_t | ||
65 | { | ||
66 | int area; | ||
67 | int zone; | ||
68 | }; | ||
69 | |||
70 | #define NVP_NR_AREAS 16 | ||
71 | |||
72 | extern struct nvp_area_info_entry_t nvp_area_info[NVP_NR_AREAS]; | ||
73 | |||
74 | typedef int (*nvp_read_fn_t)(uint32_t offset, uint32_t size, void *buf); | ||
75 | |||
76 | int nvp_init(int nvp_size, nvp_read_fn_t read, bool debug); | ||
77 | struct nvp_node_info_t nvp_get_node_info(int node); | ||
78 | int nvp_get_node_size(int node); | ||
79 | const char *nvp_get_node_name(int node); | ||
80 | const char *nvp_get_area_name(int node); | ||
81 | int nvp_read_node(int node, int offset, void *buffer, int size); | ||
82 | |||
83 | int nvp_info(void); | ||
84 | |||
85 | int nvp_get_cluster_status(int cluster); | ||
86 | int nvp_set_cluster_status(int cluster, int status); | ||
87 | int nvp_get_sector_status(int sector); | ||
88 | int nvp_set_sector_status(int sector, int status); | ||
89 | int nvp_get_cluster_number(int shadow, int area, int zone, int index); | ||
90 | int nvp_get_sector_number(int shadow, int area, int zone, int index); | ||
91 | int nvp_read_data(int shadow, int area, int zone, int offset, void *buffer, int size); | ||
92 | |||
93 | #endif /* __NVP_H__ */ | ||