1
0
Files
irix-657m-src/irix/cmd/flash/flashbuild.c
2022-09-29 17:59:04 +03:00

415 lines
8.6 KiB
C

#include <sys/types.h>
#include <sys/IP32flash.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#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);
}