* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the *
- * Free Software Foundation, Inc., *
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
struct flash_bank *p;
int j = 0;
int retval;
+ bool show_sectors = false;
+ bool prot_block_available;
- if (CMD_ARGC != 1)
+ if (CMD_ARGC < 1 || CMD_ARGC > 2)
return ERROR_COMMAND_SYNTAX_ERROR;
+ if (CMD_ARGC == 2) {
+ if (strcmp("sectors", CMD_ARGV[1]) == 0)
+ show_sectors = true;
+ else
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+
retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &p);
if (retval != ERROR_OK)
return retval;
if (p != NULL) {
char buf[1024];
+ int num_blocks;
+ struct flash_sector *block_array;
/* attempt auto probe */
retval = p->driver->auto_probe(p);
p->size,
p->bus_width,
p->chip_width);
- for (j = 0; j < p->num_sectors; j++) {
- char *protect_state;
- if (p->sectors[j].is_protected == 0)
+ prot_block_available = p->num_prot_blocks && p->prot_blocks;
+ if (!show_sectors && prot_block_available) {
+ block_array = p->prot_blocks;
+ num_blocks = p->num_prot_blocks;
+ } else {
+ block_array = p->sectors;
+ num_blocks = p->num_sectors;
+ }
+
+ for (j = 0; j < num_blocks; j++) {
+ char *protect_state = "";
+
+ if (block_array[j].is_protected == 0)
protect_state = "not protected";
- else if (p->sectors[j].is_protected == 1)
+ else if (block_array[j].is_protected == 1)
protect_state = "protected";
- else
+ else if (!show_sectors || !prot_block_available)
protect_state = "protection state unknown";
command_print(CMD_CTX,
"\t#%3i: 0x%8.8" PRIx32 " (0x%" PRIx32 " %" PRIi32 "kB) %s",
j,
- p->sectors[j].offset,
- p->sectors[j].size,
- p->sectors[j].size >> 10,
+ block_array[j].offset,
+ block_array[j].size,
+ block_array[j].size >> 10,
protect_state);
}
COMMAND_HANDLER(handle_flash_erase_check_command)
{
+ bool blank = true;
if (CMD_ARGC != 1)
return ERROR_COMMAND_SYNTAX_ERROR;
if (p->sectors[j].is_erased == 0)
erase_state = "not erased";
else if (p->sectors[j].is_erased == 1)
- erase_state = "erased";
+ continue;
else
erase_state = "erase state unknown";
+ blank = false;
command_print(CMD_CTX,
"\t#%3i: 0x%8.8" PRIx32 " (0x%" PRIx32 " %" PRIi32 "kB) %s",
j,
erase_state);
}
+ if (blank)
+ command_print(CMD_CTX, "\tBank is erased");
return retval;
}
"in %fs", first, last, p->bank_number, duration_elapsed(&bench));
}
- return ERROR_OK;
+ return retval;
}
COMMAND_HANDLER(handle_flash_protect_command)
struct flash_bank *p;
int retval;
+ int num_blocks;
retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &p);
if (retval != ERROR_OK)
return retval;
+ if (p->num_prot_blocks)
+ num_blocks = p->num_prot_blocks;
+ else
+ num_blocks = p->num_sectors;
+
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], first);
if (strcmp(CMD_ARGV[2], "last") == 0)
- last = p->num_sectors - 1;
+ last = num_blocks - 1;
else
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], last);
bool set;
COMMAND_PARSE_ON_OFF(CMD_ARGV[3], set);
- retval = flash_check_sector_parameters(CMD_CTX, first, last, p->num_sectors);
+ retval = flash_check_sector_parameters(CMD_CTX, first, last, num_blocks);
if (retval != ERROR_OK)
return retval;
{
uint32_t offset;
uint8_t *buffer;
- struct fileio fileio;
+ struct fileio *fileio;
if (CMD_ARGC != 3)
return ERROR_COMMAND_SYNTAX_ERROR;
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], offset);
if (fileio_open(&fileio, CMD_ARGV[1], FILEIO_READ, FILEIO_BINARY) != ERROR_OK)
- return ERROR_OK;
+ return ERROR_FAIL;
- int filesize;
- retval = fileio_size(&fileio, &filesize);
+ size_t filesize;
+ retval = fileio_size(fileio, &filesize);
if (retval != ERROR_OK) {
- fileio_close(&fileio);
+ fileio_close(fileio);
return retval;
}
buffer = malloc(filesize);
if (buffer == NULL) {
- fileio_close(&fileio);
+ fileio_close(fileio);
LOG_ERROR("Out of memory");
return ERROR_FAIL;
}
size_t buf_cnt;
- if (fileio_read(&fileio, filesize, buffer, &buf_cnt) != ERROR_OK) {
+ if (fileio_read(fileio, filesize, buffer, &buf_cnt) != ERROR_OK) {
free(buffer);
- fileio_close(&fileio);
- return ERROR_OK;
+ fileio_close(fileio);
+ return ERROR_FAIL;
}
retval = flash_driver_write(p, buffer, offset, buf_cnt);
buffer = NULL;
if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK)) {
- command_print(CMD_CTX, "wrote %ld bytes from file %s to flash bank %u"
+ command_print(CMD_CTX, "wrote %zu bytes from file %s to flash bank %u"
" at offset 0x%8.8" PRIx32 " in %fs (%0.3f KiB/s)",
- (long)filesize, CMD_ARGV[1], p->bank_number, offset,
+ filesize, CMD_ARGV[1], p->bank_number, offset,
duration_elapsed(&bench), duration_kbps(&bench, filesize));
}
- fileio_close(&fileio);
+ fileio_close(fileio);
+
+ return retval;
+}
+
+COMMAND_HANDLER(handle_flash_read_bank_command)
+{
+ uint32_t offset;
+ uint8_t *buffer;
+ struct fileio *fileio;
+ uint32_t length;
+ size_t written;
+
+ if (CMD_ARGC != 4)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ struct duration bench;
+ duration_start(&bench);
+
+ struct flash_bank *p;
+ int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &p);
+ if (ERROR_OK != retval)
+ return retval;
+
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], offset);
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], length);
+
+ buffer = malloc(length);
+ if (buffer == NULL) {
+ LOG_ERROR("Out of memory");
+ return ERROR_FAIL;
+ }
+
+ retval = flash_driver_read(p, buffer, offset, length);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Read error");
+ free(buffer);
+ return retval;
+ }
+
+ retval = fileio_open(&fileio, CMD_ARGV[1], FILEIO_WRITE, FILEIO_BINARY);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Could not open file");
+ free(buffer);
+ return retval;
+ }
+
+ retval = fileio_write(fileio, length, buffer, &written);
+ fileio_close(fileio);
+ free(buffer);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Could not write file");
+ return ERROR_FAIL;
+ }
+
+ if (duration_measure(&bench) == ERROR_OK)
+ command_print(CMD_CTX, "wrote %ld bytes to file %s from flash bank %u"
+ " at offset 0x%8.8" PRIx32 " in %fs (%0.3f KiB/s)",
+ (long)written, CMD_ARGV[1], p->bank_number, offset,
+ duration_elapsed(&bench), duration_kbps(&bench, written));
return retval;
}
+
+COMMAND_HANDLER(handle_flash_verify_bank_command)
+{
+ uint32_t offset;
+ uint8_t *buffer_file, *buffer_flash;
+ struct fileio *fileio;
+ size_t read_cnt;
+ size_t filesize;
+ int differ;
+
+ if (CMD_ARGC != 3)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ struct duration bench;
+ duration_start(&bench);
+
+ struct flash_bank *p;
+ int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &p);
+ if (ERROR_OK != retval)
+ return retval;
+
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], offset);
+
+ retval = fileio_open(&fileio, CMD_ARGV[1], FILEIO_READ, FILEIO_BINARY);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Could not open file");
+ return retval;
+ }
+
+ retval = fileio_size(fileio, &filesize);
+ if (retval != ERROR_OK) {
+ fileio_close(fileio);
+ return retval;
+ }
+
+ buffer_file = malloc(filesize);
+ if (buffer_file == NULL) {
+ LOG_ERROR("Out of memory");
+ fileio_close(fileio);
+ return ERROR_FAIL;
+ }
+
+ retval = fileio_read(fileio, filesize, buffer_file, &read_cnt);
+ fileio_close(fileio);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("File read failure");
+ free(buffer_file);
+ return retval;
+ }
+
+ if (read_cnt != filesize) {
+ LOG_ERROR("Short read");
+ free(buffer_file);
+ return ERROR_FAIL;
+ }
+
+ buffer_flash = malloc(filesize);
+ if (buffer_flash == NULL) {
+ LOG_ERROR("Out of memory");
+ free(buffer_file);
+ return ERROR_FAIL;
+ }
+
+ retval = flash_driver_read(p, buffer_flash, offset, read_cnt);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Flash read error");
+ free(buffer_flash);
+ free(buffer_file);
+ return retval;
+ }
+
+ if (duration_measure(&bench) == ERROR_OK)
+ command_print(CMD_CTX, "read %ld bytes from file %s and flash bank %u"
+ " at offset 0x%8.8" PRIx32 " in %fs (%0.3f KiB/s)",
+ (long)read_cnt, CMD_ARGV[1], p->bank_number, offset,
+ duration_elapsed(&bench), duration_kbps(&bench, read_cnt));
+
+ differ = memcmp(buffer_file, buffer_flash, read_cnt);
+ command_print(CMD_CTX, "contents %s", differ ? "differ" : "match");
+ if (differ) {
+ uint32_t t;
+ int diffs = 0;
+ for (t = 0; t < read_cnt; t++) {
+ if (buffer_flash[t] == buffer_file[t])
+ continue;
+ command_print(CMD_CTX, "diff %d address 0x%08x. Was 0x%02x instead of 0x%02x",
+ diffs, t + offset, buffer_flash[t], buffer_file[t]);
+ if (diffs++ >= 127) {
+ command_print(CMD_CTX, "More than 128 errors, the rest are not printed.");
+ break;
+ }
+ keep_alive();
+ }
+ }
+ free(buffer_flash);
+ free(buffer_file);
+
+ return differ ? ERROR_FAIL : ERROR_OK;
+}
+
void flash_set_dirty(void)
{
struct flash_bank *c;
.name = "info",
.handler = handle_flash_info_command,
.mode = COMMAND_EXEC,
- .usage = "bank_id",
+ .usage = "bank_id ['sectors']",
.help = "Print information about a flash bank.",
},
{
"and/or erase the region to be used. Allow optional "
"offset from beginning of bank (defaults to zero)",
},
+ {
+ .name = "read_bank",
+ .handler = handle_flash_read_bank_command,
+ .mode = COMMAND_EXEC,
+ .usage = "bank_id filename offset length",
+ .help = "Read binary data from flash bank to file, "
+ "starting at specified byte offset from the "
+ "beginning of the bank.",
+ },
+ {
+ .name = "verify_bank",
+ .handler = handle_flash_verify_bank_command,
+ .mode = COMMAND_EXEC,
+ .usage = "bank_id filename offset",
+ .help = "Read binary data from flash bank and file, "
+ "starting at specified byte offset from the "
+ "beginning of the bank. Compare the contents.",
+ },
{
.name = "protect",
.handler = handle_flash_protect_command,
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], c->size);
COMMAND_PARSE_NUMBER(int, CMD_ARGV[3], c->chip_width);
COMMAND_PARSE_NUMBER(int, CMD_ARGV[4], c->bus_width);
- c->default_padded_value = 0xff;
+ c->default_padded_value = c->erased_value = 0xff;
c->num_sectors = 0;
c->sectors = NULL;
+ c->num_prot_blocks = 0;
+ c->prot_blocks = NULL;
c->next = NULL;
int retval;