Introduce emmctools for the sony nwz players.
This tool is specific to the em1/mp200 sony based players. In deals with raw emmc images (which is possible but hard to get). This tool is also useful as a documentation of the underlying emmc format used for a future port. Change-Id: I66c9b0e47351e5d89f6a404aa62038e00fdc1093
This commit is contained in:
parent
b19b250de7
commit
8c1a9f5082
6 changed files with 1004 additions and 0 deletions
20
utils/nwztools/emmctools/Makefile
Normal file
20
utils/nwztools/emmctools/Makefile
Normal file
|
@ -0,0 +1,20 @@
|
|||
DEFINES=
|
||||
CC=gcc
|
||||
LD=gcc
|
||||
CFLAGS=-g -std=c99 -W -Wall $(DEFINES)
|
||||
LDFLAGS=
|
||||
BINS=emmctool
|
||||
|
||||
all: $(BINS)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
emmctool: emmctool.o misc.o nvp.o
|
||||
$(LD) -o $@ $^ $(LDFLAGS)
|
||||
|
||||
clean:
|
||||
rm -fr *.o
|
||||
|
||||
veryclean:
|
||||
rm -rf $(BINS)
|
242
utils/nwztools/emmctools/emmctool.c
Normal file
242
utils/nwztools/emmctools/emmctool.c
Normal file
|
@ -0,0 +1,242 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2012 Amaury Pouly
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <getopt.h>
|
||||
#include <stdarg.h>
|
||||
#include <ctype.h>
|
||||
#include "misc.h"
|
||||
#include <sys/stat.h>
|
||||
#include <openssl/md5.h>
|
||||
#include "nvp.h"
|
||||
|
||||
bool g_debug = false;
|
||||
char *g_out_prefix = NULL;
|
||||
FILE *g_in_file = NULL;
|
||||
bool g_force = false;
|
||||
|
||||
#define let_the_force_flow(x) do { if(!g_force) return x; } while(0)
|
||||
#define continue_the_force(x) if(x) let_the_force_flow(x)
|
||||
|
||||
#define check_field(v_exp, v_have, str_ok, str_bad) \
|
||||
if((v_exp) != (v_have)) \
|
||||
{ cprintf(RED, str_bad); let_the_force_flow(__LINE__); } \
|
||||
else { cprintf(RED, str_ok); }
|
||||
|
||||
#define errorf(...) do { cprintf(GREY, __VA_ARGS__); return __LINE__; } while(0)
|
||||
|
||||
static void print_hex(void *p, int size, int unit)
|
||||
{
|
||||
uint8_t *p8 = p;
|
||||
uint16_t *p16 = p;
|
||||
uint32_t *p32 = p;
|
||||
for(int i = 0; i < size; i += unit, p8++, p16++, p32++)
|
||||
{
|
||||
if(i != 0 && (i % 16) == 0)
|
||||
printf("\n");
|
||||
if(unit == 1)
|
||||
printf(" %02x", *p8);
|
||||
else if(unit == 2)
|
||||
printf(" %04x", *p16);
|
||||
else
|
||||
printf(" %08x", *p32);
|
||||
}
|
||||
}
|
||||
|
||||
#define SECTOR 512u
|
||||
#define EMMC_MINIBOOT_START 0
|
||||
#define EMMC_MINIBOOT_SIZE (8 * SECTOR)
|
||||
#define EMMC_UBOOT_START (8 * SECTOR)
|
||||
#define EMMC_FU_LINUX_START (512 * SECTOR)
|
||||
#define EMMC_LINUX_START (66048 * SECTOR)
|
||||
#define EMMC_NVP_START ((512 + 32768) * SECTOR)
|
||||
#define EMMC_NVP_SIZE (30720 * SECTOR)
|
||||
|
||||
#define print_entry(begin, end, ...) \
|
||||
do{ cprintf(YELLOW, " %08x %08x ", begin, end); cprintf(GREEN, __VA_ARGS__); } while(0)
|
||||
|
||||
static int read(uint32_t offset, uint32_t size, void *buf)
|
||||
{
|
||||
if(fseek(g_in_file, offset, SEEK_SET))
|
||||
errorf("Cannot seek in file: %m\n");
|
||||
if(fread(buf, size, 1, g_in_file) != 1)
|
||||
errorf("Cannot read in file: %m\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nvp_read(uint32_t offset, uint32_t size, void *buf)
|
||||
{
|
||||
if(offset + size > EMMC_NVP_SIZE)
|
||||
errorf("nvp read out of nvp area\n");
|
||||
return read(offset + EMMC_NVP_START, size, buf);
|
||||
}
|
||||
|
||||
// returns size or 0
|
||||
static uint32_t do_image(uint32_t start, const char *name)
|
||||
{
|
||||
uint32_t size;
|
||||
int ret = read(start, sizeof(size), &size);
|
||||
if(ret) return ret;
|
||||
/* actual uboot size contains 4 bytes for the size, 4 for the crc pad and
|
||||
* must be ronded to the next sector */
|
||||
size = ROUND_UP(size + 8, SECTOR);
|
||||
|
||||
print_entry(start, start + size, name);
|
||||
|
||||
/* Check U-Boot crc (must be 0) */
|
||||
uint32_t crc_buffer[SECTOR / 4];
|
||||
uint32_t crc = 0;
|
||||
uint32_t pos = start + 4;
|
||||
uint32_t rem_size = size - 4;
|
||||
while(rem_size)
|
||||
{
|
||||
ret = read(pos, SECTOR, crc_buffer);
|
||||
if(ret) return ret;
|
||||
uint32_t sz = MIN(rem_size, SECTOR);
|
||||
for(unsigned i = 0; i < sz / 4; i++)
|
||||
crc ^= crc_buffer[i];
|
||||
pos += sz;
|
||||
rem_size -= sz;
|
||||
}
|
||||
|
||||
if(crc == 0)
|
||||
{
|
||||
cprintf(RED, " (CRC Ok)\n");
|
||||
return size;
|
||||
}
|
||||
else
|
||||
{
|
||||
cprintf(RED, " (CRC Mismatch)\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int do_emmc(void)
|
||||
{
|
||||
cprintf(BLUE, "eMMC map\n");
|
||||
cprintf(RED, " begin end comment\n");
|
||||
|
||||
print_entry(EMMC_MINIBOOT_START, EMMC_MINIBOOT_START + EMMC_MINIBOOT_SIZE, "eMMC Mini Boot\n");
|
||||
|
||||
uint32_t uboot_size = do_image(EMMC_UBOOT_START, "U-Boot");
|
||||
if(!uboot_size)
|
||||
return 1;
|
||||
|
||||
uint32_t fulinux_start = EMMC_UBOOT_START + uboot_size;
|
||||
uint32_t fulinux_size = do_image(fulinux_start, "FU Linux");
|
||||
if(!fulinux_size)
|
||||
return 1;
|
||||
|
||||
uint32_t fu_initrd_size = do_image(EMMC_FU_LINUX_START, "FU initrd");
|
||||
if(!fu_initrd_size)
|
||||
return 1;
|
||||
|
||||
print_entry(EMMC_NVP_START, EMMC_NVP_START + EMMC_NVP_SIZE, "NVP\n");
|
||||
|
||||
uint32_t linux_size = do_image(EMMC_LINUX_START, "Linux");
|
||||
if(!linux_size)
|
||||
return 1;
|
||||
|
||||
int ret = nvp_info();
|
||||
continue_the_force(ret);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
printf("Usage: emmctool [options] img\n");
|
||||
printf("Options:\n");
|
||||
printf(" -o <prefix>\tSet output prefix\n");
|
||||
printf(" -f/--force\tForce to continue on errors\n");
|
||||
printf(" -?/--help\tDisplay this message\n");
|
||||
printf(" -d/--debug\tDisplay debug messages\n");
|
||||
printf(" -c/--no-color\tDisable color output\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
while(1)
|
||||
{
|
||||
static struct option long_options[] =
|
||||
{
|
||||
{"help", no_argument, 0, '?'},
|
||||
{"debug", no_argument, 0, 'd'},
|
||||
{"no-color", no_argument, 0, 'c'},
|
||||
{"force", no_argument, 0, 'f'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
int c = getopt_long(argc, argv, "?dcfo:", long_options, NULL);
|
||||
if(c == -1)
|
||||
break;
|
||||
switch(c)
|
||||
{
|
||||
case -1:
|
||||
break;
|
||||
case 'c':
|
||||
enable_color(false);
|
||||
break;
|
||||
case 'd':
|
||||
g_debug = true;
|
||||
break;
|
||||
case 'f':
|
||||
g_force = true;
|
||||
break;
|
||||
case '?':
|
||||
usage();
|
||||
break;
|
||||
case 'o':
|
||||
g_out_prefix = optarg;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
if(argc - optind != 1)
|
||||
{
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
g_in_file = fopen(argv[optind], "rb");
|
||||
if(g_in_file == NULL)
|
||||
{
|
||||
perror("Cannot open boot file");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ret = nvp_init(EMMC_NVP_SIZE, &nvp_read, g_debug);
|
||||
if(ret) return ret;
|
||||
ret = do_emmc();
|
||||
|
||||
fclose(g_in_file);
|
||||
|
||||
color(OFF);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
53
utils/nwztools/emmctools/misc.c
Normal file
53
utils/nwztools/emmctools/misc.c
Normal file
|
@ -0,0 +1,53 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2010 Amaury Pouly
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <ctype.h>
|
||||
#include "misc.h"
|
||||
|
||||
char OFF[] = { 0x1b, 0x5b, 0x31, 0x3b, '0', '0', 0x6d, '\0' };
|
||||
|
||||
char GREY[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '0', 0x6d, '\0' };
|
||||
char RED[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '1', 0x6d, '\0' };
|
||||
char GREEN[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '2', 0x6d, '\0' };
|
||||
char YELLOW[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '3', 0x6d, '\0' };
|
||||
char BLUE[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '4', 0x6d, '\0' };
|
||||
|
||||
static bool g_color_enable = true;
|
||||
|
||||
void *xmalloc(size_t s)
|
||||
{
|
||||
void * r = malloc(s);
|
||||
if(!r) bugp("malloc");
|
||||
return r;
|
||||
}
|
||||
|
||||
void enable_color(bool enable)
|
||||
{
|
||||
g_color_enable = enable;
|
||||
}
|
||||
|
||||
void color(color_t c)
|
||||
{
|
||||
if(g_color_enable)
|
||||
printf("%s", (char *)c);
|
||||
}
|
50
utils/nwztools/emmctools/misc.h
Normal file
50
utils/nwztools/emmctools/misc.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2010 Amaury Pouly
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#ifndef __MISC_H__
|
||||
#define __MISC_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define _STR(a) #a
|
||||
#define STR(a) _STR(a)
|
||||
|
||||
#define bug(...) do { fprintf(stderr,"["__FILE__":"STR(__LINE__)"]ERROR: "__VA_ARGS__); exit(1); } while(0)
|
||||
#define bugp(...) do { fprintf(stderr, __VA_ARGS__); perror(" "); exit(1); } while(0)
|
||||
|
||||
#define ROUND_UP(val, round) ((((val) + (round) - 1) / (round)) * (round))
|
||||
|
||||
typedef char color_t[];
|
||||
|
||||
extern color_t OFF, GREY, RED, GREEN, YELLOW, BLUE;
|
||||
void *xmalloc(size_t s);
|
||||
void color(color_t c);
|
||||
void enable_color(bool enable);
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#define cprintf(col, ...) do {color(col); printf(__VA_ARGS__); }while(0)
|
||||
|
||||
#define cprintf_field(str1, ...) do{ cprintf(GREEN, str1); cprintf(YELLOW, __VA_ARGS__); }while(0)
|
||||
|
||||
#endif /* __MISC_H__ */
|
546
utils/nwztools/emmctools/nvp.c
Normal file
546
utils/nwztools/emmctools/nvp.c
Normal file
|
@ -0,0 +1,546 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2012 Amaury Pouly
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#include "nvp.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
static struct nvp_zone_info_entry_t nvp_zone_ubt[] =
|
||||
{
|
||||
{0x18, 0, 1, 4, 0, 0, 0, 0, "system information"},
|
||||
{0x17, 1, 1, 0x20, 0, 0, 0, 0, "u-boot password"},
|
||||
{9, 2, 1, 4, 0, 0, 0, 0, "firmware update flag"},
|
||||
{0xA, 3, 1, 4, 0, 0, 0, 0, "beep ok flag"},
|
||||
{0x22, 4, 1, 0x10, 0, 0, 0, 0, "rtc alarm"},
|
||||
{0x50, 5, 1, 4, 0, 0, 0, 0, "hold mode"}
|
||||
};
|
||||
|
||||
static struct nvp_zone_info_entry_t nvp_zone_sys[] =
|
||||
{
|
||||
{0x10, 1, 1, 0x40, 0, 0, 0, 0, "model id"},
|
||||
{4, 2, 1, 0x10, 0, 0, 0, 0, "serial number"},
|
||||
{0xB, 3, 1, 0x20, 0, 0, 0, 0, "ship information"},
|
||||
{0x44, 4, 1, 4, 0, 0, 0, 0, "color variation"},
|
||||
{0x1A, 5, 1, 5, 0, 0, 0, 0, "product code"},
|
||||
{0x1D, 6, 1, 8, 0, 0, 0, 0, "update file name"},
|
||||
{0x20, 7, 1, 0x40, 0, 0, 0, 0, "key and signature"},
|
||||
{0x11, 8, 1, 4, 0, 0, 0, 0, "test mode flag"},
|
||||
{0x12, 9, 1, 4, 0, 0, 0, 0, "getty mode flag"},
|
||||
{0x46, 0xA, 1, 4, 0, 0, 0, 0, "disable iptable flag"},
|
||||
{0x1E, 0xB, 1, 0x40, 0, 0, 0, 0, "sound driver parameter"},
|
||||
{0x1F, 0xC, 1, 0x40, 0, 0, 0, 0, "noise cancel driver parameter"},
|
||||
{0x4D, 0xD, 1, 6, 0, 0, 0, 0, "wifi mac address"},
|
||||
{0x4B, 0xE, 1, 4, 0, 0, 0, 0, "wifi protected setup"},
|
||||
{0x52, 0xF, 1, 0x10, 0, 0, 0, 0, "fm parameter"},
|
||||
{0x53, 0x10, 1, 4, 0, 0, 0, 0, "speaker ship info"},
|
||||
{0x54, 0x11, 1, 4, 0, 0, 0, 0, "mass storage class mode"},
|
||||
{0x19, 0x12, 1, 4, 0, 0, 0, 0, "exception monitor mode"},
|
||||
{0x1B, 0x13, 1, 4, 0, 0, 0, 0, "battery calibration"},
|
||||
{0x56, 0x14, 1, 0x200, 0, 0, 0, 0, "bluetooth pskey"}
|
||||
};
|
||||
|
||||
static struct nvp_zone_info_entry_t nvp_zone_app[] =
|
||||
{
|
||||
{5, 0, 8, 0x1000, 0, 0, 0, 0, "application parameter"},
|
||||
{7, 0x40, 1, 0x14, 0, 0, 0, 0, "secure clock"},
|
||||
{0xC, 0x41, 1, 0xA0, 0, 0, 0, 0, "aad icv"},
|
||||
{0xD, 0x42, 2, 0x208, 0, 0, 0, 0, "empr key"},
|
||||
{0x4C, 0x44, 1, 0x10, 0, 0, 0, 0, "slacker time"},
|
||||
{0x15, 0x45, 1, 4, 0, 0, 0, 0, "key mode (debug/release)"},
|
||||
{0x47, 0x46, 1, 0x40, 0, 0, 0, 0, "marlin time"},
|
||||
{0x48, 0x47, 0x20, 0x4000, 0, 0, 0, 0, "marlin crl"},
|
||||
{0x59, 0x76, 1, 0x200, 0, 0, 0, 0, "btmw factory pair info"},
|
||||
{0x58, 0x77, 1, 0x200, 0, 0, 0, 0, "btmw factory scdb"},
|
||||
{0x57, 0x78, 1, 4, 0, 0, 0, 0, "btmw log mode flag"},
|
||||
{0x55, 0x79, 1, 4, 0, 0, 0, 0, "europe vol regulation flag"},
|
||||
{8, 0x7A, 1, 8, 0, 0, 0, 0, "middleware parameter"},
|
||||
{0x16, 0x7B, 1, 4, 0, 0, 0, 0, "quick shutdown flag"},
|
||||
{0x45, 0x7C, 1, 4, 0, 0, 0, 0, "time out to sleep"},
|
||||
{0x4E, 0x7D, 1, 4, 0, 0, 0, 0, "application debug mode flag"},
|
||||
{0x4F, 0x7E, 1, 4, 0, 0, 0, 0, "browser log mode flag"}
|
||||
};
|
||||
|
||||
static struct nvp_zone_info_entry_t nvp_zone_drm[] =
|
||||
{
|
||||
{3, 1, 2, 0x2C0, 0, 0, 0, 0, "aad key"},
|
||||
{0x1C, 6, 1, 0x40, 0, 0, 0, 0, "wmt key"},
|
||||
{0x51, 9, 0x11, 0x2020, 0, 0, 0, 0, "slacker id file"},
|
||||
{0x49, 0x1A, 0x41, 0x8100, 0, 0, 0, 0, "marlin device key"},
|
||||
{0x21, 0x5B, 1, 0x40, 0, 0, 0, 0, "starfish id"},
|
||||
{0x23, 0x5C, 4, 0x800, 0, 0, 0, 0, "bluetooth address"}
|
||||
};
|
||||
|
||||
static struct nvp_zone_info_entry_t nvp_zone_ekb[] =
|
||||
{
|
||||
{0xE, 0, 0x20, 0x4000, 0, 0, 0, 0, "EKB 0"},
|
||||
{0xF, 0x20, 0x20, 0x4000, 0, 0, 0, 0, "EKB 1"},
|
||||
{0x4A, 0x40, 0x30, 0x6000, 0, 0, 0, 0, "marlin user key"}
|
||||
};
|
||||
|
||||
static struct nvp_zone_info_entry_t nvp_zone_emp[] =
|
||||
{
|
||||
{0x24, 0, 2, 0x400, 0, 0, 0, 0, "EMPR 0"},
|
||||
{0x25, 2, 2, 0x400, 0, 0, 0, 0, "EMPR 1"},
|
||||
{0x26, 4, 2, 0x400, 0, 0, 0, 0, "EMPR 2"},
|
||||
{0x27, 6, 2, 0x400, 0, 0, 0, 0, "EMPR 3"},
|
||||
{0x28, 8, 2, 0x400, 0, 0, 0, 0, "EMPR 4"},
|
||||
{0x29, 0xA, 2, 0x400, 0, 0, 0, 0, "EMPR 5"},
|
||||
{0x2A, 0xC, 2, 0x400, 0, 0, 0, 0, "EMPR 6"},
|
||||
{0x2B, 0xE, 2, 0x400, 0, 0, 0, 0, "EMPR 7"},
|
||||
{0x2C, 0x10, 2, 0x400, 0, 0, 0, 0, "EMPR 8"},
|
||||
{0x2D, 0x12, 2, 0x400, 0, 0, 0, 0, "EMPR 9"},
|
||||
{0x2E, 0x14, 2, 0x400, 0, 0, 0, 0, "EMPR 10"},
|
||||
{0x2F, 0x16, 2, 0x400, 0, 0, 0, 0, "EMPR 11"},
|
||||
{0x30, 0x18, 2, 0x400, 0, 0, 0, 0, "EMPR 12"},
|
||||
{0x31, 0x1A, 2, 0x400, 0, 0, 0, 0, "EMPR 13"},
|
||||
{0x32, 0x1C, 2, 0x400, 0, 0, 0, 0, "EMPR 14"},
|
||||
{0x33, 0x1E, 2, 0x400, 0, 0, 0, 0, "EMPR 15"},
|
||||
{0x34, 0x20, 2, 0x400, 0, 0, 0, 0, "EMPR 16"},
|
||||
{0x35, 0x22, 2, 0x400, 0, 0, 0, 0, "EMPR 17"},
|
||||
{0x36, 0x24, 2, 0x400, 0, 0, 0, 0, "EMPR 18"},
|
||||
{0x37, 0x26, 2, 0x400, 0, 0, 0, 0, "EMPR 19"},
|
||||
{0x38, 0x28, 2, 0x400, 0, 0, 0, 0, "EMPR 20"},
|
||||
{0x39, 0x2A, 2, 0x400, 0, 0, 0, 0, "EMPR 21"},
|
||||
{0x3A, 0x2C, 2, 0x400, 0, 0, 0, 0, "EMPR 22"},
|
||||
{0x3B, 0x2E, 2, 0x400, 0, 0, 0, 0, "EMPR 23"},
|
||||
{0x3C, 0x30, 2, 0x400, 0, 0, 0, 0, "EMPR 24"},
|
||||
{0x3D, 0x32, 2, 0x400, 0, 0, 0, 0, "EMPR 25"},
|
||||
{0x3E, 0x34, 2, 0x400, 0, 0, 0, 0, "EMPR 26"},
|
||||
{0x3F, 0x36, 2, 0x400, 0, 0, 0, 0, "EMPR 27"},
|
||||
{0x40, 0x38, 2, 0x400, 0, 0, 0, 0, "EMPR 28"},
|
||||
{0x41, 0x3A, 2, 0x400, 0, 0, 0, 0, "EMPR 29"},
|
||||
{0x42, 0x3C, 2, 0x400, 0, 0, 0, 0, "EMPR 30"},
|
||||
{0x43, 0x3E, 2, 0x400, 0, 0, 0, 0, "EMPR 31"}
|
||||
};
|
||||
|
||||
static struct nvp_zone_info_entry_t nvp_zone_bti[] =
|
||||
{
|
||||
{1, 0, 0x20, 0x40000, 0, 0, 0, 0, "boot image"}
|
||||
};
|
||||
|
||||
static struct nvp_zone_info_entry_t nvp_zone_hdi[] =
|
||||
{
|
||||
{2, 0, 0x20, 0x40000, 0, 0, 0, 0, "hold image"}
|
||||
};
|
||||
|
||||
static struct nvp_zone_info_entry_t nvp_zone_lbi[] =
|
||||
{
|
||||
{0x14, 0, 0x20, 0x40000, 0, 0, 0, 0, "low battery image"}
|
||||
};
|
||||
|
||||
static struct nvp_zone_info_entry_t nvp_zone_upi[] =
|
||||
{
|
||||
{0x13, 0, 0x20, 0x40000, 0, 0, 0, 0, "update image"}
|
||||
};
|
||||
|
||||
static struct nvp_zone_info_entry_t nvp_zone_eri[] =
|
||||
{
|
||||
{6, 0, 0x20, 0x40000, 0, 0, 0, 0, "update error image"}
|
||||
};
|
||||
|
||||
struct nvp_area_info_entry_t nvp_area_info[NVP_NR_AREAS] =
|
||||
{
|
||||
{2, nvp_zone_ubt, 6, 0, 0, 0, 0, "u-boot parameter"},
|
||||
{2, nvp_zone_sys, 0x14, 0, 0, 0, 0, "system parameter"},
|
||||
{2, nvp_zone_app, 0x11, 0, 0, 0, 0, "application parameter"},
|
||||
{2, nvp_zone_drm, 6, 0, 0, 0, 0, "drm data"},
|
||||
{2, nvp_zone_ekb, 3, 0, 0, 0, 0, "ekb data"},
|
||||
{2, nvp_zone_emp, 0x20, 0, 0, 0, 0, "empr data"},
|
||||
{2, 0, 0, 0, 0, 0, 0, "reserved"},
|
||||
{2, 0, 0, 0, 0, 0, 0, "reserved"},
|
||||
{1, nvp_zone_bti, 1, 0, 0, 0, 0, "boot image"},
|
||||
{1, nvp_zone_hdi, 1, 0, 0, 0, 0, "hold image"},
|
||||
{1, nvp_zone_lbi, 1, 0, 0, 0, 0, "low battery image"},
|
||||
{1, nvp_zone_upi, 1, 0, 0, 0, 0, "update image"},
|
||||
{1, nvp_zone_eri, 1, 0, 0, 0, 0, "update error image"},
|
||||
{1, 0, 0, 0, 0, 0, 0, "reserved"},
|
||||
{1, 0, 0, 0, 0, 0, 0, "reserved"},
|
||||
{1, 0, 0, 0, 0, 0, 0, "reserved"}
|
||||
};
|
||||
|
||||
static int nr_nodes;
|
||||
static struct nvp_node_info_t *node_info;
|
||||
static nvp_read_fn_t nvp_read;
|
||||
static int nvp_size;
|
||||
static int nr_sectors;
|
||||
static int nr_clusters;
|
||||
static uint8_t *nvp_table;
|
||||
static uint8_t *nvp_shadow;
|
||||
static uint16_t *nvp_bitmap;
|
||||
|
||||
int nvp_get_cluster_status(int cluster)
|
||||
{
|
||||
if(cluster <= 3 || cluster >= nr_clusters)
|
||||
{
|
||||
cprintf(GREY, "invalid cluster number: cluster=%d\n", cluster);
|
||||
return -1;
|
||||
}
|
||||
return nvp_bitmap[cluster];
|
||||
}
|
||||
|
||||
int nvp_set_cluster_status(int cluster, int status)
|
||||
{
|
||||
if(cluster <= 3 || cluster >= nr_clusters)
|
||||
{
|
||||
cprintf(GREY, "invalid cluster number: cluster=%d\n", cluster);
|
||||
return -1;
|
||||
}
|
||||
nvp_bitmap[cluster] = status;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nvp_get_sector_status(int sector)
|
||||
{
|
||||
if(sector <= 3 || sector >= nr_sectors)
|
||||
{
|
||||
cprintf(GREY, "invalid sector number: sector=%d\n", sector);
|
||||
return -1;
|
||||
}
|
||||
return (nvp_bitmap[sector >> 4] >> (sector & 0xf)) & 0x1;
|
||||
}
|
||||
|
||||
int nvp_set_sector_status(int sector, int status)
|
||||
{
|
||||
if(sector <= 3 || sector >= nr_sectors)
|
||||
{
|
||||
cprintf(GREY, "invalid sector number: sector=%d\n", sector);
|
||||
return -1;
|
||||
}
|
||||
if(status)
|
||||
nvp_bitmap[sector >> 4] |= 1 << (sector & 0xf);
|
||||
else
|
||||
nvp_bitmap[sector >> 4] &= ~(1 << (sector & 0xf));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nvp_get_cluster_number(int shadow, int area, int zone, int index)
|
||||
{
|
||||
int start = nvp_area_info[area].zone_info[zone].start;
|
||||
int count = nvp_area_info[area].zone_info[zone].count;
|
||||
if(index >= count)
|
||||
{
|
||||
cprintf(GREY, "invalid index: index=%d\n", index);
|
||||
return -1;
|
||||
}
|
||||
uint8_t *ptr = shadow ? nvp_shadow : nvp_table;
|
||||
uint16_t cluster = *(uint16_t *)&ptr[area * NVP_AREA_TABLE_SIZE + (start + index) * 2];
|
||||
if(cluster == 0)
|
||||
return 0;
|
||||
if(cluster <= 3 || cluster >= nr_clusters)
|
||||
{
|
||||
cprintf(GREY, "invalid cluster: shadow=%d area=%d zone=%d index=%d cluster=%d\n",
|
||||
shadow, area, zone, index, cluster);
|
||||
return -1;
|
||||
}
|
||||
return cluster;
|
||||
}
|
||||
|
||||
int nvp_get_sector_number(int shadow, int area, int zone, int index)
|
||||
{
|
||||
int start = nvp_area_info[area].zone_info[zone].start;
|
||||
int count = nvp_area_info[area].zone_info[zone].count;
|
||||
if(index >= count)
|
||||
{
|
||||
cprintf(GREY, "invalid index: index=%d\n", index);
|
||||
return -1;
|
||||
}
|
||||
uint8_t *ptr = shadow ? nvp_shadow : nvp_table;
|
||||
uint32_t sector = *(uint32_t *)&ptr[area * NVP_AREA_TABLE_SIZE + (start + index) * 4];
|
||||
if(sector == 0)
|
||||
return 0;
|
||||
if(sector <= 0x3f || sector >= (unsigned)nr_sectors)
|
||||
{
|
||||
cprintf(GREY, "invalid sector: shadow=%d area=%d zone=%d index=%d sector=%d\n",
|
||||
shadow, area, zone, index, sector);
|
||||
return -1;
|
||||
}
|
||||
return sector;
|
||||
}
|
||||
|
||||
int nvp_read_data(int shadow, int area, int zone, int offset, void *buf, int size)
|
||||
{
|
||||
int large = nvp_area_info[area].kind == NVP_AREA_LARGE_KIND;
|
||||
int unit_size = large ? NVP_LARGE_AREA_SIZE : NVP_SMALL_AREA_SIZE;
|
||||
|
||||
while(size > 0)
|
||||
{
|
||||
int index = offset / unit_size;
|
||||
int unit_offset = offset % unit_size;
|
||||
int sec_cluster = large ?
|
||||
nvp_get_cluster_number(shadow, area, zone, index) :
|
||||
nvp_get_sector_number(shadow, area, zone, index);
|
||||
if(sec_cluster == 0)
|
||||
return -1;
|
||||
//cprintf(GREY, "[sec_cluster=%d]", sec_cluster);
|
||||
int read = MIN(size, unit_size - unit_offset);
|
||||
int ret = nvp_read(sec_cluster * unit_size, read, buf);
|
||||
if(ret)
|
||||
return ret;
|
||||
buf += read;
|
||||
offset += read;
|
||||
size -= read;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct nvp_node_info_t nvp_get_node_info(int node)
|
||||
{
|
||||
return node_info[node];
|
||||
}
|
||||
|
||||
int nvp_get_node_size(int node)
|
||||
{
|
||||
struct nvp_node_info_t i = nvp_get_node_info(node);
|
||||
return nvp_area_info[i.area].zone_info[i.zone].size;
|
||||
}
|
||||
|
||||
const char *nvp_get_node_name(int node)
|
||||
{
|
||||
struct nvp_node_info_t i = nvp_get_node_info(node);
|
||||
return nvp_area_info[i.area].zone_info[i.zone].name;
|
||||
}
|
||||
|
||||
const char *nvp_get_area_name(int area)
|
||||
{
|
||||
return nvp_area_info[area].name;
|
||||
}
|
||||
|
||||
int nvp_read_node(int node, int offset, void *buffer, int size)
|
||||
{
|
||||
struct nvp_node_info_t i = nvp_get_node_info(node);
|
||||
return nvp_read_data(0, i.area, i.zone, offset, buffer, size);
|
||||
}
|
||||
|
||||
int nvp_init(int size, nvp_read_fn_t read, bool debug)
|
||||
{
|
||||
nvp_read = read;
|
||||
nvp_size = size;
|
||||
nr_sectors = nvp_size / NVP_SECTOR_SIZE;
|
||||
nr_clusters = (nr_sectors + NVP_SECTOR_PER_CLUSTER) / NVP_SECTOR_PER_CLUSTER;
|
||||
// check that the tables are consistent and compute the number of nodes
|
||||
if(debug)
|
||||
cprintf(BLUE, "NVP Debug\n");
|
||||
for(int i = 0; i < NVP_NR_AREAS; i++)
|
||||
{
|
||||
if(debug)
|
||||
{
|
||||
cprintf(RED, " %s Area: ", nvp_area_info[i].kind == NVP_AREA_SMALL_KIND ? "Small" : "Large");
|
||||
cprintf(GREEN, "%s\n", nvp_area_info[i].name);
|
||||
}
|
||||
if(nvp_area_info[i].zone_info == NULL)
|
||||
continue;
|
||||
|
||||
struct nvp_zone_info_entry_t *zones = nvp_area_info[i].zone_info;
|
||||
int nr_zones = nvp_area_info[i].nr_zones;
|
||||
int kind = nvp_area_info[i].kind;
|
||||
if(kind != NVP_AREA_SMALL_KIND && kind != NVP_AREA_LARGE_KIND)
|
||||
continue;
|
||||
|
||||
uint32_t bitmap[256];
|
||||
memset(bitmap, 0, sizeof(bitmap));
|
||||
|
||||
for(int j = 0; j < nr_zones; j++)
|
||||
{
|
||||
if(debug)
|
||||
{
|
||||
cprintf_field(" Zone ", "%s", zones[j].name);
|
||||
cprintf_field(" Node ", "%d", zones[j].node);
|
||||
cprintf_field(" Start ", "%#x", zones[j].start);
|
||||
cprintf_field(" Count ", "%#x", zones[j].count);
|
||||
cprintf_field(" Size ", "%#x\n", zones[j].size);
|
||||
}
|
||||
|
||||
if(kind == NVP_AREA_LARGE_KIND)
|
||||
{
|
||||
if(zones[j].start >= NVP_LARGE_AREA_MAX_CLUSTER ||
|
||||
zones[j].start + zones[j].count > NVP_LARGE_AREA_MAX_CLUSTER)
|
||||
{
|
||||
cprintf(GREY, "Bad zone start/count\n");
|
||||
return 95;
|
||||
}
|
||||
if(zones[j].size > zones[j].count * NVP_LARGE_AREA_SIZE)
|
||||
{
|
||||
cprintf(GREY, "Bad zone size\n");
|
||||
return 96;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(zones[j].start >= NVP_SMALL_AREA_MAX_CLUSTER ||
|
||||
zones[j].start + zones[j].count > NVP_SMALL_AREA_MAX_CLUSTER)
|
||||
{
|
||||
cprintf(GREY, "Bad zone start/count\n");
|
||||
return 97;
|
||||
}
|
||||
if(zones[j].size > zones[j].count * NVP_SMALL_AREA_SIZE)
|
||||
{
|
||||
cprintf(GREY, "Bad zone size\n");
|
||||
return 98;
|
||||
}
|
||||
}
|
||||
|
||||
nr_nodes++;
|
||||
|
||||
for(int k = 0; k < zones[j].count; k++)
|
||||
{
|
||||
if(bitmap[zones[j].start + k])
|
||||
{
|
||||
cprintf(GREY, "Zone overlap !\n");
|
||||
return 99;
|
||||
}
|
||||
bitmap[zones[j].start + k] = 0xffffffff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// build node table
|
||||
nr_nodes++; // nodes start at 1 ?!
|
||||
node_info = malloc(nr_nodes * sizeof(struct nvp_node_info_t));
|
||||
memset(node_info, 0xff, nr_nodes * sizeof(struct nvp_node_info_t));
|
||||
|
||||
for(int i = 0; i < NVP_NR_AREAS; i++)
|
||||
{
|
||||
if(nvp_area_info[i].zone_info == NULL)
|
||||
continue;
|
||||
|
||||
struct nvp_zone_info_entry_t *zones = nvp_area_info[i].zone_info;
|
||||
int nr_zones = nvp_area_info[i].nr_zones;
|
||||
int kind = nvp_area_info[i].kind;
|
||||
if(kind != NVP_AREA_SMALL_KIND && kind != NVP_AREA_LARGE_KIND)
|
||||
continue;
|
||||
|
||||
for(int j = 0; j < nr_zones; j++)
|
||||
{
|
||||
int node = zones[j].node;
|
||||
if(node >= nr_nodes)
|
||||
{
|
||||
cprintf(GREY, "Node out of bounds !\n");
|
||||
return 89;
|
||||
}
|
||||
if(node_info[node].area != -1 && node_info[node].zone != -1)
|
||||
{
|
||||
cprintf(GREY, "Node overlap: area=%d zone=%d node=%d to area=%d zone=%d !\n",
|
||||
i, j, node, node_info[node].area, node_info[node].zone);
|
||||
return 88;
|
||||
}
|
||||
node_info[node].area = i;
|
||||
node_info[node].zone = j;
|
||||
}
|
||||
}
|
||||
|
||||
// load allocation table
|
||||
nvp_table = malloc(NVP_CLUSTER_SIZE);
|
||||
int ret = nvp_read(NVP_TABLE_SECTOR * NVP_SECTOR_SIZE, NVP_CLUSTER_SIZE, nvp_table);
|
||||
if(ret) return ret;
|
||||
|
||||
// init shadow table
|
||||
nvp_shadow = malloc(NVP_CLUSTER_SIZE);
|
||||
memset(nvp_shadow, 0, NVP_CLUSTER_SIZE);
|
||||
|
||||
// init bitmap
|
||||
nvp_bitmap = malloc(sizeof(uint16_t) * nr_clusters);
|
||||
memset(nvp_bitmap, 0, sizeof(uint16_t) * nr_clusters);
|
||||
|
||||
// read map
|
||||
for(int i = 0; i < NVP_NR_AREAS; i++)
|
||||
{
|
||||
if(nvp_area_info[i].zone_info == NULL)
|
||||
continue;
|
||||
int kind = nvp_area_info[i].kind;
|
||||
if(kind != NVP_AREA_SMALL_KIND && kind != NVP_AREA_LARGE_KIND)
|
||||
continue;
|
||||
|
||||
if(kind == NVP_AREA_LARGE_KIND)
|
||||
{
|
||||
for(int cluster = 0; cluster < NVP_LARGE_AREA_MAX_CLUSTER; cluster++)
|
||||
{
|
||||
uint16_t entry = *(uint16_t *)&nvp_table[i * NVP_AREA_TABLE_SIZE + cluster * 2];
|
||||
if(entry == 0)
|
||||
continue;
|
||||
if(nvp_get_cluster_status(entry) != 0)
|
||||
{
|
||||
cprintf(GREY, "cluster already used: area=%d cluster=%d entry=%d\n", i, cluster, entry);
|
||||
return 78;
|
||||
}
|
||||
nvp_set_cluster_status(entry, 0xffff);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(int cluster = 0; cluster < NVP_SMALL_AREA_MAX_CLUSTER; cluster++)
|
||||
{
|
||||
uint32_t entry = *(uint32_t *)&nvp_table[i * NVP_AREA_TABLE_SIZE + cluster * 4];
|
||||
if(entry == 0)
|
||||
continue;
|
||||
if(nvp_get_sector_status(entry) != 0)
|
||||
{
|
||||
cprintf(GREY, "sector already used: area=%d cluster=%d entry=%d\n", i, cluster, entry);
|
||||
return 76;
|
||||
}
|
||||
nvp_set_sector_status(entry, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nvp_info(void)
|
||||
{
|
||||
uint32_t version;
|
||||
int ret = nvp_read(0, sizeof(version), &version);
|
||||
if(ret) return ret;
|
||||
|
||||
cprintf(BLUE, "NVP\n");
|
||||
cprintf_field(" Version: ", "%x\n", version);
|
||||
|
||||
for(int i = 0; i < NVP_NR_AREAS; i++)
|
||||
{
|
||||
cprintf(RED, " Area: ");
|
||||
cprintf(GREEN, "%s\n", nvp_area_info[i].name);
|
||||
if(nvp_area_info[i].zone_info == NULL)
|
||||
continue;
|
||||
|
||||
struct nvp_zone_info_entry_t *zones = nvp_area_info[i].zone_info;
|
||||
int nr_zones = nvp_area_info[i].nr_zones;
|
||||
|
||||
for(int j = 0; j < nr_zones; j++)
|
||||
{
|
||||
cprintf_field(" Zone ", "%s", zones[j].name);
|
||||
cprintf(BLUE, " ->");
|
||||
uint8_t buf[0x20];
|
||||
int ret = nvp_read_data(0, i, j, 0, buf, MIN(0x20, zones[j].size));
|
||||
if(ret)
|
||||
{
|
||||
cprintf(RED, " No data\n");
|
||||
continue;
|
||||
}
|
||||
for(int i = 0; i < MIN(0x20, zones[j].size); i++)
|
||||
cprintf(YELLOW, " %02x", buf[i]);
|
||||
cprintf(BLUE, " -> ");
|
||||
for(int i = 0; i < MIN(0x20, zones[j].size); i++)
|
||||
cprintf(YELLOW, "%c", isprint(buf[i]) ? buf[i] : '.');
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
93
utils/nwztools/emmctools/nvp.h
Normal file
93
utils/nwztools/emmctools/nvp.h
Normal file
|
@ -0,0 +1,93 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2012 Amaury Pouly
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#ifndef __NVP_H__
|
||||
#define __NVP_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "misc.h"
|
||||
|
||||
#define NVP_AREA_LARGE_KIND 1
|
||||
#define NVP_AREA_SMALL_KIND 2
|
||||
|
||||
#define NVP_SMALL_AREA_MAX_CLUSTER 128
|
||||
#define NVP_LARGE_AREA_MAX_CLUSTER 256
|
||||
#define NVP_AREA_TABLE_SIZE 512
|
||||
|
||||
#define NVP_SECTOR_SIZE 512
|
||||
#define NVP_TABLE_SECTOR 16
|
||||
#define NVP_DATA_SECTOR_MIN 64
|
||||
#define NVP_DATA_SECTOR_MAX 32767
|
||||
#define NVP_SECTOR_PER_CLUSTER 16
|
||||
#define NVP_CLUSTER_SIZE (NVP_SECTOR_SIZE * NVP_SECTOR_PER_CLUSTER)
|
||||
|
||||
#define NVP_LARGE_AREA_SIZE NVP_CLUSTER_SIZE
|
||||
#define NVP_SMALL_AREA_SIZE NVP_SECTOR_SIZE
|
||||
|
||||
struct nvp_zone_info_entry_t
|
||||
{
|
||||
int node;
|
||||
int start; // in 4 unit
|
||||
int count; // in 512 unit for kind 2 and in 8192 for kind 1
|
||||
int size;
|
||||
int res0, res1, res2, res3;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
struct nvp_area_info_entry_t
|
||||
{
|
||||
int kind;
|
||||
struct nvp_zone_info_entry_t *zone_info;
|
||||
int nr_zones;
|
||||
int res0, res1, res2, res3;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
struct nvp_node_info_t
|
||||
{
|
||||
int area;
|
||||
int zone;
|
||||
};
|
||||
|
||||
#define NVP_NR_AREAS 16
|
||||
|
||||
extern struct nvp_area_info_entry_t nvp_area_info[NVP_NR_AREAS];
|
||||
|
||||
typedef int (*nvp_read_fn_t)(uint32_t offset, uint32_t size, void *buf);
|
||||
|
||||
int nvp_init(int nvp_size, nvp_read_fn_t read, bool debug);
|
||||
struct nvp_node_info_t nvp_get_node_info(int node);
|
||||
int nvp_get_node_size(int node);
|
||||
const char *nvp_get_node_name(int node);
|
||||
const char *nvp_get_area_name(int node);
|
||||
int nvp_read_node(int node, int offset, void *buffer, int size);
|
||||
|
||||
int nvp_info(void);
|
||||
|
||||
int nvp_get_cluster_status(int cluster);
|
||||
int nvp_set_cluster_status(int cluster, int status);
|
||||
int nvp_get_sector_status(int sector);
|
||||
int nvp_set_sector_status(int sector, int status);
|
||||
int nvp_get_cluster_number(int shadow, int area, int zone, int index);
|
||||
int nvp_get_sector_number(int shadow, int area, int zone, int index);
|
||||
int nvp_read_data(int shadow, int area, int zone, int offset, void *buffer, int size);
|
||||
|
||||
#endif /* __NVP_H__ */
|
Loading…
Reference in a new issue