1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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 ****************************************************************************/
26 static struct nvp_zone_info_entry_t nvp_zone_ubt
[] =
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"}
36 static struct nvp_zone_info_entry_t nvp_zone_sys
[] =
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"}
60 static struct nvp_zone_info_entry_t nvp_zone_app
[] =
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"}
81 static struct nvp_zone_info_entry_t nvp_zone_drm
[] =
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"}
91 static struct nvp_zone_info_entry_t nvp_zone_ekb
[] =
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"}
98 static struct nvp_zone_info_entry_t nvp_zone_emp
[] =
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"}
134 static struct nvp_zone_info_entry_t nvp_zone_bti
[] =
136 {1, 0, 0x20, 0x40000, 0, 0, 0, 0, "boot image"}
139 static struct nvp_zone_info_entry_t nvp_zone_hdi
[] =
141 {2, 0, 0x20, 0x40000, 0, 0, 0, 0, "hold image"}
144 static struct nvp_zone_info_entry_t nvp_zone_lbi
[] =
146 {0x14, 0, 0x20, 0x40000, 0, 0, 0, 0, "low battery image"}
149 static struct nvp_zone_info_entry_t nvp_zone_upi
[] =
151 {0x13, 0, 0x20, 0x40000, 0, 0, 0, 0, "update image"}
154 static struct nvp_zone_info_entry_t nvp_zone_eri
[] =
156 {6, 0, 0x20, 0x40000, 0, 0, 0, 0, "update error image"}
159 struct nvp_area_info_entry_t nvp_area_info
[NVP_NR_AREAS
] =
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"}
180 static struct nvp_node_info_t
*node_info
;
181 static nvp_read_fn_t nvp_read
;
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
;
189 int nvp_get_cluster_status(int cluster
)
191 if(cluster
<= 3 || cluster
>= nr_clusters
)
193 cprintf(GREY
, "invalid cluster number: cluster=%d\n", cluster
);
196 return nvp_bitmap
[cluster
];
199 int nvp_set_cluster_status(int cluster
, int status
)
201 if(cluster
<= 3 || cluster
>= nr_clusters
)
203 cprintf(GREY
, "invalid cluster number: cluster=%d\n", cluster
);
206 nvp_bitmap
[cluster
] = status
;
210 int nvp_get_sector_status(int sector
)
212 if(sector
<= 3 || sector
>= nr_sectors
)
214 cprintf(GREY
, "invalid sector number: sector=%d\n", sector
);
217 return (nvp_bitmap
[sector
>> 4] >> (sector
& 0xf)) & 0x1;
220 int nvp_set_sector_status(int sector
, int status
)
222 if(sector
<= 3 || sector
>= nr_sectors
)
224 cprintf(GREY
, "invalid sector number: sector=%d\n", sector
);
228 nvp_bitmap
[sector
>> 4] |= 1 << (sector
& 0xf);
230 nvp_bitmap
[sector
>> 4] &= ~(1 << (sector
& 0xf));
234 int nvp_get_cluster_number(int shadow
, int area
, int zone
, int index
)
236 int start
= nvp_area_info
[area
].zone_info
[zone
].start
;
237 int count
= nvp_area_info
[area
].zone_info
[zone
].count
;
240 cprintf(GREY
, "invalid index: index=%d\n", index
);
243 uint8_t *ptr
= shadow
? nvp_shadow
: nvp_table
;
244 uint16_t cluster
= *(uint16_t *)&ptr
[area
* NVP_AREA_TABLE_SIZE
+ (start
+ index
) * 2];
247 if(cluster
<= 3 || cluster
>= nr_clusters
)
249 cprintf(GREY
, "invalid cluster: shadow=%d area=%d zone=%d index=%d cluster=%d\n",
250 shadow
, area
, zone
, index
, cluster
);
256 int nvp_get_sector_number(int shadow
, int area
, int zone
, int index
)
258 int start
= nvp_area_info
[area
].zone_info
[zone
].start
;
259 int count
= nvp_area_info
[area
].zone_info
[zone
].count
;
262 cprintf(GREY
, "invalid index: index=%d\n", index
);
265 uint8_t *ptr
= shadow
? nvp_shadow
: nvp_table
;
266 //cprintf(GREY, "[offset: 0x%x]", area * NVP_AREA_TABLE_SIZE + (start + index) * 4);
267 uint32_t sector
= *(uint32_t *)&ptr
[area
* NVP_AREA_TABLE_SIZE
+ (start
+ index
) * 4];
270 if(sector
<= 0x3f || sector
>= (unsigned)nr_sectors
)
272 cprintf(GREY
, "invalid sector: shadow=%d area=%d zone=%d index=%d sector=%d\n",
273 shadow
, area
, zone
, index
, sector
);
279 int nvp_read_data(int shadow
, int area
, int zone
, int offset
, void *buf
, int size
)
281 int large
= nvp_area_info
[area
].kind
== NVP_AREA_LARGE_KIND
;
282 int unit_size
= large
? NVP_LARGE_AREA_SIZE
: NVP_SMALL_AREA_SIZE
;
287 int index
= offset
/ unit_size
;
288 int unit_offset
= offset
% unit_size
;
289 int sec_cluster
= large
?
290 nvp_get_cluster_number(shadow
, area
, zone
, index
) :
291 nvp_get_sector_number(shadow
, area
, zone
, index
);
294 int read
= MIN(size
, unit_size
- unit_offset
);
295 //cprintf(GREY, "[sec_cluster=%d unit_size=%d read=%d]", sec_cluster, unit_size, read);
296 int ret
= nvp_read(sec_cluster
* unit_size
, read
, buf
);
307 bool nvp_is_valid_node(int node
)
309 return node
>= 0 && node
< nr_nodes
&& node_info
[node
].area
!= -1;
312 struct nvp_node_info_t
nvp_get_node_info(int node
)
314 return node_info
[node
];
317 int nvp_get_node_size(int node
)
319 struct nvp_node_info_t i
= nvp_get_node_info(node
);
320 return nvp_area_info
[i
.area
].zone_info
[i
.zone
].size
;
323 const char *nvp_get_node_name(int node
)
325 struct nvp_node_info_t i
= nvp_get_node_info(node
);
326 return nvp_area_info
[i
.area
].zone_info
[i
.zone
].name
;
329 const char *nvp_get_area_name(int area
)
331 return nvp_area_info
[area
].name
;
334 int nvp_read_node(int node
, int offset
, void *buffer
, int size
)
336 struct nvp_node_info_t i
= nvp_get_node_info(node
);
337 return nvp_read_data(0, i
.area
, i
.zone
, offset
, buffer
, size
);
340 int nvp_init(int size
, nvp_read_fn_t read
, bool debug
)
344 nr_sectors
= nvp_size
/ NVP_SECTOR_SIZE
;
345 nr_clusters
= (nr_sectors
+ NVP_SECTOR_PER_CLUSTER
) / NVP_SECTOR_PER_CLUSTER
;
346 // check that the tables are consistent and compute the number of nodes
348 cprintf(BLUE
, "NVP Debug\n");
349 for(int i
= 0; i
< NVP_NR_AREAS
; i
++)
353 cprintf(RED
, " %s Area: ", nvp_area_info
[i
].kind
== NVP_AREA_SMALL_KIND
? "Small" : "Large");
354 cprintf(GREEN
, "%s\n", nvp_area_info
[i
].name
);
356 if(nvp_area_info
[i
].zone_info
== NULL
)
359 struct nvp_zone_info_entry_t
*zones
= nvp_area_info
[i
].zone_info
;
360 int nr_zones
= nvp_area_info
[i
].nr_zones
;
361 int kind
= nvp_area_info
[i
].kind
;
362 if(kind
!= NVP_AREA_SMALL_KIND
&& kind
!= NVP_AREA_LARGE_KIND
)
365 uint32_t bitmap
[256];
366 memset(bitmap
, 0, sizeof(bitmap
));
368 for(int j
= 0; j
< nr_zones
; j
++)
372 cprintf_field(" Zone ", "%s", zones
[j
].name
);
373 cprintf_field(" Node ", "%d", zones
[j
].node
);
374 cprintf_field(" Start ", "%#x", zones
[j
].start
);
375 cprintf_field(" Count ", "%#x", zones
[j
].count
);
376 cprintf_field(" Size ", "%#x\n", zones
[j
].size
);
379 if(kind
== NVP_AREA_LARGE_KIND
)
381 if(zones
[j
].start
>= NVP_LARGE_AREA_MAX_CLUSTER
||
382 zones
[j
].start
+ zones
[j
].count
> NVP_LARGE_AREA_MAX_CLUSTER
)
384 cprintf(GREY
, "Bad zone start/count\n");
387 if(zones
[j
].size
> zones
[j
].count
* NVP_LARGE_AREA_SIZE
)
389 cprintf(GREY
, "Bad zone size\n");
395 if(zones
[j
].start
>= NVP_SMALL_AREA_MAX_CLUSTER
||
396 zones
[j
].start
+ zones
[j
].count
> NVP_SMALL_AREA_MAX_CLUSTER
)
398 cprintf(GREY
, "Bad zone start/count\n");
401 if(zones
[j
].size
> zones
[j
].count
* NVP_SMALL_AREA_SIZE
)
403 cprintf(GREY
, "Bad zone size\n");
410 for(int k
= 0; k
< zones
[j
].count
; k
++)
412 if(bitmap
[zones
[j
].start
+ k
])
414 cprintf(GREY
, "Zone overlap !\n");
417 bitmap
[zones
[j
].start
+ k
] = 0xffffffff;
423 nr_nodes
++; // nodes start at 1 ?!
424 node_info
= malloc(nr_nodes
* sizeof(struct nvp_node_info_t
));
425 memset(node_info
, 0xff, nr_nodes
* sizeof(struct nvp_node_info_t
));
427 for(int i
= 0; i
< NVP_NR_AREAS
; i
++)
429 if(nvp_area_info
[i
].zone_info
== NULL
)
432 struct nvp_zone_info_entry_t
*zones
= nvp_area_info
[i
].zone_info
;
433 int nr_zones
= nvp_area_info
[i
].nr_zones
;
434 int kind
= nvp_area_info
[i
].kind
;
435 if(kind
!= NVP_AREA_SMALL_KIND
&& kind
!= NVP_AREA_LARGE_KIND
)
438 for(int j
= 0; j
< nr_zones
; j
++)
440 int node
= zones
[j
].node
;
443 cprintf(GREY
, "Node out of bounds !\n");
446 if(node_info
[node
].area
!= -1 && node_info
[node
].zone
!= -1)
448 cprintf(GREY
, "Node overlap: area=%d zone=%d node=%d to area=%d zone=%d !\n",
449 i
, j
, node
, node_info
[node
].area
, node_info
[node
].zone
);
452 node_info
[node
].area
= i
;
453 node_info
[node
].zone
= j
;
457 // load allocation table
458 nvp_table
= malloc(NVP_CLUSTER_SIZE
);
459 int ret
= nvp_read(NVP_TABLE_SECTOR
* NVP_SECTOR_SIZE
, NVP_CLUSTER_SIZE
, nvp_table
);
463 nvp_shadow
= malloc(NVP_CLUSTER_SIZE
);
464 memset(nvp_shadow
, 0, NVP_CLUSTER_SIZE
);
467 nvp_bitmap
= malloc(sizeof(uint16_t) * nr_clusters
);
468 memset(nvp_bitmap
, 0, sizeof(uint16_t) * nr_clusters
);
471 for(int i
= 0; i
< NVP_NR_AREAS
; i
++)
473 if(nvp_area_info
[i
].zone_info
== NULL
)
475 int kind
= nvp_area_info
[i
].kind
;
476 if(kind
!= NVP_AREA_SMALL_KIND
&& kind
!= NVP_AREA_LARGE_KIND
)
479 if(kind
== NVP_AREA_LARGE_KIND
)
481 for(int cluster
= 0; cluster
< NVP_LARGE_AREA_MAX_CLUSTER
; cluster
++)
483 uint16_t entry
= *(uint16_t *)&nvp_table
[i
* NVP_AREA_TABLE_SIZE
+ cluster
* 2];
486 if(nvp_get_cluster_status(entry
) != 0)
488 cprintf(GREY
, "cluster already used: area=%d cluster=%d entry=%d\n", i
, cluster
, entry
);
491 nvp_set_cluster_status(entry
, 0xffff);
496 for(int cluster
= 0; cluster
< NVP_SMALL_AREA_MAX_CLUSTER
; cluster
++)
498 uint32_t entry
= *(uint32_t *)&nvp_table
[i
* NVP_AREA_TABLE_SIZE
+ cluster
* 4];
501 if(nvp_get_sector_status(entry
) != 0)
503 cprintf(GREY
, "sector already used: area=%d cluster=%d entry=%d\n", i
, cluster
, entry
);
506 nvp_set_sector_status(entry
, 1);
517 int ret
= nvp_read(0, sizeof(version
), &version
);
520 cprintf(BLUE
, "NVP\n");
521 cprintf_field(" Version: ", "%x\n", version
);
523 for(int i
= 0; i
< NVP_NR_AREAS
; i
++)
525 cprintf(RED
, " Area: ");
526 cprintf(GREEN
, "%s\n", nvp_area_info
[i
].name
);
527 if(nvp_area_info
[i
].zone_info
== NULL
)
530 struct nvp_zone_info_entry_t
*zones
= nvp_area_info
[i
].zone_info
;
531 int nr_zones
= nvp_area_info
[i
].nr_zones
;
533 for(int j
= 0; j
< nr_zones
; j
++)
535 cprintf_field(" Zone ", "%s", zones
[j
].name
);
536 cprintf(BLUE
, " ->");
539 int ret
= nvp_read_data(0, i
, j
, 0, buf
, MIN(sz
, zones
[j
].size
));
542 cprintf(RED
, " No data\n");
546 for(int i
= 0; i
< MIN(sz
, zones
[j
].size
); i
++)
547 cprintf(YELLOW
, " %02x", buf
[i
]);
548 cprintf(BLUE
, " -> ");
549 for(int i
= 0; i
< MIN(sz
, zones
[j
].size
); i
++)
550 cprintf(YELLOW
, "%c", isprint(buf
[i
]) ? buf
[i
] : '.');