/************************************************************************** * * * Copyright (C) 1996, Silicon Graphics, Inc. * * * * These coded instructions, statements, and computer programs contain * * unpublished proprietary information of Silicon Graphics, Inc., and * * are protected by Federal copyright law. They may not be disclosed * * to third parties or copied or duplicated in any form, in whole or * * in part, without the prior written consent of Silicon Graphics, Inc. * * * **************************************************************************/ #if defined(IP30) #include #include #include #include #include #include #include #include #include #include "flash_prom_cmd.h" static int _fl_copy(__psunsigned_t src, __psunsigned_t dst, int len); #define FCMD_CHECK 0x1 /* * command structure */ typedef struct flash_cmd flash_cmd_t; struct flash_cmd { char *cmd; int (*func)(int, char **, flash_cmd_t *); char *usage; unsigned flags; }; #define FLASH_USAGE(_p) FPR_PR(("flash %s %s\n", (_p)->cmd, (_p)->usage)) SETUP_TIME #ifdef FDEBUG unsigned long long _cksum64(unsigned long long *lp, int len, unsigned long long sum) { len &= ~0x7; /* trucate to mod(8)==0 */ while (len) { sum = sum + *lp++; len -= sizeof (*lp); } return(sum); } #endif static ulong running_prom(void) { ulong pc, ppc; extern ulong get_pc(void); pc = get_pc(); if (IS_COMPAT_PHYS(pc)) ppc = COMPAT_TO_PHYS(pc); else ppc = KDM_TO_PHYS(pc); return(IS_PROM_PADDR(ppc)?ppc:0); } static unsigned running_rprom(void) { ulong ppc = running_prom(); return((ppc >= SFLASH_RPROM_PADDR && ppc < (SFLASH_RPROM_PADDR + SFLASH_RPROM_SIZE))); } static unsigned running_fprom(void) { ulong ppc = running_prom(); return((ppc >= SFLASH_FPROM_PADDR && ppc < (SFLASH_FPROM_PADDR + SFLASH_FPROM_SIZE))); } /******************************************************************/ #include #include extern MEMORYDESCRIPTOR *mem_contains(unsigned long, unsigned long); extern MEMORYDESCRIPTOR *mem_getblock(void); extern void mem_list(void); int _fl_get( char *path, __psunsigned_t *get_buf, int *get_size) { #define READ_SIZE (16 * 1024) MEMORYDESCRIPTOR *m; __psunsigned_t bufp, ptr, buf_lim; ULONG fd, cnt, total; LONG err; if (!(m = mem_getblock())) { FPR_ERR(("No free memory descriptors available.\n")); mem_list(); return(ENOMEM); } FPR_HI((" memblock base=%#x count=%ld\n", arcs_ptob(m->BasePage), arcs_ptob(m->PageCount))); bufp = arcs_ptob(m->BasePage); bufp = PHYS_TO_K0(bufp); err = Open(path, OpenReadOnly, &fd); if (err) { FPR_ERR(("Open error %ld for %s\n", err, path)); return(err); } cnt = 0; total = 0; ptr = bufp; buf_lim = bufp + arcs_ptob(m->PageCount); do { err = Read(fd, (void *)ptr, READ_SIZE, &cnt); if (err != ESUCCESS) { FPR_ERR(("Read error %ld for %s\n", err, path)); goto bail; } total += cnt; ptr += cnt; if (ptr > buf_lim) { FPR_ERR(("File too big > %d\n", arcs_ptob(m->PageCount))); err = EBADF; goto bail; } } while (cnt); *get_buf = bufp; *get_size = total; bail: Close(fd); return(err); } #ifdef FDEBUG #include extern int load_elf_struct64(char *, ULONG *, int, int, void *); union commonhdr { Elf64_Ehdr elfhdr64; }; /* * load the pgm section into load_buf and add a ~_cksum_fl16 at end */ static int _fl_load( char *path, __psunsigned_t exe_base, __psunsigned_t *load_buf, int *load_size) { __psunsigned_t bufp, boffset; MEMORYDESCRIPTOR *m; ULONG fd, cnt; LONG err; union commonhdr *commonhdr = 0; Elf64_Ehdr *elfhdr; Elf64_Phdr *pgmhdr = 0; unsigned int size; #ifdef XXX Elf64_Shdr *shdr; #endif /* XXX */ if (!(m = mem_getblock())) { FPR_ERR(("No free memory descriptors available.\n")); mem_list(); return(FL_ERR); } FPR_HI((" memblock base=%#x count=%ld\n", arcs_ptob(m->BasePage), arcs_ptob(m->PageCount))); /* * use the memory from the top */ bufp = arcs_ptob(m->BasePage + m->PageCount); bufp = PHYS_TO_K0(bufp - SFLASH_MAX_SIZE); /* * initialize possbile holes with all 1's */ { int64_t *lp = (int64_t*) bufp; cnt = SFLASH_RPROM_SIZE + FLASH_HEADER_SIZE; while (cnt) { *lp++ = -1; cnt -= sizeof(int64_t); } } /* load */ err = Open(path, OpenReadOnly, &fd); if (err) { FPR_ERR(("Open error %ld for %s\n", err, path)); return(err); } commonhdr = dmabuf_malloc(sizeof(union commonhdr)); if (commonhdr == 0) { Close(fd); FPR_ERR(("cant dmabuf_malloc commondr (%d)\n", sizeof(union commonhdr))); return(FL_ERR); } elfhdr = &(commonhdr->elfhdr64); err = load_elf_struct64(path, &fd, sizeof(Elf64_Ehdr), 0, elfhdr); if (err != ESUCCESS) { FPR_ERR(("%s: cant read elf64 header err=%i\n", err)); goto bail; } if (!IS_ELF(commonhdr->elfhdr64) || commonhdr->elfhdr64.e_ident[EI_CLASS] != ELFCLASS64) { FPR_ERR(("Not elf class 64\n")); goto bail; } FPR_HI(("file fd %li, Elf 64\n", fd)); FPR_HI((" type %#x mach %#x version %u\n", elfhdr->e_type, elfhdr->e_machine, elfhdr->e_version)); FPR_HI((" entry-addr %#x hsize %u flg %#x\n", elfhdr->e_entry, elfhdr->e_ehsize, elfhdr->e_flags)); FPR_HI((" program off %#llx size %#x num %#x\n", elfhdr->e_phoff, elfhdr->e_phentsize, elfhdr->e_phnum)); FPR_HI((" section off %#llx size %#x num %#x\n\n", elfhdr->e_shoff, elfhdr->e_shentsize, elfhdr->e_shnum)); size = elfhdr->e_phentsize * elfhdr->e_phnum; if (size > 0) { FPR_HI(("about to load program headers\n")); pgmhdr = (Elf64_Phdr *) dmabuf_malloc(size); if (pgmhdr == 0) { FPR_ERR(("cant alloc pgmhdr, size=%d\n", size)); goto bail; } err = load_elf_struct64(path, &fd, size, elfhdr->e_phoff, pgmhdr); if (err != ESUCCESS) { FPR_ERR(("load_elf_struct() failed err=%d\n", err)); goto bail; } /* dump program headers */ FPR_HI(("\nheader entry size %d\n", elfhdr->e_phentsize)); FPR_HI(("%d entries in file\n", elfhdr->e_phnum)); for(cnt = 0; cnt < elfhdr->e_phnum; cnt++) { FPR_MSG(("program %d: size %d vaddr %x\n", cnt, pgmhdr[cnt].p_memsz, pgmhdr[cnt].p_vaddr)); FPR_HI((" type %x, offset %llx", pgmhdr[cnt].p_type, pgmhdr[cnt].p_offset)); FPR_HI((" file size %llx, mem size %llx, " " flags %x, align %llx\n", pgmhdr[cnt].p_filesz, pgmhdr[cnt].p_memsz, pgmhdr[cnt].p_flags, pgmhdr[cnt].p_align)); } } else { FPR_ERR(("no program header!\n")); goto bail; } for(size = 0, cnt = 0; cnt < elfhdr->e_phnum; cnt++) { __psunsigned_t boffset, beg_paddr; /* check PT_LOAD type */ if (pgmhdr[cnt].p_type != PT_LOAD) continue; if (IS_COMPAT_PHYS(pgmhdr[cnt].p_vaddr)) beg_paddr = COMPAT_TO_PHYS(pgmhdr[cnt].p_vaddr); else beg_paddr = KDM_TO_PHYS(pgmhdr[cnt].p_vaddr); /* check vaddr+memsz range */ if (!IS_PROM_PADDR(beg_paddr) && !IS_PROM_PADDR(beg_paddr+pgmhdr[cnt].p_memsz-2)) continue; if (beg_paddr < exe_base) { FPR_ERR(("Bad (p_vaddr=0x%llx paddr=0x%x) < exe_base=0x%x\n", pgmhdr[cnt].p_vaddr, beg_paddr, exe_base)); err = ENOMEM; goto bail; } boffset = (beg_paddr - exe_base); err = load_elf_struct64(path, &fd, pgmhdr[cnt].p_filesz, pgmhdr[cnt].p_offset, (void *)(bufp + boffset)); if (err != ESUCCESS) goto bail; /* size must be begin of bufp to all loaded pgms */ if (boffset + pgmhdr[cnt].p_filesz > size) size = boffset + pgmhdr[cnt].p_filesz; } #ifdef XXX /* * dump section headers */ size = elfhdr->e_shentsize * elfhdr->e_shnum; if (size > 0) { FPR_MSG(("about to load section headers size=%#x\n", size)); shdr = (Elf64_Shdr *) dmabuf_malloc(size); if (shdr == 0) { FPR_ERR(("cant alloc shdr, size=%d\n", size)); goto bail; } err = load_elf_struct64(path, &fd, size, elfhdr->e_shoff, shdr); if (err != ESUCCESS) { FPR_ERR(("load_elf_struct() failed err=%d\n", err)); goto bail; } FPR_MSG(("section entry size %#d\n", elfhdr->e_shentsize)); FPR_MSG(("%#d entries in file\n", elfhdr->e_shnum)); for(cnt = 0; cnt < elfhdr->e_shnum; cnt++) { printf("[%d]\n", cnt); dump_bytes((char *)&shdr[cnt], sizeof(Elf64_Shdr), 1); FPR_MSG(("\n")); FPR_MSG(("%d: %#x type %#x, offset %#llx, vaddr %#llx, " "section size %#llx, align %#llx, entsize %#llx, " "flags %#llx\n", cnt, shdr[cnt].sh_name, shdr[cnt].sh_type, shdr[cnt].sh_offset, shdr[cnt].sh_addr, shdr[cnt].sh_size, shdr[cnt].sh_addralign, shdr[cnt].sh_entsize, shdr[cnt].sh_flags)); } dmabuf_free(shdr); } #endif /* FDEBUG */ if (elfhdr->e_type != ET_EXEC) { FPR_MSG(("%s: not executable!\n", path)); goto bail; } if (size & 1) size += 1; *load_size = size; *load_buf = bufp; bail: if (commonhdr) dmabuf_free(commonhdr); if (pgmhdr) dmabuf_free(pgmhdr); if (fd) Close(fd); return(err); } /* * syntax: fl load [] - */ static int fl_load(int argc, char **argv, flash_cmd_t *fcmdp) { __psunsigned_t ld_buf; int rv, ld_sz; char *path; FPR_LO(("load: \n")); if (argc <= 0) { /* no path, try env variables */ /* XXX for now hardcode is some stuff */ path = "bootp()femto.engr:i2/prom"; } else path = argv[0]; FPR_LO(("path=%s\n", path)); ld_sz = 0; ld_buf = 0; rv = _fl_load(path, SFLASH_EXE_BASE, &ld_buf, &ld_sz); if (rv != ESUCCESS || !ld_sz || !ld_buf) FPR_ERR(("No text/data in %s to load\n", path)); FPR_MSG(("\n%s loaded @0x%x, actual size %d, flash rdup size %d\n", path, ld_buf, ld_sz, SFLASH_RDUP(ld_sz))); return(rv); } /* * erase segments from beg_seg to end_seg inclusive */ static int _fl_erase(unsigned beg_seg, unsigned end_seg) { unsigned seg; flash_err_t frv; if (end_seg - beg_seg >= SFLASH_MAX_SEGS) return(1); for (seg = beg_seg; seg <= end_seg; seg++) { frv = flash_erase(seg); if (frv) { flash_print_err(frv); return(1); } } return(0); } /* * syntax: fl get [] - */ static int fl_get(int argc, char **argv, flash_cmd_t *fcmdp) { __psunsigned_t get_buf; int rv, get_sz; char *path; if (argc <= 0) { /* no path, try env variables */ /* XXX for now hardcode is some stuff */ path = "bootp()femto.engr:i2/prom"; } else path = argv[0]; FPR_PR(("get: %s\n", path)); get_sz = 0; get_buf = 0; rv = _fl_get(path, &get_buf, &get_sz); if (rv) return(rv); FPR_PR(("%d bytes read to 0x%x, sum -r:\n", get_sz, get_buf)); FPR_PR(("%05u %d\n", flash_cksum_r((void *)get_buf, get_sz, 0), (get_sz + 511)/512)); return(0); } #endif #define PROM_CMD_OPT_f 0 #define PROM_CMD_OPT_R 1 #define PROM_CMD_OPT_r 2 #define PROM_CMD_OPT_Force 3 /* * syntax: fl prom [-r|-R] - */ static int fl_prom(int argc, char **argv, flash_cmd_t *fcmdp) { char *path; char *data; flash_header_t *hdr; __psunsigned_t ld_buf = 0; int ld_sz = 0; int flash_n_reset_fprom = running_fprom(); int opt = PROM_CMD_OPT_f; int rv; FPR_LO(("prom:\n")); if (argc) { if (!strcmp(argv[0], "-r")) { opt = PROM_CMD_OPT_r; argc--; argv++; } else if (!strcmp(argv[0], "-R")) { opt = PROM_CMD_OPT_R; argc--; argv++; } else if (!strcmp(argv[0], "-Force")) { opt = PROM_CMD_OPT_Force; argc--; argv++; } } if (argc <= 0) { FPR_ERR(("no file specified\n")); return(1); } else path = argv[0]; rv = _fl_get(path, &ld_buf, &ld_sz); if (rv) { return(1); } FPR_MSG(("%d bytes loaded to mem @ 0x%x\n", ld_sz, ld_buf)); if (opt == PROM_CMD_OPT_Force) { FPR_PR(("Program loaded data to base of flash\n")); goto force_flash; } rv = _fl_check_bin_image((char*)ld_buf, ld_sz); switch (rv) { case IP30PROM_BIN_FORMAT: { /* rprom.bin format */ /* * we will be running fprom or dprom, rprom will not * use this fct */ if (opt == PROM_CMD_OPT_R || opt == PROM_CMD_OPT_r) { FPR_PR(("Programming Rprom\n")); rv = _fl_prom((uint16_t *)ld_buf, 0, SFLASH_RPROM_SEG, SFLASH_RPROM_SIZE); if (rv) goto rprom_failed; } /* * make sure the rprom is good before attempting to * re-flash the fprom section */ if (flash_prom_ok((char *)SFLASH_RPROM_ADDR, SFLASH_RPROM_HDR_ADDR) == 0) goto bad_rprom; if (opt != PROM_CMD_OPT_r) { FPR_PR(("Programming Fprom\n")); rv = _fl_prom((uint16_t *)(ld_buf + SFLASH_RPROM_SIZE), flash_n_reset_fprom, SFLASH_FPROM_SEG, ld_sz - SFLASH_RPROM_SIZE); if (rv) goto fprom_failed; } break; } case FPROM_BIN_FORMAT: { /* fprom.bin format */ if (opt != PROM_CMD_OPT_f) { FPR_ERR(("bad option %s\n", argv[-1])); return(1); } /* * make sure the rprom is good before attempting to * re-flash the fprom section */ if (flash_prom_ok((char *)SFLASH_RPROM_ADDR, SFLASH_RPROM_HDR_ADDR) == 0) goto bad_rprom; FPR_PR(("Programming Fprom\n")); rv = _fl_prom((uint16_t *)ld_buf, flash_n_reset_fprom, SFLASH_FPROM_SEG, ld_sz); if (rv) goto fprom_failed; break; } default: { if (!yes("Unrecognized binary image, program anyway")); return(1); force_flash: if (!yes("This is VERY risky! Are you REALLY REALLY sure")) return(1); rv = _fl_prom((uint16_t *)ld_buf, flash_n_reset_fprom, SFLASH_RPROM_SEG, MIN(ld_sz, SFLASH_MAX_SIZE)); if (rv) goto force_failed; break; } } /* switch */ return(0); rprom_failed: FPR_ERR(("Programming Rprom failed\n")); return(1); fprom_failed: FPR_ERR(("Programming Fprom failed\n")); return(1); force_failed: FPR_ERR(("Programming Flash failed\n")); return(1); bad_rprom: FPR_ERR(("Rprom section is bad cannot proceed\n")); return(1); } /* * syntax: fl log [inval] [] */ /*ARGSUSED*/ static int fl_log(int argc, char **argv, flash_cmd_t *fcmdp) { flash_pds_ent_t *ent = 0; char *data; int invalidate = 0; int len, i; int hoffset; while (argc--) { if ( !strcmp("inval", *argv)) { invalidate = 1; } else { hoffset = atoi(*argv)/sizeof(vu_short); ent = (flash_pds_ent_t *)(SFLASH_PDS_ADDR + hoffset); } argv++; } /* * ent returned is the next entry but data and len * is from the current log entry */ i = 0; data = 0; do { ent = flash_pds_get_log(ent, &data, &len, invalidate); if (!data) break; FPR_PR(("[0x%04x] ", ((__psint_t)data&0xffff)-FPDS_ENT_DATA_OFFS*sizeof(vu_short))); flash_print_log((void *)data, len); if ((++i % 16) == 0) { if (!yes("more")) return(0); } } while (ent); return(0); } /* * key=0 ==> first data entry starting from ent * ent=0 ==> start searching from begin of PDS */ static flash_pds_ent_t * fl_pds_get_data(char *key, flash_pds_ent_t *ent) { char *buf; int len; u_short cksum; flash_pds_da0_t *da0; ent = flash_pds_find_data(key, ent); if (!ent) return(0); da0 = (flash_pds_da0_t *)ent->data; key = (char *)(da0 + 1); /* in case key was 0 */ buf = malloc(da0->datalen + 8); /* datalen and some pad */ if (buf == 0) { FPR_ERR(("cant malloc %d bytes\n", da0->datalen)); return(0); } len = flash_pds_copy_data(key, buf, 0); cksum = flash_cksum_r(buf, len, 0); FPR_PR(("PDS DATA key=%s: cksum 0x%x (%d bytes) is %s (actual 0x%x)\n", key, da0->datasum, da0->datalen, (da0->datasum != cksum)?"BAD":"OK", cksum)); free(buf); return(ent); } #define DATA_CMD_OPT_def 0 #define DATA_CMD_OPT_d 1 #define DATA_CMD_OPT_f 2 #define DATA_CMD_OPT_m 3 #define DATA_CMD_OPT_r 4 /* * "[[-d|-f|-m] [|]]" */ static int fl_data(int argc, char **argv, flash_cmd_t *fcmdp) { int opt = DATA_CMD_OPT_def; int len; char *key, *file, *buf; struct range rg; flash_pds_ent_t *ent; flash_err_t frv; if (argc) { opt = DATA_CMD_OPT_r; if (!strcmp(argv[0], "-d")) { opt = DATA_CMD_OPT_d; argc--; argv++; } else if (!strcmp(argv[0], "-f")) { opt = DATA_CMD_OPT_f; argc--; argv++; } else if (!strcmp(argv[0], "-m")) { opt = DATA_CMD_OPT_m; argc--; argv++; } } key = argv[0]; argc--; argv++; switch (opt) { case DATA_CMD_OPT_d: /* delete option */ flash_pds_inval_data(key); break; case DATA_CMD_OPT_f: /* add from file option */ if (argc == 0) { FLASH_USAGE(fcmdp); return(-1); } frv = _fl_get(argv[0], (__psunsigned_t *)&buf, &len); if (frv) break; frv = flash_pds_set_data(key, buf, len); if (frv) flash_print_err(frv); break; case DATA_CMD_OPT_m: /* add from memory option */ if (argc == 1 && !parse_range(argv[0], 1, &rg)) { FLASH_USAGE(fcmdp); return(-1); } frv = flash_pds_set_data(key, (char *)rg.ra_base, rg.ra_count); if (frv) flash_print_err(frv); break; case DATA_CMD_OPT_r: /* read option */ fl_pds_get_data(key, 0); break; default: /* read all option */ ent = 0; while (ent = fl_pds_get_data(0, ent)) ; break; } return(0); } /* * syntax: */ /*ARGSUSED*/ static int fl_resetpds(int argc, char **argv, flash_cmd_t *fcmdp) { /* call flash_pds_init with resetpds flag on */ flash_pds_init(1); return(0); } static struct reg_desc rprom_flags_desc[] = { { RPROM_FLG_TEST, 0, "RPROM TEST", NULL, NULL }, { RPROM_FLG_DBG_MSK, -4, "Debug", "0x%x", NULL }, { RPROM_FLG_FVP, 0, "FPROM Valid Pend",NULL,NULL }, { RPROM_FLG_VRB_MSK, 0, "Verbose", "0x%x", NULL }, {0,0,NULL,NULL,NULL} }; /* * syntax: <16 bit flag> */ /*ARGSUSED*/ static int fl_rpromflg(int argc, char **argv, flash_cmd_t *fcmdp) { ushort oval, nval; if (argc) { nval = atoi(*argv); } oval = flash_get_nv_rpromflg(); FPR_PR(("Current flag=%R\n", oval, rprom_flags_desc)); if (!argc) return(0); /* call flash_pds_init with resetpds flag on */ flash_set_nv_rpromflg(nval); FPR_PR(("New flag=%R\n", nval, rprom_flags_desc)); return(0); } #ifdef FDEBUG /* * syntax: fl setenv var [str] */ /*ARGSUSED*/ static int fl_senv(int argc, char **argv, flash_cmd_t *fcmdp) { flash_err_t rv; short zero = 0; char *str = (char *)&zero; if (argc > 2 || !argc) return(1); if (argc == 2) str = argv[1]; FPR_LO(("senv: var %s str %s\n", argv[0], str)); START_TIME; rv = flash_setenv(argv[0], str); STOP_TIME("setenv ") FPR_PR(("rv=0x%x\n",rv)); return(rv); } /* * syntax: fl unsetenv var */ /*ARGSUSED*/ static int fl_uenv(int argc, char **argv, flash_cmd_t *fcmdp) { int rv; if (argc != 1) return(1); /* * 0 for string entry implies unset */ START_TIME; rv = flash_setenv(argv[0], 0); STOP_TIME("unsetenv "); FPR_PR(("rv=0x%x\n",rv)); return(rv); } /* * syntax: fl getenv var */ /*ARGSUSED*/ static int fl_genv(int argc, char **argv, flash_cmd_t *fcmdp) { flash_pds_ent_t *p; if (argc != 1) return(1); FPR_LO(("genv: var %s\n", argv[0])); START_TIME; p = flash_findenv(0, argv[0]); STOP_TIME("getenv "); if (p) FPR_PR(("%s\n", p->data)); return(0); } /* syntax: fl pds [all | env | log] */ /*ARGSUSED*/ static int fl_pds(int argc, char **argv, flash_cmd_t *fcmdp) { u_short filter = FPDS_FILTER_VALID; flash_pds_ent_t *ent = 0; int len; char msg[514]; FPR_PDS(("fl_pds:\n")); if (argc >= 1) { if (!strcmp(argv[0], "all")) filter = FPDS_FILTER_ALL; else if (!strcmp(argv[0], "env")) filter = FPDS_ENT_ENV_TYPE; else if (!strcmp(argv[0], "log")) filter = FPDS_ENT_LOG_TYPE; else if (!strcmp(argv[0], "data")) filter = FPDS_ENT_DAT_TYPE; else if (!strcmp(argv[0], "compress")) { vu_short *rv; rv = flash_pds_compress(0); FPR_PR(("flash_pds_compress rv = 0x%x\n", rv)); return(0); } } while (ent = flash_pds_ent_next(ent, filter)) { __psunsigned_t offset; len = ent->pds_hlen*sizeof(uint16_t); bcopy((void *)ent->data, msg, len); msg[len] = 0; offset = ((__psunsigned_t)ent - (__psunsigned_t)SFLASH_PDS_ADDR); switch (FPDS_ENT_TYPE(ent)) { case FPDS_ENT_ENV_TYPE: { printf("env: offs 0x%06x: %s: len %d: %s\n", 0xffffff&offset, (ent->valid==FPDS_ENT_VALID)?"VAL":"INV", len, msg); break; } case FPDS_ENT_LOG_TYPE: { printf("log: offs 0x%06x: %s: len %d:\n", 0xffffff&offset, (ent->valid==FPDS_ENT_VALID)?"VAL":"INV", len); flash_print_log((void *)msg, len); break; } case FPDS_ENT_DA0_TYPE: { flash_pds_da0_t *da0 = (flash_pds_da0_t *)ent->data; printf("da0: offs 0x%06x: %s: len %d:\n", 0xffffff&offset, (ent->valid==FPDS_ENT_VALID)?"VAL":"INV", len); printf(" len %d, cksum %d (0x%x): key %s\n", da0->datalen, da0->datasum, da0->datasum, (char *)(da0 + 1)); break; } case FPDS_ENT_DA1_TYPE: { printf("da1: offs 0x%06x: %s: len %d:\n", 0xffffff&offset, (ent->valid==FPDS_ENT_VALID)?"VAL":"INV", len); break; } default: { printf("unknown: offs 0x%06x: %s: type 0x%x (%d bytes):\n", 0xffffff&offset, (ent->valid==FPDS_ENT_VALID)?"VAL":"INV", ent->pds_type_len & FPDS_ENT_TYPE_MASK, ent->pds_hlen * sizeof(uint16_t)); break; } } } return(0); } /* * syntax: fl erase ( | all) [] */ /*ARGSUSED*/ static int fl_erase(int argc, char **argv, flash_cmd_t *fcmdp) { unsigned beg_seg, end_seg; if (argc == 1) { if (!strcmp(argv[0], "all")) { beg_seg = 0; end_seg = SFLASH_MAX_SEGS - 1; FPR_PR(("flash: erase all segments")); } else { beg_seg = atoi(argv[0]); end_seg = beg_seg; FPR_PR(("flash: erase segment %d @%#x", beg_seg, SFLASH_SEG_ADDR(beg_seg))); } } else if (argc == 2) { beg_seg = atoi(argv[0]); end_seg = atoi(argv[1]); FPR_PR(("flash: erase segments %d - %d", beg_seg, end_seg)); } else { FLASH_USAGE(fcmdp); return(0); } if (!yes("")) return(1); if (_fl_erase(beg_seg, end_seg)) FPR_ERR(("Error: unable to complete erase\n")); else FPR_MSG(("Erase completed\n")); return(0); } /* * syntax: fl fprom [ [wd-pattern]] */ /*ARGSUSED*/ static int fl_writest(int argc, char **argv, flash_cmd_t *fcmdp) { int seg = 2, n; unsigned *u1, test=0; unsigned short *fp, *src_buf, *tp = (unsigned short *)&test; flash_err_t frv; if (argc >= 1) seg = atoi(argv[0]); if (argc >= 2) test = (unsigned)atoi(argv[1]); src_buf = (unsigned short *)malloc(SFLASH_SEG_SIZE); if (!src_buf) { FPR_ERR(("flash: src buffer alloc failed\n")); return(0); } n = SFLASH_SEG_SIZE/2; while (n--) src_buf[n] = tp[n&1]; fp = (unsigned short *)SFLASH_SEG_ADDR(seg); FPR_PR((" write segment %d@%#x from %#x with %#x", seg, fp, src_buf, test)); if (!yes("")) return(1); START_TIME; frv = flash_cp(src_buf, fp, SFLASH_SEG_SIZE/2); STOP_TIME("\tsegment write"); if (frv) flash_print_err(frv); n = SFLASH_SEG_SIZE/4; u1 = (unsigned *)src_buf; START_TIME; while (n--) { if (*u1++ == test) continue; FPR_ERR(("flash: memory write failure @ %#x\n", u1-1)); free(src_buf); return(0); } STOP_TIME("\tmemory buffer K1 read/test"); n = SFLASH_SEG_SIZE/4; u1 = (unsigned *)SFLASH_SEG_ADDR(seg); START_TIME; while (n--) { if (*u1++ == test) continue; FPR_ERR(("flash: segment write failure @ %#x\n", u1-1)); free(src_buf); return(0); } STOP_TIME("\tflash segment K1 read/test"); free(src_buf); return(0); } /*ARGSUSED*/ static int _fl_copy(__psunsigned_t src, __psunsigned_t dst, int hlen) { int n; long long lsum; unsigned short *sp, *dp, sum; long long *lsp = (long long *)src; long long *ldp = (long long *)dst; flash_err_t frv; n = hlen; START_TIME; frv = flash_cp((uint16_t *)src, (vu_short *)dst, hlen); STOP_TIME("flash copy "); if (frv) flash_print_err(frv); /* verify the copy */ n = hlen; START_TIME; while (n > 3) { n -= 4; if (*lsp++ == *ldp++) continue; FPR_ERR((" lcompare failure src/dst %04x(%#x)/%04x(%#x)\n", *(lsp-1), lsp-1, *(ldp-1), ldp-1)); return(0); } if (n) { /* we have some odd hwds, 1,2, or 3 */ sp = (unsigned short *)lsp; dp = (unsigned short *)ldp; while (n--) { if (*sp++ == *dp++) continue; FPR_ERR((" hcompare failure src/dst %04x(%#x)/%04x(%#x)\n", *(sp-1), sp-1, *(dp-1), dp-1)); return(0); } } STOP_TIME("src/dst cmp "); START_TIME; sum = 0xffff & ~_cksum1((void *)src, hlen*2, 0); STOP_TIME("in_cksum src"); printf(" in_cksum src=%#x\n", sum); START_TIME; sum = 0xffff & ~_cksum1((void *)dst, hlen*2, 0); STOP_TIME("in_cksum dst"); printf(" in_cksum dst=%#x\n", sum); START_TIME; lsum = _cksum64((void *)src, hlen*2, 0); STOP_TIME("cksum64 src"); printf("cksum64 src=%#llx\n", lsum); START_TIME; lsum = _cksum64((void *)dst, hlen*2, 0); STOP_TIME("cksum64 dst"); printf("cksum64 dst=%#llx\n", lsum); return(0); } /* * syntax: fl copy */ /*ARGSUSED*/ static int fl_copy(int argc, char **argv, flash_cmd_t *fcmdp) { int len; long long lsum; __psint_t src, dst; if (argc != 3) { FLASH_USAGE(fcmdp); return(0); } /* switch over to command parser for addr/RANGE parsing*/ atob_ptr(argv[0], &src); atob_ptr(argv[1], &dst); len = atoi(argv[2]); if (!IS_KSEGDM(src) || !IS_KSEGDM(src+len)) { FPR_ERR(("src addr %#x not K0/1\n", src)); return(0); } if (!IS_FLASH_ADDR(dst) || !IS_FLASH_ADDR(dst + len - 2)) { FPR_ERR(("dst addr %#x len %d not flash\n", dst, len)); return(0); } if (len & 1) { FPR_ERR(("len not even bytes, flash is 16bit device\n")); } FPR_PR(("flash: copy %#x -> %#x for %d bytes", src, dst, len)); if (!yes("")) return(1); return(_fl_copy(src, dst, len/2)); } /* * syntax: fl dump [ | ] */ /*ARGSUSED*/ static int fl_dump(int argc, char **argv, flash_cmd_t *fcmdp) { static __psint_t addr; static int len; static int addr_flg = 1; if (argc >= 3) addr_flg = 0; if (argc >= 2) len = atoi(argv[1]); if (!len) len = 0x80; if (argc >= 1) atob_ptr(argv[0], &addr); if (addr >= 0 && addr < SFLASH_MAX_SEGS) addr = (__psint_t)SFLASH_SEG_ADDR(addr); else if (!IS_KSEGDM(addr) && !IS_COMPAT_PHYS(addr)) { FPR_ERR(("Bad addr: %#x\n", addr)); return(0); } dump_bytes((char *)addr, len, addr_flg); addr += len; printf("\n"); return(0); } /* * syntax: fl 1fe * set the flash_mem_base to 1fe */ /*ARGSUSED*/ static int fl_1fe(int argc, char **argv, flash_cmd_t *fcmdp) { flash_mem_base = FLASH_MEM_ALT_BASE; FPR_PR(("flash_mem_base set to 0x%x\n", flash_mem_base)); return(0); } /* * syntax: fl 1fc * set the flash_mem_base to 1fc */ /*ARGSUSED*/ static int fl_1fc(int argc, char **argv, flash_cmd_t *fcmdp) { flash_mem_base = FLASH_MEM_BASE; FPR_PR(("flash_mem_base set to 0x%x\n", flash_mem_base)); if (running_rprom() || running_fprom()) FPR_PR(("CAUTION: You can toast the prom you are executing!!!\n")); return(0); } /* * syntax: fl time */ /*ARGSUSED*/ static int fl_time(int argc, char **argv, flash_cmd_t *fcmdp) { int i = atoi(argv[0]); ulong t10k, t10k_ns, ns; vu_long hticks; #ifdef US_DELAY_DEBUG __uint32_t before, after; #endif extern __uint32_t us_before, us_after; extern ulong decinsperloop, uc_decinsperloop; extern ulong _ticksper1024inst(void); extern ulong delay_calibrate(void); FPR_PR(("time: us_delay(%d): ", i)); START_TIME; us_delay(i); SAMPLE_TICKS(hticks); #ifdef IP30 ns = hticks * HEART_COUNT_NSECS; #else ns = hticks * 100; #endif #ifdef US_DELAY_DEBUG before = us_before; after = us_after; FPR_PR(("C0_COUNT: took a little less than 0x%x - 0x%x = " "%u ticks.\n", (__psunsigned_t)before,(__psunsigned_t)after, after-before)); #endif FPR_PR(("took %d,%03d,%03d nsecs hticks=%u\n", ns/1000000, (ns%1000000)/1000, (ns%1000000)%1000, hticks)); FPR_PR(("uc_decinsperloop=%u decinsperloop=%u\n", uc_decinsperloop, decinsperloop)); START_TIME; t10k = _ticksper1024inst(); SAMPLE_TICKS(hticks); #ifdef IP30 ns = hticks * HEART_COUNT_NSECS; t10k_ns = t10k * HEART_COUNT_NSECS; #else ns = hticks * 100; t10k_ns = t10k * 100; #endif FPR_PR(("_ticksper1024inst took %d,%03d,%03d nsecs hticks=%u\n", ns/1000000, (ns%1000000)/1000, (ns%1000000)%1000, hticks)); FPR_PR(("_ticksper1024inst=%u ticks, %u secs\n", t10k, t10k_ns)); return(0); } /* * syntax: fl cksum [( | ) [len]] */ /*ARGSUSED*/ static int fl_cksum(int argc, char **argv, flash_cmd_t *fcmdp) { int len = 0x80000; /* default is 512K*/ int cksum, n; __psint_t data = 0; long long llsum; if (argc >= 1) { atob_ptr(argv[0], &data); len = SFLASH_SEG_SIZE; } if (argc >= 2) len = atoi(argv[1]); if (data >= 0 && data < SFLASH_MAX_SEGS) data = (__psint_t)SFLASH_SEG_ADDR(data); else if (!IS_KSEGDM(data) || !IS_KSEGDM(data+len)) { FPR_ERR(("Bad addr/len: %#x/%#x\n", data/len)); return(0); } #if NOT START_TIME; cksum = flash_cksum_r((char *)data, len, 0); STOP_TIME("sum "); FPR_PR(("sum -r %d bytes @%#x\n", len, data)); FPR_PR(("%05u %d\n", cksum, (len+511)/512)); START_TIME; isum = _cksum32_16((void *)data, len, 0); STOP_TIME("cksum32_16 "); START_TIME; llsum = _cksum64_16((void *)data, len, 0); STOP_TIME("cksum64_16 "); FPR_PR((" 32bit %#x 64bit %#llx by 16 bit access\n", isum, llsum)); START_TIME; isum = _cksum32((void *)data, len, 0); STOP_TIME("cksum32 "); #endif FPR_PR(("%d bytes @%#x:\n", len, data)); START_TIME; cksum = 0xffff & ~_cksum1((void *)data, len, 0); STOP_TIME("in_cksum "); FPR_PR(("in_cksum %#x\n", cksum)); START_TIME; llsum = _cksum64((void *)data, len, 0); STOP_TIME("cksum64 "); FPR_PR(("cksum64 %#llx\n", llsum)); return(0); } /* * syntax: fl sum-r */ /*ARGSUSED*/ static int fl_sum_r(int argc, char **argv, flash_cmd_t *fcmdp) { int cksum, len, n; __psint_t data = 0; long long llsum; if (argc < 2) { FLASH_USAGE(fcmdp); return(0); } atob_ptr(argv[0], &data); len = atoi(argv[1]); if (data >= 0 && data < SFLASH_MAX_SEGS) data = (__psint_t)SFLASH_SEG_ADDR(data); else if (!IS_KSEGDM(data) || !IS_KSEGDM(data+len)) { FPR_ERR(("Bad addr/len: %#x/%#x\n", data/len)); return(0); } START_TIME; cksum = flash_cksum_r((char *)data, len, 0); STOP_TIME("sum "); FPR_PR(("sum -r %d bytes @%#x\n", len, data)); FPR_PR(("%05u %d\n", cksum, (len+511)/512)); FPR_PR(("0x%x\n", cksum)); return(0); } static int fl_log_test(int argc, char **argv, flash_cmd_t *f) { char buf[128]; char *str; int n = 0; if (argc) str = argv[0]; else str = "flash log test"; if (argc == 2) { TIMEINFO t; START_TIME; cpu_get_tod(&t); STOP_TIME("get tod "); n = atoi(argv[1]); } START_TIME; flash_pds_log(str); STOP_TIME("log test "); START_TIME; flash_pds_prf("flash_pds_prf: string test %s=0x%x %s=%d", "A", 0xA, "B", 2); STOP_TIME("log1 write "); START_TIME; flash_pds_write_log(PDS_LOG_TYPE2, 0xa, 0xb, 0xc, 0xd); STOP_TIME("log2 write "); START_TIME; while (n--) { flash_pds_prf("%s %8d", str, n); } STOP_TIME("logN write "); return(0); } /* * test power en-dis able fct by toggling it */ static int fl_power(int argc, char **argv, flash_cmd_t *f) { static int off_state; if (off_state) { ip30_setup_power(); off_state = 0; FPR_MSG(("Power ints are ON\n")); } else { ip30_disable_power(); off_state = 1; FPR_MSG(("Power ints are OFF\n")); } return(0); } #define ERASED_UINT64 0xffffffffffffffff static __psunsigned_t erase_chk(int seg) { uint64_t *fdp = (uint64_t *)SFLASH_SEG_ADDR(seg); uint64_t *fdp_end = (uint64_t *)SFLASH_SEG_ADDR(seg+1); while (fdp < fdp_end) { if (*fdp++ == ERASED_UINT64) continue; return((__psunsigned_t)(fdp - 1)); } return(0); } #define BITSPERSHORT 16 static flash_err_t ttf_extra(int seg, int sl) { vu_short *fp = SFLASH_SEG_ADDR(seg); vu_short *seg_endp = SFLASH_SEG_ADDR(seg + 1); int i, ii; vu_short test, actual; flash_err_t rv; for (i=0; fp < seg_endp; i++) { test = 0xffff; for (ii=0; ii < BITSPERSHORT; ii++) { if (sl) test <<= 1; else test >>= 1; rv = flash_cp((void *)&test, fp, 1); actual = *fp; if (rv || test != actual) goto failed; } fp++; } return(rv); failed: printf("ttf_extfa: failed fp=0x%x i=%d ii=%d\n", fp, i, ii); if (rv) flash_print_err(rv); printf(" test=0x%x actual=0x%x\n", test, actual); return(1); } /* * test time-to-failure of a segment */ static int fl_ttf(int argc, char **argv, flash_cmd_t *f) { int extra = 0, erase_only = 0, set_count = 0, fcnt; unsigned n, count = 1; __psunsigned_t echk; flash_err_t frv; char *bufp = 0; while (argc--) { if ( !strcmp("extra", *argv)) { extra = 1; } else if ( !strcmp("erase_only", *argv)) { erase_only = 1; } else if ( !strcmp("set_count", *argv)) { set_count = 1; } else { count = (unsigned) atoi(*argv); } argv++; } if (set_count) { fcnt = count; fcnt += flash_get_nv_cnt(SFLASH_FPROM_SEG); flash_set_nv_cnt(SFLASH_FPROM_SEG, &fcnt); printf("new count %d\n", fcnt); return(0); } if (!extra) { bufp = (char *)align_malloc(SFLASH_SEG_SIZE, sizeof(__uint64_t)); if (!bufp) { printf("no mem for %d size\n", SFLASH_SEG_SIZE); return(0); } } printf("flash erase-to-failure test of segment 14,\n" " %d loops extra=%d erase_only=%d: ", count, extra, erase_only); if (!yes("continue")) return(0); for (n = 0; n < count; n++) { printf(" n = %8d: ", n); if (extra) { START_TIME; if (ttf_extra(14, n & 1)) break; STOP_TIME("ttf_extra "); } else if (!erase_only) { START_TIME; bcopy((void *)SFLASH_SEG_ADDR(n&0x7), bufp, SFLASH_SEG_SIZE); /* fill the buffer */ frv = flash_cp((void *)bufp, SFLASH_SEG_ADDR(14), SFLASH_SEG_SIZE/sizeof(uint16_t)); STOP_TIME("segfill "); if (frv) { flash_print_err(frv); break; } } frv = flash_erase(14); if (frv) { flash_print_err(frv); break; } fcnt = flash_get_nv_cnt(SFLASH_FPROM_SEG) + 1; flash_set_nv_cnt(SFLASH_FPROM_SEG, &fcnt); echk = erase_chk(14); if (echk) { printf("erase failure at 0x%x\n", echk); break; } } if (bufp) align_free(bufp); return(0); } #endif /* FDEBUG */ /*ARGSUSED*/ /* * repeat flash cmds */ static int fl_repeat(int argc, char **argv, flash_cmd_t *fcmdp) { int flash_cmd(int argc, char **argv, char **envp); int count; if (argc < 2) { FLASH_USAGE(fcmdp); return(0); } count = atoi(argv[0]); if (count <= 0) { FLASH_USAGE(fcmdp); return(0); } argc--; argv++; while (count--) { flash_cmd(argc, argv, 0); flash_pds_prf("%s: rep count %d", argv[0], count); } return(0); } /* * syntax: fl info */ /*ARGSUSED*/ static int fl_info(int argc, char **argv, flash_cmd_t *fcmdp) { unsigned short mfgid, devid; int seg = 0, status; if (argc >= 1) seg = atoi(argv[0]); flash_id(&mfgid, &devid); FPR_PR(("Flash Base=0x%x ID(mfg %#x dev %#x)\n", flash_mem_base, mfgid, devid)); /* check mfg and dev and give appropriate confirm/warning */ if (mfgid != SFLASH_MFG_ID) FPR_PR(("Warning: unknown mfg id 0x%x, expected 0x%x\n", mfgid, SFLASH_MFG_ID)); if (devid != SFLASH_DEV_ID) FPR_PR(("Warning: unknown device id 0x%x, expected 0x%x\n", devid, SFLASH_DEV_ID)); flash_print_status(seg); FPR_PR(("\n")); FPR_PR(("RPROM ")); flash_print_prom_info(SFLASH_RPROM_HDR_ADDR, (u_short *)SFLASH_RPROM_ADDR); FPR_PR(("\n")); FPR_PR(("FPROM ")); flash_print_prom_info(SFLASH_FPROM_HDR_ADDR, (u_short *)SFLASH_FPROM_ADDR + FLASH_HEADER_SIZE/sizeof(uint16_t)); FPR_PR(("\n")); /* * if seg is non-zero it will be used as flag to check the * pds usage data structs */ flash_print_pds_status(seg); return(0); } #define FCMD_PROM_USAGE "[-r|-R] " #define FCMD_LOG_USAGE "[inval] []" #define FCMD_DATA_USAGE "[[-d|-f|-m] [|]]" #define FCMD_RESETPDS_USAGE "" #define FCMD_RPROMFLG_USAGE "<16-bit flag>" #define FCMD_INFO_USAGE "" #define FCMD_HELP_USAGE "" #ifdef FDEBUG #define FCMD_SENV_USAGE " []" #define FCMD_GENV_USAGE "" #define FCMD_UENV_USAGE "" #define FCMD_GET_USAGE "[]" #define FCMD_LOAD_USAGE "[]" #define FCMD_ERASE_USAGE "( [] | all)" #define FCMD_PDS_USAGE "[all | env | log | compress ]" #define FCMD_1FC_USAGE "" #define FCMD_1FE_USAGE "" #define FCMD_WRITEST_USAGE "[ []]" #define FCMD_COPY_USAGE " " #define FCMD_DUMP_USAGE "[( | ) [ []]" #define FCMD_TIME_USAGE "" #define FCMD_CKSUM_USAGE "[( | ) []]" #define FCMD_SUM_R_USAGE " " #define FCMD_LOG_TEST_USAGE "[ []]" #endif /* FDEBUG */ static int fl_usage(int, char **, flash_cmd_t *); /* * flash commands */ static flash_cmd_t fl_cmds[] = { {"prom", fl_prom, FCMD_PROM_USAGE, FCMD_CHECK}, {"log", fl_log, FCMD_LOG_USAGE, FCMD_CHECK}, {"data", fl_data, FCMD_DATA_USAGE, FCMD_CHECK}, {"resetpds",fl_resetpds,FCMD_RESETPDS_USAGE, FCMD_CHECK}, {"rpromflg",fl_rpromflg,FCMD_RPROMFLG_USAGE, 0}, {"info", fl_info, FCMD_INFO_USAGE, 0}, {"?", fl_usage, FCMD_HELP_USAGE, 0}, {"help", fl_usage, FCMD_HELP_USAGE, 0}, #ifdef FDEBUG {"setenv", fl_senv, FCMD_SENV_USAGE, FCMD_CHECK}, {"unsetenv",fl_uenv, FCMD_UENV_USAGE, FCMD_CHECK}, {"getenv", fl_genv, FCMD_GENV_USAGE, FCMD_CHECK}, {"load", fl_load, FCMD_LOAD_USAGE, 0}, {"get", fl_get, FCMD_GET_USAGE, 0}, {"erase", fl_erase, FCMD_ERASE_USAGE, FCMD_CHECK}, {"pds", fl_pds, FCMD_PDS_USAGE, FCMD_CHECK}, {"writest", fl_writest, FCMD_WRITEST_USAGE, FCMD_CHECK}, {"copy", fl_copy, FCMD_COPY_USAGE, FCMD_CHECK}, {"1fc", fl_1fc, FCMD_1FC_USAGE, 0}, {"1fe", fl_1fe, FCMD_1FE_USAGE, 0}, {"dump", fl_dump, FCMD_DUMP_USAGE, 0}, {"time", fl_time, FCMD_TIME_USAGE, 0}, {"cksum", fl_cksum, FCMD_CKSUM_USAGE, 0}, {"sum-r", fl_sum_r, FCMD_SUM_R_USAGE, 0}, {"log_test",fl_log_test,FCMD_LOG_TEST_USAGE, 0}, {"power", fl_power, "power", 0}, {"ttf", fl_ttf, "[extra | erase_only] []", 0}, #endif /* FDEBUG */ {"repeat", fl_repeat, "repeat count flash cmd ...", 0}, { 0 }, }; /*ARGSUSED*/ static int fl_usage(int argc, char **argv, flash_cmd_t *fcmdp) { for (fcmdp = fl_cmds; fcmdp->cmd; fcmdp++) FLASH_USAGE(fcmdp); return(0); } /*ARGSUSED*/ int flash_cmd(int argc, char **argv, char **envp) { flash_cmd_t *fcmdp = fl_cmds; if (argc < 2) goto err; for (; fcmdp->cmd; fcmdp++) { if ( !strcmp(fcmdp->cmd, argv[1])) { if (fcmdp->flags & FCMD_CHECK) { if (!flash_ok()) { FPR_ERR(("flash: flash part not found at 0x%x\n", flash_mem_base)); return(0); } } argc -= 2; argv += 2; (void)(*fcmdp->func)(argc, argv, fcmdp); return(0); } } FPR_ERR(("unknown flash command\n")); err: return(fl_usage(argc, argv, fl_cmds)); } #endif /* defined(IP30) */