#include #include #include #include #include #include #include #include #include "flashcommon.h" #define OPTS "po:c:O:" int cputypes = 0xf; /* bits from cpubits[] */ char *outfile = "prom.inst"; char *infile; int flash_ver[2]; uint loadoffset = 0x4400; int print_seg_info = 0; extern int optind; extern char *optarg; extern int opterr; static int valid_seg_hdr(FlashSegment *seg) { long *xslim = body(seg); long *xsp; long xsum; if (print_seg_info) printf("seg limit is 0x%x\n", xslim); if ((seg->magic != FLASH_SEGMENT_MAGIC) || ((int)seg & FLASH_PAGE_SIZE - 1) || (seg->segLen & 0x3)) { if (print_seg_info) printf("seg magic, alignment or length is invalid\n"); return(0); } for (xsum = 0, xsp = (long *)seg; xsp != xslim; xsp++) xsum += *xsp; if (print_seg_info) printf("calculated checksum is: %d\n", xsum); return(xsum == 0); } /* * next_seg returns a pointer to the next valid segment header * in the flash. It returns NULL if no valid header is found * before reaching the end of the flash address space. * * NB: if *flash points to a valid header next_seg will return * the value of flash. */ static FlashSegment * next_seg(char *flash, char *lim) { long *magicptr = (long *)((int)flash & ~0x3); /* ensure proper alignment */ FlashSegment *seg; /* * since we are looking for an int, align to last int * in the file */ lim = (char *)((int)lim & ~0x3); next: while (*magicptr != FLASH_SEGMENT_MAGICx) { if (magicptr >= (long *)(lim)) { return(NULL); } else { magicptr++; } } seg = (FlashSegment *)((int)magicptr - sizeof(long long)); if (valid_seg_hdr(seg)) { if (seg->segLen != 0) return(seg); else return(NULL); } else { if (++magicptr >= (long *)lim) return(NULL); } goto next; } void print_segs(char *flash, char *lim) { long *magicptr = (long *)((int)flash & ~0x3); /* ensure proper alignment */ FlashSegment *seg; char strbuf[256]; /* * since we are looking for an int, align to last int * in the file */ lim = (char *)((int)lim & ~0x3); next: while (*magicptr != FLASH_SEGMENT_MAGICx) { if (magicptr >= (long *)(lim)) { return; } else { magicptr++; } } seg = (FlashSegment *)((int)magicptr - sizeof(long long)); printf("segment address\t: 0x%x\n", seg); printf("seg->reserved\t: 0x%llx\n", seg->reserved); printf("seg->magic\t: 0x%x\n", seg->magic); printf("seg->segLen\t: 0x%x\n", seg->segLen); printf("seg->nameLen\t: 0x%x\n", seg->nameLen); printf("seg->vsnLen\t: 0x%x\n", seg->vsnLen); printf("seg->segType\t: 0x%x\n", seg->segType); printf("seg->pad \t: 0x%x\n", seg->pad); strncpy(strbuf, seg->name, seg->nameLen); strbuf[seg->nameLen] = '\0'; printf("seg->name\t: %s\n", strbuf); strncpy(strbuf, seg->version, seg->vsnLen); strbuf[seg->vsnLen] = '\0'; printf("seg->version\t: %s\n", strbuf); printf("seg->chksum\t: %d\n", seg->chksum); if (valid_seg_hdr(seg)) { printf("This segment is VALID\n\n"); } else { printf("This segment is INVALID\n\n"); } magicptr++; goto next; } /* * find_named_flash_seg() returns a pointer to the first data byte * in the named flash ROM segment. */ static FlashSegment * find_named_flash_seg(char *name, char *fp, int len) { FlashSegment *seg = (FlashSegment *)fp; while (seg = next_seg((char *)seg, (char *)((int)fp + (len - 1)))) { if (!strncmp(seg->name, name, seg->nameLen)) return(seg); seg = (FlashSegment *)((int)seg + seg->segLen); } return(NULL); } #ifdef isdigit #undef isdigit #endif #define isdigit(x) (((x) >= '0') && ((x) <= '9')) #define toint(x) ((int)(x) - (int)('0')) static void get_flash_version(char *fp, int len) { FlashSegment *seg = find_named_flash_seg("version", fp, len); char *verno; flash_ver[FLASHPROM_MAJOR] = flash_ver[FLASHPROM_MINOR] = 0; if (seg == NULL) { seg = find_named_flash_seg("firmware", fp, len); if (seg == NULL) { fprintf(stderr, "no valid version or firmware segment found\n"); exit(4); } } if (seg->vsnLen == 0) return; verno = seg->version; /* * flash version numbers are of the form x.y where x and y * are both decimal integers. Check to ensure that first * character of the version string is a decimal digit. */ if (!isdigit(*verno)) return; /* * while reading decimal digits calculate the integer version number */ while (isdigit(*verno)) { flash_ver[FLASHPROM_MAJOR] = (flash_ver[FLASHPROM_MAJOR] * 10) + toint(*verno); verno++; } /* * we should have stopped at a decimal point * if not, we don't have a valid version string, reset major to 0 * and return */ if (*verno++ != '.') { flash_ver[FLASHPROM_MAJOR] = 0; return; } /* * a digit should follow the decimal point, if not, we don't * have a valid version string. */ if (!isdigit(*verno)) { flash_ver[FLASHPROM_MAJOR] = 0; return; } /* * get the minor version number. */ while (isdigit(*verno)) { flash_ver[FLASHPROM_MINOR] = (flash_ver[FLASHPROM_MINOR] * 10) + toint(*verno); verno++; } } int flash_version(int which, char *fp, int len) { static int beenthere = 0; if (beenthere) return(which ? flash_ver[FLASHPROM_MINOR] : flash_ver[FLASHPROM_MAJOR]); get_flash_version(fp, len); beenthere = 1; return(which ? flash_ver[FLASHPROM_MINOR] : flash_ver[FLASHPROM_MAJOR]); } void create_header(promhdr_t *hp, char *fp, int len, int cputypes, uint off) { hp->magic = PROM_MAGIC; hp->offset = off; hp->len = len; hp->version[FLASHPROM_MAJOR] = flash_version(FLASHPROM_MAJOR, fp, len); hp->version[FLASHPROM_MINOR] = flash_version(FLASHPROM_MINOR, fp, len); hp->cputypes = cputypes; hp->cksum = gensum(fp, len); } void write_outfile(char *outfile, promhdr_t *hp, char *fp, int len) { int fd; char hdrbuf[FLASH_PAGE_SIZE]; if ((fd = open(outfile, O_RDWR|O_TRUNC|O_CREAT, 0644)) < 0) { perror("open"); exit(3); } bzero(hdrbuf, FLASH_PAGE_SIZE); bcopy(hp, hdrbuf, sizeof(promhdr_t)); if (write(fd, hdrbuf, FLASH_PAGE_SIZE) < 0) { perror("write"); exit(3); } if (write(fd, fp, len) < 0) { perror("write"); exit(3); } close(fd); } void unknown_cpu(void) { int i; fprintf(stderr, "Unknown cpu type. Recognized cpu types are:\n"); for (i = 0; i < NCPUTYPES; i++) { fprintf(stderr, "\t%s\n", cpustrings[i]); } } void usage(void) { fprintf(stderr, "flashbuild [-p] [-o file] [-c cputype[,cputype...]] [-O offset] file\n"); } main(int argc, char **argv) { int o; struct stat sbuf; promhdr_t hdr; char *options; int fd; char *fp; int len; opterr = 0; if (argc < 2) { usage(); exit(1); } while ((o = getopt(argc, argv, OPTS)) != EOF) { switch (o) { case 'p': print_seg_info = 1; break; case 'o': outfile = optarg; break; case 'c': options = optarg; cputypes = 0; while (*options) { int i; char *value; switch (i = getsubopt(&options, cpustrings, &value)) { case R4600: case R4600SC: case R5000: case R5000SC: case R5000LM: case R5000SCLM: case R10000: case R10000MP: case R10000LM: case R10000MPLM: cputypes |= cpubits[i]; break; default: unknown_cpu(); usage(); exit(1); } } break; case 'O': loadoffset = strtoul(optarg, NULL, 0); break; default: usage(); exit(1); } } if (optind != argc - 1) { usage(); exit(1); } infile = argv[optind]; if ((fd = open(infile, O_RDONLY)) < 0) { perror("open"); exit(2); } if (fstat(fd, &sbuf) < 0) { perror("fstat"); exit(2); } /* round file length up to nearest 256 byte boundry */ len = (sbuf.st_size + 255) & ~0xff; if ((int)(fp = mmap(0, len, PROT_READ, MAP_SHARED, fd, 0)) == -1) { perror("mmap"); exit(2); } if (print_seg_info) { print_segs(fp, (char *)(fp + len - 1)); exit(0); } /* * current flash images have a segment header as the first * structure in the file -- check to see if this is so. * XXX: if the layout of the flash image file changes, this * assumption may no longer hold true. */ if (!valid_seg_hdr((FlashSegment *)fp)) { fprintf(stderr, "not a valid flash image file\n"); exit(4); } create_header(&hdr, fp, len, cputypes, loadoffset); write_outfile(outfile, &hdr, fp, len); exit(0); }