static int ublast2_write_firmware_section(struct jtag_libusb_device_handle *libusb_dev, struct image *firmware_image, int section_index) { uint16_t chunk_size; uint8_t data[SECTION_BUFFERSIZE]; uint8_t *data_ptr = data; size_t size_read; uint16_t size = (uint16_t)firmware_image->sections[section_index].size; uint16_t addr = (uint16_t)firmware_image->sections[section_index].base_address; LOG_DEBUG("section %02i at addr 0x%04x (size 0x%04x)", section_index, addr, size); /* Copy section contents to local buffer */ int ret = image_read_section(firmware_image, section_index, 0, size, data, &size_read); if ((ret != ERROR_OK) || (size_read != size)) { /* Propagating the return code would return '0' (misleadingly indicating * successful execution of the function) if only the size check fails. */ return ERROR_FAIL; } uint16_t bytes_remaining = size; /* Send section data in chunks of up to 64 bytes to ULINK */ while (bytes_remaining > 0) { if (bytes_remaining > 64) chunk_size = 64; else chunk_size = bytes_remaining; jtag_libusb_control_transfer(libusb_dev, LIBUSB_REQUEST_TYPE_VENDOR | \ LIBUSB_ENDPOINT_OUT, USBBLASTER_CTRL_LOAD_FIRM, addr, 0, (char *)data_ptr, chunk_size, 100); bytes_remaining -= chunk_size; addr += chunk_size; data_ptr += chunk_size; } return ERROR_OK; }
static int loadDriver(struct ecosflash_flash_bank *info) { size_t buf_cnt; size_t image_size; struct image image; image.base_address_set = 0; image.start_address_set = 0; struct target *target = info->target; int retval; if ((retval = image_open(&image, info->driverPath, NULL)) != ERROR_OK) { return retval; } info->start_address = image.start_address; image_size = 0x0; int i; for (i = 0; i < image.num_sections; i++) { void *buffer = malloc(image.sections[i].size); if ((retval = image_read_section(&image, i, 0x0, image.sections[i].size, buffer, &buf_cnt)) != ERROR_OK) { free(buffer); image_close(&image); return retval; } target_write_buffer(target, image.sections[i].base_address, buf_cnt, buffer); image_size += buf_cnt; LOG_DEBUG("%zu bytes written at address 0x%8.8" PRIx32 "", buf_cnt, image.sections[i].base_address); free(buffer); } image_close(&image); return ERROR_OK; }
int flash_write_unlock(struct target *target, struct image *image, uint32_t *written, int erase, bool unlock) { int retval = ERROR_OK; int section; uint32_t section_offset; struct flash_bank *c; int *padding; section = 0; section_offset = 0; if (written) *written = 0; if (erase) { /* assume all sectors need erasing - stops any problems * when flash_write is called multiple times */ flash_set_dirty(); } /* allocate padding array */ padding = calloc(image->num_sections, sizeof(*padding)); /* This fn requires all sections to be in ascending order of addresses, * whereas an image can have sections out of order. */ struct imagesection **sections = malloc(sizeof(struct imagesection *) * image->num_sections); int i; for (i = 0; i < image->num_sections; i++) { sections[i] = &image->sections[i]; } qsort(sections, image->num_sections, sizeof(struct imagesection *), compare_section); /* loop until we reach end of the image */ while (section < image->num_sections) { uint32_t buffer_size; uint8_t *buffer; int section_last; uint32_t run_address = sections[section]->base_address + section_offset; uint32_t run_size = sections[section]->size - section_offset; int pad_bytes = 0; if (sections[section]->size == 0) { LOG_WARNING("empty section %d", section); section++; section_offset = 0; continue; } /* find the corresponding flash bank */ retval = get_flash_bank_by_addr(target, run_address, false, &c); if (retval != ERROR_OK) { goto done; } if (c == NULL) { section++; /* and skip it */ section_offset = 0; continue; } /* collect consecutive sections which fall into the same bank */ section_last = section; padding[section] = 0; while ((run_address + run_size - 1 < c->base + c->size - 1) && (section_last + 1 < image->num_sections)) { /* sections are sorted */ assert(sections[section_last + 1]->base_address >= c->base); if (sections[section_last + 1]->base_address >= (c->base + c->size)) { /* Done with this bank */ break; } /* FIXME This needlessly touches sectors BETWEEN the * sections it's writing. Without auto erase, it just * writes ones. That WILL INVALIDATE data in cases * like Stellaris Tempest chips, corrupting internal * ECC codes; and at least FreeScale suggests issues * with that approach (in HC11 documentation). * * With auto erase enabled, data in those sectors will * be needlessly destroyed; and some of the limited * number of flash erase cycles will be wasted... * * In both cases, the extra writes slow things down. */ /* if we have multiple sections within our image, * flash programming could fail due to alignment issues * attempt to rebuild a consecutive buffer for the flash loader */ pad_bytes = (sections[section_last + 1]->base_address) - (run_address + run_size); padding[section_last] = pad_bytes; run_size += sections[++section_last]->size; run_size += pad_bytes; if (pad_bytes > 0) LOG_INFO("Padding image section %d with %d bytes", section_last-1, pad_bytes); } if (run_address + run_size - 1 > c->base + c->size - 1) { /* If we have more than one flash chip back to back, then we limit * the current write operation to the current chip. */ LOG_DEBUG("Truncate flash run size to the current flash chip."); run_size = c->base + c->size - run_address; assert(run_size > 0); } /* If we're applying any sector automagic, then pad this * (maybe-combined) segment to the end of its last sector. */ if (unlock || erase) { int sector; uint32_t offset_start = run_address - c->base; uint32_t offset_end = offset_start + run_size; uint32_t end = offset_end, delta; for (sector = 0; sector < c->num_sectors; sector++) { end = c->sectors[sector].offset + c->sectors[sector].size; if (offset_end <= end) break; } delta = end - offset_end; padding[section_last] += delta; run_size += delta; } /* allocate buffer */ buffer = malloc(run_size); if (buffer == NULL) { LOG_ERROR("Out of memory for flash bank buffer"); retval = ERROR_FAIL; goto done; } buffer_size = 0; /* read sections to the buffer */ while (buffer_size < run_size) { size_t size_read; size_read = run_size - buffer_size; if (size_read > sections[section]->size - section_offset) size_read = sections[section]->size - section_offset; /* KLUDGE! * * #¤%#"%¤% we have to figure out the section # from the sorted * list of pointers to sections to invoke image_read_section()... */ intptr_t diff = (intptr_t)sections[section] - (intptr_t)image->sections; int t_section_num = diff / sizeof(struct imagesection); LOG_DEBUG("image_read_section: section = %d, t_section_num = %d, section_offset = %d, buffer_size = %d, size_read = %d", (int)section, (int)t_section_num, (int)section_offset, (int)buffer_size, (int)size_read); if ((retval = image_read_section(image, t_section_num, section_offset, size_read, buffer + buffer_size, &size_read)) != ERROR_OK || size_read == 0) { free(buffer); goto done; } /* see if we need to pad the section */ while (padding[section]--) (buffer + buffer_size)[size_read++] = 0xff; buffer_size += size_read; section_offset += size_read; if (section_offset >= sections[section]->size) { section++; section_offset = 0; } } retval = ERROR_OK; if (unlock) { retval = flash_unlock_address_range(target, run_address, run_size); } if (retval == ERROR_OK) { if (erase) { /* calculate and erase sectors */ retval = flash_erase_address_range(target, true, run_address, run_size); } } if (retval == ERROR_OK) { /* write flash sectors */ retval = flash_driver_write(c, buffer, run_address - c->base, run_size); } free(buffer); if (retval != ERROR_OK) { /* abort operation */ goto done; } if (written != NULL) *written += run_size; /* add run size to total written counter */ } done: free(sections); free(padding); return retval; }