diff options
Diffstat (limited to 'ubi-utils/src/ubiinfo/ubiinfo.c')
-rw-r--r-- | ubi-utils/src/ubiinfo/ubiinfo.c | 406 |
1 files changed, 406 insertions, 0 deletions
diff --git a/ubi-utils/src/ubiinfo/ubiinfo.c b/ubi-utils/src/ubiinfo/ubiinfo.c new file mode 100644 index 0000000..6f7443b --- /dev/null +++ b/ubi-utils/src/ubiinfo/ubiinfo.c @@ -0,0 +1,406 @@ +/* + * Copyright (c) International Business Machines Corp., 2006 + * + * 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * Print out information about the UBI table this IPL is using. This + * can be used afterwards to analyze misbehavior of the IPL code. The + * input this program requires is the last 1 MiB DDRAM of our system + * where the scanning table is placed into. + * + * Author: Frank Haverkamp <haver@vnet.ibm.com> + */ + +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <time.h> +#include <argp.h> +#include <getopt.h> +#include <stdint.h> +#include <sys/time.h> +#include <netinet/in.h> + +#define __unused __attribute__((unused)) + +/* This should hopefully be constant and the same in all + * configurations. + */ +#define CFG_IPLSIZE 512 +#define CFG_SPLCODE 512 +#define MEMTOP 0x06600000 /* Sunray 102 MiB */ +#define MEMSIZE 0x00100000 /* 1 MiB */ +#define CODE_SIZE (64 * 1024) + +/* FIXME Except of the memory size this should be defined via + * parameters + * + * CFG_MEMTOP_BAMBOO 0x02000000 + * CFG_MEMTOP_SUNRAY 0x06600000 + */ + +#include "ubiipl.h" +#include "ubiflash.h" + +#define MIN(x,y) ((x)<(y)?(x):(y)) + +#define ERR_RET(rc) { \ + fprintf(stderr, "%s:%d failed rc=%d\n", __func__, \ + __LINE__, (rc)); \ + return (rc); \ + } + +#define VERSION "1.3" + +static error_t parse_opt (int key, char *arg, struct argp_state *state); +const char *argp_program_version = VERSION; +const char *argp_program_bug_address = "<haver@vnet.ibm.com>"; + +static char doc[] = "\nVersion: " VERSION "\n\t" + " at "__DATE__" "__TIME__"\n" + "\n" + "Test program\n"; + +static struct argp_option options[] = { + /* common settings */ + { .name = "verbose", + .key = 'v', + .arg = "<level>", + .flags = 0, + .doc = "Set verbosity level to <level>", + .group = OPTION_ARG_OPTIONAL }, + + { .name = "memtop", + .key = 'm', + .arg = "<memtop>", + .flags = 0, + .doc = "Set top of memory, 102 MiB for Sunray and 16 MiB for Bamboo", + .group = OPTION_ARG_OPTIONAL }, + + { .name = NULL, + .key = 0, + .arg = NULL, + .flags = 0, + .doc = NULL, + .group = 0 }, +}; + +typedef struct test_args { + int verbose; + unsigned long memtop; + char *arg1; + char **options; +} test_args; + +static struct test_args g_args = { + .memtop = MEMTOP, + .verbose = 0, + .arg1 = NULL, + .options = NULL, +}; + +static struct argp argp = { + options: options, + parser: parse_opt, + args_doc: "[last_1MiB_memory.bin]", + doc: doc, + children: NULL, + help_filter: NULL, + argp_domain: NULL, +}; + +static int verbose = 0; + +/** + * @brief Parse the arguments passed into the test case. + * + * @param key The parameter. + * @param arg Argument passed to parameter. + * @param state Location to put information on parameters. + * + * @return error_t + */ +static error_t +parse_opt(int key, char *arg, struct argp_state *state) +{ + /* Get the `input' argument from `argp_parse', which we + know is a pointer to our arguments structure. */ + test_args *args = state->input; + + switch (key) { + /* common settings */ + case 'v': /* --verbose=<level> */ + verbose = args->verbose = strtoul(arg, (char **)NULL, 0); + break; + + case 'm': /* --memtop */ + args->memtop = strtoul(arg, (char **)NULL, 0); + break; + + case ARGP_KEY_NO_ARGS: + /* argp_usage(state); */ + break; + + case ARGP_KEY_ARG: + args->arg1 = arg; + /* Now we consume all the rest of the arguments. + `state->next' is the index in `state->argv' of the + next argument to be parsed, which is the first STRING + we're interested in, so we can just use + `&state->argv[state->next]' as the value for + arguments->strings. + + _In addition_, by setting `state->next' to the end + of the arguments, we can force argp to stop parsing + here and return. */ + + args->options = &state->argv[state->next]; + state->next = state->argc; + break; + + case ARGP_KEY_END: + /* print out message if no arguments are given but PFI + write should be done */ + break; + + default: + return(ARGP_ERR_UNKNOWN); + } + return 0; +} + +static void +hexdump(const char *buf, int len) +{ + char line[16]; + char str[256]; + char dummy[256]; + int j = 0; + + while (len > 0) { + int i; + + strcpy(str, " "); + + for (j = 0; j < MIN(16, len); j++) + line[j] = *buf++; + + for (i = 0; i < j; i++) { + if (!(i & 3)) { + sprintf(dummy, " %.2x", line[i] & 0xff); + strcat(str, dummy); + } else { + sprintf(dummy, "%.2x", line[i] & 0xff); + strcat(str, dummy); + } + } + + /* Print empty space */ + for (; i < 16; i++) + if (!(i & 1)) + strcat(str, " "); + else + strcat(str, " "); + + strcat(str, " "); + for (i = 0; i < j; i++) { + if (isprint(line[i])) { + sprintf(dummy, "%c", line[i]); + strcat(str, dummy); + } else { + strcat(str, "."); + } + } + printf("%s\n", str); + len -= 16; + } +} + +static void +print_status_help(void) +{ + printf("Error Codes from IPL\n"); + printf(" IO Error %d\n", STAT_IO_FAILED); + printf(" Block is bad %d\n", STAT_BLOCK_BAD); + printf(" ECC unrec error %d\n", STAT_ECC_ERROR); + printf(" CRC csum failed %d\n", STAT_CRC_ERROR); + printf(" Magic not avail %d\n", STAT_NO_MAGIC); + printf(" No image avail %d\n", STAT_NO_IMAGE); + printf(" Image is invalid %d\n", STAT_INVALID_IMAGE); + printf(" Image is defect %d\n\n", STAT_DEFECT_IMAGE); + +} + +static void +print_ubi_scan_info(struct ubi_scan_info *fi) +{ + int i; + + printf("ubi_scan_info\n"); + printf(" version %08x\n", ntohl(fi->version)); + printf(" bootstatus %08x\n", ntohl(fi->bootstatus)); + printf(" flashtype %08x\n", ntohl(fi->flashtype)); + printf(" flashid %08x\n", ntohl(fi->flashid)); + printf(" flashmfgr %08x\n", ntohl(fi->flashmfr)); + printf(" flashsize %d bytes (%dM)\n", + ntohl(fi->flashsize), ntohl(fi->flashsize) / (1024 * 1024)); + printf(" blocksize %d bytes\n", ntohl(fi->blocksize)); + printf(" blockshift %d\n", ntohl(fi->blockshift)); + printf(" nrblocks %d\n", ntohl(fi->nrblocks)); + printf(" pagesize %d\n", ntohl(fi->pagesize)); + printf(" imagelen %d\n", ntohl(fi->imagelen)); + printf(" blockinfo %08x\n", ntohl((int)fi->blockinfo)); + + printf(" nr imageblocks imageoffs\n"); + for (i = 0; i < UBI_BLOCK_IDENT_MAX; i++) + printf(" [%2d] %08x %08x\n", i, + ntohl(fi->imageblocks[i]), + ntohl(fi->imageoffs[i])); + + for (i = 0; i < UBI_TIMESTAMPS; i++) { + if (!ntohl(fi->times[i])) + continue; + printf("time[%3d] = %08x %.3f sec\n", i, ntohl(fi->times[i]), + (double)ntohl(fi->times[i]) / 500000000.0); + } + + printf("crc32_table\n"); + hexdump((char *)&fi->crc32_table, sizeof(fi->crc32_table)); + printf("\npage_buf\n"); + hexdump((char *)&fi->page_buf, sizeof(fi->page_buf)); + + printf("\n"); + +} + +static void +print_ubi_block_info(struct ubi_scan_info *fi, + struct ubi_vid_hdr *bi, int nr) +{ + int i; + int unknown = 0; + + printf("\nBINFO\n"); + + for (i = 0; i < nr; i++) { + if ((int)ubi32_to_cpu(bi[i].magic) != UBI_VID_HDR_MAGIC) { + printf("block=%d %08x\n", + i, i * ntohl(fi->blocksize)); +#if 0 + printf("."); + if ((unknown & 0x3f) == 0x3f) + printf("\n"); + unknown++; +#else + hexdump((char *)&bi[i], + sizeof(struct ubi_vid_hdr)); +#endif + } else { + if (unknown) + printf("\n"); + printf("block=%d %08x\n" + " leb_ver=0x%x data_size=%d " + "lnum=%d used_ebs=0x%x\n" + " data_crc=%08x hdr_crc=%08x\n", + i, i * ntohl(fi->blocksize), + ubi32_to_cpu(bi[i].leb_ver), + ubi32_to_cpu(bi[i].data_size), + ubi32_to_cpu(bi[i].lnum), + ubi32_to_cpu(bi[i].used_ebs), + ubi32_to_cpu(bi[i].data_crc), + ubi32_to_cpu(bi[i].hdr_crc)); + hexdump((char *)&bi[i], + sizeof(struct ubi_vid_hdr)); + unknown = 0; + } + } +} + +static int do_read(unsigned int memtop, char *buf, int buf_len __unused) +{ + unsigned long finfo_addr; + unsigned long binfo_addr; + unsigned long images_addr; + unsigned long nrblocks; + unsigned long bi_size; + unsigned long images_size; + struct ubi_scan_info *fi; + struct ubi_vid_hdr *bi; + char *images; + unsigned long memaddr = memtop - MEMSIZE; + + print_status_help(); + + /* Read and print FINFO */ + finfo_addr = MEMSIZE - CFG_IPLSIZE * 1024; + + printf("read info at addr %08lx\n", finfo_addr); + fi = (struct ubi_scan_info *)(buf + finfo_addr); + + binfo_addr = ntohl((unsigned long)fi->blockinfo) - memaddr; + images_addr = ntohl((unsigned long)fi->images) - memaddr; + nrblocks = ntohl(fi->nrblocks); + + printf("BINFO %08lx\n", binfo_addr); + + bi_size = nrblocks * sizeof(struct ubi_vid_hdr); + images_size = nrblocks * sizeof(unsigned int); + + printf("FINFO\n"); + print_ubi_scan_info(fi); + /* hexdump((char *)fi, sizeof(*fi)); */ + + /* Read and print BINFO */ + bi = (struct ubi_vid_hdr *)(buf + binfo_addr); + print_ubi_block_info(fi, bi, nrblocks); + + /* Read and print IMAGES */ + images = buf + images_addr; + printf("\nIMAGES\n"); + hexdump(images, images_size); + + return 0; +} + +int main(int argc, char *argv[]) +{ + char buf[MEMSIZE]; + FILE *fp; + int rc; + + argp_parse(&argp, argc, argv, ARGP_IN_ORDER, 0, &g_args); + + if (!g_args.arg1) { + fprintf(stderr, "Please specify a file " + "name for memory dump!\n"); + exit(EXIT_FAILURE); + } + + memset(buf, 0xAB, sizeof(buf)); + + fp = fopen(g_args.arg1, "r"); + if (!fp) + exit(EXIT_FAILURE); + rc = fread(buf, 1, sizeof(buf), fp); + if (rc != sizeof(buf)) + exit(EXIT_FAILURE); + fclose(fp); + do_read(g_args.memtop, buf, sizeof(buf)); + + exit(EXIT_SUCCESS); +} |