예제 #1
0
/**********************************************************************
 *
 **********************************************************************
 0 1 2 3 4
:1000100084C083C082C081C080C07FC07EC07DC0DC
 ~~ データ長
   ~~~~ アドレス
       ~~ レコードタイプ
         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~データ
                                         ~~チェックサム.
 */
int	read_ihex(char *s)
{
	int c;
	if(s[0] == ':') {
		read_hex_string(s+1);
		c = databuf[3];
		parse_ihex(c,databuf,dataidx);
	}
	return 0;
}
예제 #2
0
파일: firmware.c 프로젝트: florolf/canboot
static int firmware_validate(const char *firmware_path, struct controller_param **params) {
    FILE *f = fopen(firmware_path, "r");

    if(!f) {
        perror("Opening firmware file failed");
        return 0;
    }

    int ret = 0;
    char buf[256];
    uint32_t offset = 0;
    bool got_type = false;

    while(fgets(buf, 256, f)) {
        chomp(buf);

        if(buf[0] == '#')
            continue;
        else if(buf[0] == 'C') {
            const char *name = &buf[2];
            size_t name_len = strlen(name);

            got_type = true;

            struct controller_param *p;

            *params = NULL;
            for(p = controller_params; p->name; p++)
                if(!strncasecmp(p->name, name, name_len)) {
                    *params = p;
                    break;
                }

            if(!*params) {
                log("Unknown controller type \"%s\"", name);
                ret = 0;
                goto out;
            }
        }
        else if(buf[0] == ':') {
            if(!got_type) {
                log("Got IHEX before type statement");
                ret = 0;
                goto out;
            }

            uint32_t new_offset, length;

            enum ihex_record rtype = parse_ihex(buf, &new_offset, &length, NULL);
            switch(rtype) {
            case IHEX_INVALID:
                ret = 0;
                goto out;
                break;

            case IHEX_DATA:
                if(new_offset < offset) {
                    log("IHEX is not monotonic");
                    ret = 0;
                    goto out;
                }

                offset = new_offset;

                if(offset + length > PAGE_ROUND_DOWN((*params)->pagesize, (*params)->bootloader_offset)) {
                    log("Data reaches into bootloader area");
                    ret = 0;
                    goto out;
                }
                break;

            case IHEX_EOF:
                break;

            default:
                log("Unsupported IHEX record %02X", rtype);
                ret = 0;
                goto out;
                break;
            }
        } else {
            log("Got invalid line: %s", buf);
            ret = 0;
            goto out;
        }
    }

    if(!got_type) {
        log("Controller type needs to be specified");
        ret = 0;
        goto out;
    }

    ret = 1;
out:
    fclose(f);
    return ret;
}
예제 #3
0
파일: firmware.c 프로젝트: florolf/canboot
int firmware_flash(int cansock, const char *firmware_dir, canid_t addr) {
    const char *file = firmware_make_path(firmware_dir, addr);

    log("Using firmware file %s", file);

    struct controller_param *params;
    if(!firmware_validate(file, &params)) {
        log("Firmware file validation failed, sending reset");

        can_send_reset(cansock, addr);

        return -1;
    }

    FILE *f = fopen(file, "r");
    char buf[256];
    uint8_t *pagebuf = malloc(params->pagesize);
    uint32_t fillcnt = 0, base_addr;

    while(fgets(buf, 256, f)) {
        chomp(buf);

        if(buf[0] != ':')
            continue;

        uint32_t offset, length;
        uint8_t *data;
        if(parse_ihex(buf, &offset, &length, &data) == IHEX_EOF)
            break;

        while(length) {
            if(fillcnt == 0) { // We're starting a new page
                base_addr = PAGE_ROUND_DOWN(params->pagesize, offset);

                memset(pagebuf, 0, offset - base_addr);
                fillcnt = offset - base_addr;

                can_send_set_zpointer(cansock, addr, base_addr);
            }

            uint32_t to_write = MIN(length, params->pagesize - fillcnt);

            memcpy(pagebuf + fillcnt, data, to_write);
            fillcnt += to_write;
            offset += to_write;
            length -= to_write;

            if(fillcnt == params->pagesize) { // page complete, flash it
                if(do_flash(cansock, addr, fillcnt, pagebuf) < 0) {
                    log("Flashing page 0x%X failed", base_addr / 2);

                    free(data);
                    free(pagebuf);

                    return -1;
                }
                fillcnt = 0;
            }

            memmove(data, data + to_write, length);
        }

        free(data);
    }

    if(fillcnt) { // there's some data left
        if(do_flash(cansock, addr, fillcnt, pagebuf) < 0) {
            log("Flashing page 0x%X failed", base_addr / 2);

            free(pagebuf);

            return -1;
        }
    }

    free(pagebuf);

    log("Resetting device");
    can_send_reset(cansock, addr);

    return 0;
}
예제 #4
0
/*
 * Load a firmware file into target RAM. device is the open libusbx
 * device, and the path is the name of the source file. Open the file,
 * parse the bytes, and write them in one or two phases.
 *
 * If stage == 0, this uses the first stage loader, built into EZ-USB
 * hardware but limited to writing on-chip memory or CPUCS.  Everything
 * is written during one stage, unless there's an error such as the image
 * holding data that needs to be written to external memory.
 *
 * Otherwise, things are written in two stages.  First the external
 * memory is written, expecting a second stage loader to have already
 * been loaded.  Then file is re-parsed and on-chip memory is written.
 */
