Introduce emmctools for the sony nwz players.
[maemo-rb.git] / utils / nwztools / emmctools / emmctool.c
blob8fa7b0907ba8a0a32cbcfd8049719eb09fc0fdb8
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2012 Amaury Pouly
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.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
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"
34 bool g_debug = false;
35 char *g_out_prefix = NULL;
36 FILE *g_in_file = NULL;
37 bool g_force = false;
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)
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); }
47 #define errorf(...) do { cprintf(GREY, __VA_ARGS__); return __LINE__; } while(0)
49 static void print_hex(void *p, int size, int unit)
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++)
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);
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)
76 #define print_entry(begin, end, ...) \
77 do{ cprintf(YELLOW, " %08x %08x ", begin, end); cprintf(GREEN, __VA_ARGS__); } while(0)
79 static int read(uint32_t offset, uint32_t size, void *buf)
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;
88 static int nvp_read(uint32_t offset, uint32_t size, void *buf)
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);
95 // returns size or 0
96 static uint32_t do_image(uint32_t start, const char *name)
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);
105 print_entry(start, start + size, name);
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)
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;
123 if(crc == 0)
125 cprintf(RED, " (CRC Ok)\n");
126 return size;
128 else
130 cprintf(RED, " (CRC Mismatch)\n");
131 return 0;
135 static int do_emmc(void)
137 cprintf(BLUE, "eMMC map\n");
138 cprintf(RED, " begin end comment\n");
140 print_entry(EMMC_MINIBOOT_START, EMMC_MINIBOOT_START + EMMC_MINIBOOT_SIZE, "eMMC Mini Boot\n");
142 uint32_t uboot_size = do_image(EMMC_UBOOT_START, "U-Boot");
143 if(!uboot_size)
144 return 1;
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;
151 uint32_t fu_initrd_size = do_image(EMMC_FU_LINUX_START, "FU initrd");
152 if(!fu_initrd_size)
153 return 1;
155 print_entry(EMMC_NVP_START, EMMC_NVP_START + EMMC_NVP_SIZE, "NVP\n");
157 uint32_t linux_size = do_image(EMMC_LINUX_START, "Linux");
158 if(!linux_size)
159 return 1;
161 int ret = nvp_info();
162 continue_the_force(ret);
164 return 0;
167 static void usage(void)
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);
179 int main(int argc, char **argv)
181 while(1)
183 static struct option long_options[] =
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}
192 int c = getopt_long(argc, argv, "?dcfo:", long_options, NULL);
193 if(c == -1)
194 break;
195 switch(c)
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();
219 if(argc - optind != 1)
221 usage();
222 return 1;
225 g_in_file = fopen(argv[optind], "rb");
226 if(g_in_file == NULL)
228 perror("Cannot open boot file");
229 return 1;
232 int ret = nvp_init(EMMC_NVP_SIZE, &nvp_read, g_debug);
233 if(ret) return ret;
234 ret = do_emmc();
236 fclose(g_in_file);
238 color(OFF);
240 return ret;