diff options
Diffstat (limited to 'ubi-utils/src/ubiinfo')
-rw-r--r-- | ubi-utils/src/ubiinfo/ubiflash.h | 185 | ||||
-rw-r--r-- | ubi-utils/src/ubiinfo/ubiinfo.c | 406 | ||||
-rw-r--r-- | ubi-utils/src/ubiinfo/ubiipl.h | 87 |
3 files changed, 678 insertions, 0 deletions
diff --git a/ubi-utils/src/ubiinfo/ubiflash.h b/ubi-utils/src/ubiinfo/ubiflash.h new file mode 100644 index 0000000..6883879 --- /dev/null +++ b/ubi-utils/src/ubiinfo/ubiflash.h @@ -0,0 +1,185 @@ +#ifndef _UBI_FLASH_H +#define _UBI_FLASH_H +/* + * 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. + */ + +/* + * FLASH related data structures and constants for UBI. + * UBI scan analysis. + * + * IPL Initial Program Loader + * SPL Secondary Program Loader + */ + +#include <stdint.h> +#include <asm/byteorder.h> +#include <mtd/ubi-header.h> + +#define UBI_BLOCK_IDENT_MAX 16 + +/* Block status information constants */ +enum blockstat { + /* IO Error */ + STAT_IO_FAILED = 1, /* 0xffffffff */ + /* Block is bad */ + STAT_BLOCK_BAD = 2, /* 0xfffffffe */ + /* ECC unrecoverable error */ + STAT_ECC_ERROR = 3, /* 0xfffffffd */ + /* CRC checksum failed */ + STAT_CRC_ERROR = 4, /* 0xfffffffc */ + /* Magic number not available */ + STAT_NO_MAGIC = 5, /* 0xfffffffb */ + /* No image available */ + STAT_NO_IMAGE = 6, + /* Image is invalid */ + STAT_INVALID_IMAGE = 7, + /* Image is defect */ + STAT_DEFECT_IMAGE = 8, +}; + +/* + * Flash types + */ +enum flashtypes { + FLASH_TYPE_NAND = 1, + FLASH_TYPE_NOR, +}; + +/* Nand read buffer size: 2KiB + 64byte spare */ +#define NAND_READ_BUF_SIZE (2048 + 64) + +/* Size of the CRC table */ +#define CRC32_TABLE_SIZE 256 + +/* Image is not available marker for image offs */ +#define UBI_IMAGE_NOT_AVAILABLE 0xFFFFFFFF + +/* Increment this number, whenever you change the structure */ +#define UBI_SCAN_INFO_VERSION 2 + +/* Time measurement as far as the code size allows us to do this */ +#define UBI_TIMESTAMPS 16 + +/** + * struct ubi_scan_info - RAM table filled by IPL scan + * + * @version: Version of the structure + * @bootstatus: Boot status of the current boot + * @flashtype: Flash type (NAND/NOR) + * @flashid: ID of the flash chip + * @flashmfr: Manufacturer ID of the flash chip + * @flashsize: Size of the FLASH + * @blocksize: Eraseblock size + * @blockshift: Shift count to calc block number from offset + * @nrblocks: Number of erase blocks on flash + * @pagesize: Pagesize (NAND) + * @blockinfo: Pointer to an array of block status information + * filled by FLASH scan + * @images: Pointer to FLASH block translation table sorted + * by image type and load order + * @imageblocks: Number of blocks found per image + * @imageoffs: Offset per imagetype to the first + * block in the translation table + * @imagedups duplicate blocks (max. one per volume) + * @imagelen: Length of the loaded image + * @crc32_table: CRC32 table buffer + * @page_buf: Page buffer for NAND FLASH + */ +struct ubi_scan_info { + int version; + unsigned int bootstatus; + unsigned int flashtype; + unsigned int flashid; + unsigned int flashmfr; + unsigned int flashsize; + unsigned int blocksize; + unsigned int blockshift; + unsigned int nrblocks; + unsigned int pagesize; + + struct ubi_vid_hdr *blockinfo; + struct ubi_vid_hdr **images; + unsigned int imageblocks[UBI_BLOCK_IDENT_MAX]; + unsigned int imageoffs[UBI_BLOCK_IDENT_MAX]; + struct ubi_vid_hdr *imagedups[UBI_BLOCK_IDENT_MAX]; + unsigned int imagelen; + uint32_t crc32_table[CRC32_TABLE_SIZE]; + uint8_t page_buf[NAND_READ_BUF_SIZE]; + unsigned int times[UBI_TIMESTAMPS]; +}; + +/* External function definition */ +extern int flash_read(void *buf, unsigned int offs, int len); +extern int flash_read_slice(struct ubi_scan_info *fi, void *buf, + unsigned int offs, int len); +extern void ipl_main(struct ubi_scan_info *fi); + +#ifndef CFG_EXAMPLE_IPL +extern int ipl_scan(struct ubi_scan_info *fi); +extern int ipl_load(struct ubi_scan_info *fi, int nr, uint8_t *loadaddr); + +#define IPL_STATIC + +#else +#define IPL_STATIC static +#endif + +/** + * get_boot_status - get the boot status register + * + * Shift the lower 16 bit into the upper 16 bit and return + * the result. + */ +uint32_t get_boot_status(void); + +/** + * set_boot_status - Set the boot status register + * + * @status: The status value to set + * + */ +void set_boot_status(uint32_t status); + +static inline unsigned int ubi_vid_offset(struct ubi_scan_info *fi) +{ + if (fi->flashtype == FLASH_TYPE_NOR) + return UBI_EC_HDR_SIZE; + else + return fi->pagesize - UBI_VID_HDR_SIZE; +} + +static inline unsigned int ubi_data_offset(struct ubi_scan_info *fi) +{ + if (fi->flashtype == FLASH_TYPE_NOR) + return UBI_EC_HDR_SIZE + UBI_VID_HDR_SIZE; + else + return fi->pagesize; +} + +/** + * IPL checkpoints + */ +#define CHKP_HWINIT 0x3030 +#define CHKP_IPLSCAN_FAILED 0x3034 +#define CHKP_SPL_START 0x3037 +#define CHKP_SPLLOAD_STATUS 0x3130 + +extern void checkpoint(uint32_t cpoint); +extern void switch_watchdog(void); + +#endif 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); +} diff --git a/ubi-utils/src/ubiinfo/ubiipl.h b/ubi-utils/src/ubiinfo/ubiipl.h new file mode 100644 index 0000000..3a8b900 --- /dev/null +++ b/ubi-utils/src/ubiinfo/ubiipl.h @@ -0,0 +1,87 @@ +#ifndef _UBI_IPL_H +#define _UBI_IPL_H +/* + * 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. + */ + +/* + * Constants calculated from the CFG_XXX defines + * + * Declaration of the loader function which is invoked by the + * assembler part of the IPL + */ + +/* Size of IPL - is 4K for NAND and can also be 4K for NOR */ +#define IPL_SIZE 4096 + +/* Needed in asm code to upload the data, needed in C-code for CRC32 */ +#define IPL_RAMADDR (CFG_MEMTOP - IPL_SIZE) + +#if !defined(__ASSEMBLY__) + +#include <stdint.h> +#include <mtd/ubi-header.h> + +/* Address of the flash info structure */ +#define FINFO_ADDR (struct ubi_scan_info *) (CFG_MEMTOP - CFG_IPLSIZE * 1024) + +/* Size of the flash info structure */ +#define FINFO_SIZE sizeof(struct ubi_scan_info) + +/* Blockinfo array address */ +#define BINFO_ADDR (struct ubi_vid_hdr *) ((void *)FINFO_ADDR + FINFO_SIZE) + +/* Number of erase blocks */ +#define NR_ERASE_BLOCKS ((CFG_FLASHSIZE * 1024) / CFG_BLOCKSIZE) + +/* Blockinfo size */ +#define BINFO_SIZE (NR_ERASE_BLOCKS * sizeof(struct ubi_vid_hdr)) + +/* Images array address */ +#define IMAGES_ADDR (struct ubi_vid_hdr **) ((void *)BINFO_ADDR + BINFO_SIZE) + +/* Images array size */ +#define IMAGES_SIZE (NR_ERASE_BLOCKS * sizeof(unsigned int)) + +/* Total size of flash info + blockinfo + images */ +#define INFO_SIZE ((FINFO_SIZE + BINFO_SIZE + IMAGES_SIZE) / sizeof(uint32_t)) + +/* Load address of the SPL */ +#define SPL_ADDR (void *) ((void *)FINFO_ADDR - CFG_SPLCODE * 1024) + +#define IPL_SIZE_CRC32 (IPL_SIZE - sizeof(uint32_t)) +#define IPL_RAMADDR_CRC32 ((void *)(IPL_RAMADDR + sizeof(uint32_t))) + +/* + * Linker script magic to ensure that load_spl() is linked to the + * right place + */ +#define __crc32 __attribute__((__section__(".crc32"))) +#define __entry __attribute__((__section__(".entry.text"))) +#define __unused __attribute__((unused)) + +#define MIN(x,y) ((x)<(y)?(x):(y)) + +#define stop_on_error(x) \ + { while (1); } + +void __entry load_spl(void); +void hardware_init(void); + +#endif /* __ASSEMBLY__ */ + +#endif |