int ezusb_load_ram(libusb_device_handle *device, const char *path, int fx_type, int img_type, int stage)
{
	FILE *image;
	uint32_t cpucs_addr;
	bool (*is_external)(uint32_t off, size_t len);
	struct ram_poke_context ctx;
	int status;
	uint8_t iic_header[8] = { 0 };

	if (fx_type == FX_TYPE_FX3)
		return fx3_load_ram(device, path);

	image = fopen(path, "rb");
	if (image == NULL) {
		logerror("%s: unable to open for input.\n", path);
		return -2;
	} else if (verbose > 1)
		logerror("open firmware image %s for RAM upload\n", path);

	if (img_type == IMG_TYPE_IIC) {
		if ( (fread(iic_header, 1, sizeof(iic_header), image) != sizeof(iic_header))
		  || (((fx_type == FX_TYPE_FX2LP) || (fx_type == FX_TYPE_FX2)) && (iic_header[0] != 0xC2))
		  || ((fx_type == FX_TYPE_AN21) && (iic_header[0] != 0xB2))
		  || ((fx_type == FX_TYPE_FX1) && (iic_header[0] != 0xB6)) ) {
			logerror("IIC image does not contain executable code - cannot load to RAM.\n");
			return -1;
		}
	}

	/* EZ-USB original/FX and FX2 devices differ, apart from the 8051 core */
	switch(fx_type) {
	case FX_TYPE_FX2LP:
		cpucs_addr = 0xe600;
		is_external = fx2lp_is_external;
		break;
	case FX_TYPE_FX2:
		cpucs_addr = 0xe600;
		is_external = fx2_is_external;
		break;
	default:
		cpucs_addr = 0x7f92;
		is_external = fx_is_external;
		break;
	}

	/* use only first stage loader? */
	if (stage == 0) {
		ctx.mode = internal_only;

		/* if required, halt the CPU while we overwrite its code/data */
		if (cpucs_addr && !ezusb_cpucs(device, cpucs_addr, false))
			return -1;

		/* 2nd stage, first part? loader was already uploaded */
	} else {
		ctx.mode = skip_internal;

		/* let CPU run; overwrite the 2nd stage loader later */
		if (verbose)
			logerror("2nd stage: write external memory\n");
	}

	/* scan the image, first (maybe only) time */
	ctx.device = device;
	ctx.total = ctx.count = 0;
	status = parse[img_type](image, &ctx, is_external, ram_poke);
	if (status < 0) {
		logerror("unable to upload %s\n", path);
		return status;
	}

	/* second part of 2nd stage: rescan */
	// TODO: what should we do for non HEX images there?
	if (stage) {
		ctx.mode = skip_external;

		/* if needed, halt the CPU while we overwrite the 1st stage loader */
		if (cpucs_addr && !ezusb_cpucs(device, cpucs_addr, false))
			return -1;

		/* at least write the interrupt vectors (at 0x0000) for reset! */
		rewind(image);
		if (verbose)
			logerror("2nd stage: write on-chip memory\n");
		status = parse_ihex(image, &ctx, is_external, ram_poke);
		if (status < 0) {
			logerror("unable to completely upload %s\n", path);
			return status;
		}
	}

	if (verbose)
		logerror("... WROTE: %d bytes, %d segments, avg %d\n",
		(int)ctx.total, (int)ctx.count, (int)(ctx.total/ctx.count));

	/* if required, reset the CPU so it runs what we just uploaded */
	if (cpucs_addr && !ezusb_cpucs(device, cpucs_addr, true))
		return -1;

	return 0;
}
예제 #5
0
/*
 * Load an Intel HEX file into target RAM. The fd is the open "usbfs"
 * device, and the path is the name of the source file. Open the file,
 * parse the bytes, and write them in one or two phases.
 *
 * If stage == 0, this uses the first stage loader, built into EZ-USB
 * hardware but limited to writing on-chip memory or CPUCS.  Everything
 * is written during one stage, unless there's an error such as the image
 * holding data that needs to be written to external memory.
 *
 * Otherwise, things are written in two stages.  First the external
 * memory is written, expecting a second stage loader to have already
 * been loaded.  Then file is re-parsed and on-chip memory is written.
 */
int ezusb_load_ram (int fd, const char *path, int fx2, int stage)
{
    FILE			*image;
    unsigned short		cpucs_addr;
    int				(*is_external)(unsigned short off, size_t len);
    struct ram_poke_context	ctx;
    int				status;

    image = fopen (path, "r");
    if (image == 0) {
	fprintf (stderr, "%s: unable to open for input.\n", path);
	return -2;
    } else if (verbose)
	fprintf (stderr, "open RAM hexfile image %s\n", path);

    /* EZ-USB original/FX and FX2 devices differ, apart from the 8051 core */
    if (fx2) {
	cpucs_addr = 0xe600;
	is_external = fx2_is_external;
    } else {
	cpucs_addr = 0x7f92;
	is_external = fx_is_external;
    }

    /* use only first stage loader? */
    if (!stage) {
	ctx.mode = internal_only;

	/* don't let CPU run while we overwrite its code/data */
	if (!ezusb_cpucs (fd, cpucs_addr, 0))
	    return -1;

    /* 2nd stage, first part? loader was already downloaded */
    } else {
	ctx.mode = skip_internal;

	/* let CPU run; overwrite the 2nd stage loader later */
	if (verbose)
	    fprintf (stderr, "2nd stage:  write external memory\n");
    }
    
    /* scan the image, first (maybe only) time */
    ctx.device = fd;
    ctx.total = ctx.count = 0;
    status = parse_ihex (image, &ctx, is_external, ram_poke);
    if (status < 0) {
	fprintf (stderr, "unable to download %s\n", path);
	return status;
    }

    /* second part of 2nd stage: rescan */
    if (stage) {
	ctx.mode = skip_external;

	/* don't let CPU run while we overwrite the 1st stage loader */
	if (!ezusb_cpucs (fd, cpucs_addr, 0))
	    return -1;

	/* at least write the interrupt vectors (at 0x0000) for reset! */
	rewind (image);
	if (verbose)
	    fprintf (stderr, "2nd stage:  write on-chip memory\n");
	status = parse_ihex (image, &ctx, is_external, ram_poke);
	if (status < 0) {
	    fprintf (stderr, "unable to completely download %s\n", path);
	    return status;
	}
    }

    if (verbose)
	fprintf (stderr, "... WROTE: %d bytes, %d segments, avg %d\n",
	    ctx.total, ctx.count, ctx.total / ctx.count);
	
    /* now reset the CPU so it runs what we just downloaded */
    if (!ezusb_cpucs (fd, cpucs_addr, 1))
	return -1;

    return 0;
}