diff --git a/commands/Kconfig b/commands/Kconfig index 00627580e..e6168cede 100644 --- a/commands/Kconfig +++ b/commands/Kconfig @@ -303,7 +303,55 @@ config CMD_IOMEM config CMD_MEMORY bool default y - prompt "md and mw" + +config CMD_MD + tristate + default y + select CMD_MEMORY + prompt "md" + help + the md command allows to display (hexdump) memory locations and files. + +config CMD_MW + tristate + default y + select CMD_MEMORY + prompt "mw" + help + the mw command allows to write to memory locations and files. + +config CMD_MM + tristate + select CMD_MEMORY + prompt "memory modify (mm)" + help + the mm command allows to read-modify-write registers by doing: + reg = (reg & ~mask) | (val & mask) + +config CMD_MEMCMP + tristate + default y + select CMD_MEMORY + prompt "memcmp" + help + the memcmp command allows to compare memory and file regions. + +config CMD_MEMCPY + tristate + default y + select CMD_MEMORY + prompt "memcpy" + help + the memcpy command allows to copy memory and file regions. + +config CMD_MEMSET + tristate + default y + select CMD_MEMORY + prompt "memset" + help + the memset command allows to set regions of memory and files to + a specific value. config CMD_CRC tristate diff --git a/commands/Makefile b/commands/Makefile index 0ae6b9546..953ecc284 100644 --- a/commands/Makefile +++ b/commands/Makefile @@ -7,6 +7,12 @@ obj-$(CONFIG_CMD_LOADY) += loadxy.o obj-$(CONFIG_CMD_LOADS) += loads.o obj-$(CONFIG_CMD_ECHO) += echo.o obj-$(CONFIG_CMD_MEMORY) += mem.o +obj-$(CONFIG_CMD_MD) += md.o +obj-$(CONFIG_CMD_MM) += mm.o +obj-$(CONFIG_CMD_MW) += mw.o +obj-$(CONFIG_CMD_MEMCMP) += memcmp.o +obj-$(CONFIG_CMD_MEMCPY) += memcpy.o +obj-$(CONFIG_CMD_MEMSET) += memset.o obj-$(CONFIG_CMD_MTEST) += memtest.o obj-$(CONFIG_CMD_EDIT) += edit.o obj-$(CONFIG_CMD_EXEC) += exec.o diff --git a/commands/md.c b/commands/md.c new file mode 100644 index 000000000..03c5905bb --- /dev/null +++ b/commands/md.c @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2011 Sascha Hauer , Pengutronix + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +/* + * Memory Functions + * + * Copied from FADS ROM, Dan Malek (dmalek@jlc.net) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern char *mem_rw_buf; + +static int do_mem_md(int argc, char *argv[]) +{ + loff_t start = 0, size = 0x100; + int r, now; + int ret = 0; + int fd; + char *filename = "/dev/mem"; + int mode = O_RWSIZE_4; + int swab = 0; + + if (argc < 2) + return COMMAND_ERROR_USAGE; + + if (mem_parse_options(argc, argv, "bwls:x", &mode, &filename, NULL, + &swab) < 0) + return 1; + + if (optind < argc) { + if (parse_area_spec(argv[optind], &start, &size)) { + printf("could not parse: %s\n", argv[optind]); + return 1; + } + if (size == ~0) + size = 0x100; + } + + fd = open_and_lseek(filename, mode | O_RDONLY, start); + if (fd < 0) + return 1; + + do { + now = min(size, (loff_t)RW_BUF_SIZE); + r = read(fd, mem_rw_buf, now); + if (r < 0) { + perror("read"); + goto out; + } + if (!r) + goto out; + + if ((ret = memory_display(mem_rw_buf, start, r, + mode >> O_RWSIZE_SHIFT, swab))) + goto out; + + start += r; + size -= r; + } while (size); + +out: + close(fd); + + return ret ? 1 : 0; +} + +static const __maybe_unused char cmd_md_help[] = +"Usage md [OPTIONS] \n" +"display (hexdump) a memory region.\n" +"options:\n" +" -s display file (default /dev/mem)\n" +" -b output in bytes\n" +" -w output in halfwords (16bit)\n" +" -l output in words (32bit)\n" +" -x swap bytes at output\n" +"\n" +"Memory regions:\n" +"Memory regions can be specified in two different forms: start+size\n" +"or start-end, If is omitted it defaults to 0. If end is omitted it\n" +"defaults to the end of the device, except for interactive commands like md\n" +"and mw for which it defaults to 0x100.\n" +"Sizes can be specified as decimal, or if prefixed with 0x as hexadecimal.\n" +"an optional suffix of k, M or G is for kibibytes, Megabytes or Gigabytes,\n" +"respectively\n"; + + +BAREBOX_CMD_START(md) + .cmd = do_mem_md, + .usage = "memory display", + BAREBOX_CMD_HELP(cmd_md_help) +BAREBOX_CMD_END diff --git a/commands/mem.c b/commands/mem.c index 51aa04daa..7eb60afec 100644 --- a/commands/mem.c +++ b/commands/mem.c @@ -39,80 +39,11 @@ #define PRINTF(fmt,args...) #endif -#define RW_BUF_SIZE 4096 -static char *rw_buf; +char *mem_rw_buf; static char *DEVMEM = "/dev/mem"; -/* Memory Display - * - * Syntax: - * md{.b, .w, .l} {addr} {len} - */ -#define DISP_LINE_LEN 16 - -int memory_display(char *addr, loff_t offs, ulong nbytes, int size, int swab) -{ - ulong linebytes, i; - u_char *cp; - - /* Print the lines. - * - * We buffer all read data, so we can make sure data is read only - * once, and all accesses are with the specified bus width. - */ - do { - char linebuf[DISP_LINE_LEN]; - uint *uip = (uint *)linebuf; - ushort *usp = (ushort *)linebuf; - u_char *ucp = (u_char *)linebuf; - uint count = 52; - - printf("%08llx:", offs); - linebytes = (nbytes > DISP_LINE_LEN) ? DISP_LINE_LEN : nbytes; - - for (i = 0; i < linebytes; i += size) { - if (size == 4) { - u32 res; - res = (*uip++ = *((uint *)addr)); - if (swab) - res = __swab32(res); - count -= printf(" %08x", res); - } else if (size == 2) { - u16 res; - res = (*usp++ = *((ushort *)addr)); - if (swab) - res = __swab16(res); - count -= printf(" %04x", res); - } else { - count -= printf(" %02x", (*ucp++ = *((u_char *)addr))); - } - addr += size; - offs += size; - } - - while(count--) - putchar(' '); - - cp = (u_char *)linebuf; - for (i=0; i 0x7e)) - putchar('.'); - else - printf("%c", *cp); - cp++; - } - putchar('\n'); - nbytes -= linebytes; - if (ctrlc()) { - return -EINTR; - } - } while (nbytes > 0); - - return 0; -} - -static int open_and_lseek(const char *filename, int mode, loff_t pos) +int open_and_lseek(const char *filename, int mode, loff_t pos) { int fd, ret; @@ -135,7 +66,11 @@ static int open_and_lseek(const char *filename, int mode, loff_t pos) return fd; } -static int mem_parse_options(int argc, char *argv[], char *optstr, int *mode, +/* + * Common function for parsing options for the 'md', 'mw', 'memcpy', 'memcmp' + * commands. + */ +int mem_parse_options(int argc, char *argv[], char *optstr, int *mode, char **sourcefile, char **destfile, int *swab) { int opt; @@ -168,438 +103,6 @@ static int mem_parse_options(int argc, char *argv[], char *optstr, int *mode, return 0; } -static int do_mem_md(int argc, char *argv[]) -{ - loff_t start = 0, size = 0x100; - int r, now; - int ret = 0; - int fd; - char *filename = DEVMEM; - int mode = O_RWSIZE_4; - int swab = 0; - - if (argc < 2) - return COMMAND_ERROR_USAGE; - - if (mem_parse_options(argc, argv, "bwls:x", &mode, &filename, NULL, - &swab) < 0) - return 1; - - if (optind < argc) { - if (parse_area_spec(argv[optind], &start, &size)) { - printf("could not parse: %s\n", argv[optind]); - return 1; - } - if (size == ~0) - size = 0x100; - } - - fd = open_and_lseek(filename, mode | O_RDONLY, start); - if (fd < 0) - return 1; - - do { - now = min(size, (loff_t)RW_BUF_SIZE); - r = read(fd, rw_buf, now); - if (r < 0) { - perror("read"); - goto out; - } - if (!r) - goto out; - - if ((ret = memory_display(rw_buf, start, r, - mode >> O_RWSIZE_SHIFT, swab))) - goto out; - - start += r; - size -= r; - } while (size); - -out: - close(fd); - - return ret ? 1 : 0; -} - -static const __maybe_unused char cmd_md_help[] = -"Usage md [OPTIONS] \n" -"display (hexdump) a memory region.\n" -"options:\n" -" -s display file (default /dev/mem)\n" -" -b output in bytes\n" -" -w output in halfwords (16bit)\n" -" -l output in words (32bit)\n" -" -x swap bytes at output\n" -"\n" -"Memory regions:\n" -"Memory regions can be specified in two different forms: start+size\n" -"or start-end, If is omitted it defaults to 0. If end is omitted it\n" -"defaults to the end of the device, except for interactive commands like md\n" -"and mw for which it defaults to 0x100.\n" -"Sizes can be specified as decimal, or if prefixed with 0x as hexadecimal.\n" -"an optional suffix of k, M or G is for kibibytes, Megabytes or Gigabytes,\n" -"respectively\n"; - - -BAREBOX_CMD_START(md) - .cmd = do_mem_md, - .usage = "memory display", - BAREBOX_CMD_HELP(cmd_md_help) -BAREBOX_CMD_END - -static int do_mem_mw(int argc, char *argv[]) -{ - int ret = 0; - int fd; - char *filename = DEVMEM; - int mode = O_RWSIZE_4; - loff_t adr; - int swab = 0; - - if (mem_parse_options(argc, argv, "bwld:x", &mode, NULL, &filename, - &swab) < 0) - return 1; - - if (optind + 1 >= argc) - return COMMAND_ERROR_USAGE; - - adr = strtoull_suffix(argv[optind++], NULL, 0); - - fd = open_and_lseek(filename, mode | O_WRONLY, adr); - if (fd < 0) - return 1; - - while (optind < argc) { - u8 val8; - u16 val16; - u32 val32; - switch (mode) { - case O_RWSIZE_1: - val8 = simple_strtoul(argv[optind], NULL, 0); - ret = write(fd, &val8, 1); - break; - case O_RWSIZE_2: - val16 = simple_strtoul(argv[optind], NULL, 0); - if (swab) - val16 = __swab16(val16); - ret = write(fd, &val16, 2); - break; - case O_RWSIZE_4: - val32 = simple_strtoul(argv[optind], NULL, 0); - if (swab) - val32 = __swab32(val32); - ret = write(fd, &val32, 4); - break; - } - if (ret < 0) { - perror("write"); - break; - } - ret = 0; - optind++; - } - - close(fd); - - return ret ? 1 : 0; -} - -static const __maybe_unused char cmd_mw_help[] = -"Usage: mw [OPTIONS] \n" -"Write value(s) to the specifies region.\n" -"options:\n" -" -b, -w, -l use byte, halfword, or word accesses\n" -" -d write file (default /dev/mem)\n"; - -BAREBOX_CMD_START(mw) - .cmd = do_mem_mw, - .usage = "memory write (fill)", - BAREBOX_CMD_HELP(cmd_mw_help) -BAREBOX_CMD_END - -static int do_mem_cmp(int argc, char *argv[]) -{ - loff_t addr1, addr2, count = ~0; - int mode = O_RWSIZE_1; - char *sourcefile = DEVMEM; - char *destfile = DEVMEM; - int sourcefd, destfd; - char *rw_buf1; - int ret = 1; - int offset = 0; - struct stat statbuf; - - if (mem_parse_options(argc, argv, "bwls:d:", &mode, &sourcefile, - &destfile, NULL) < 0) - return 1; - - if (optind + 2 > argc) - return COMMAND_ERROR_USAGE; - - addr1 = strtoull_suffix(argv[optind], NULL, 0); - addr2 = strtoull_suffix(argv[optind + 1], NULL, 0); - - if (optind + 2 == argc) { - if (sourcefile == DEVMEM) { - printf("source and count not given\n"); - return 1; - } - if (stat(sourcefile, &statbuf)) { - perror("stat"); - return 1; - } - count = statbuf.st_size - addr1; - } else { - count = strtoull_suffix(argv[optind + 2], NULL, 0); - } - - sourcefd = open_and_lseek(sourcefile, mode | O_RDONLY, addr1); - if (sourcefd < 0) - return 1; - - destfd = open_and_lseek(destfile, mode | O_RDONLY, addr2); - if (destfd < 0) { - close(sourcefd); - return 1; - } - - rw_buf1 = xmalloc(RW_BUF_SIZE); - - while (count > 0) { - int now, r1, r2, i; - - now = min((loff_t)RW_BUF_SIZE, count); - - r1 = read(sourcefd, rw_buf, now); - if (r1 < 0) { - perror("read"); - goto out; - } - - r2 = read(destfd, rw_buf1, now); - if (r2 < 0) { - perror("read"); - goto out; - } - - if (r1 != now || r2 != now) { - printf("regions differ in size\n"); - goto out; - } - - for (i = 0; i < now; i++) { - if (rw_buf[i] != rw_buf1[i]) { - printf("files differ at offset %d\n", offset); - goto out; - } - offset++; - } - - count -= now; - } - - printf("OK\n"); - ret = 0; -out: - close(sourcefd); - close(destfd); - free(rw_buf1); - - return ret; -} - -static const __maybe_unused char cmd_memcmp_help[] = -"Usage: memcmp [OPTIONS] \n" -"\n" -"options:\n" -" -b, -w, -l use byte, halfword, or word accesses\n" -" -s source file (default /dev/mem)\n" -" -d destination file (default /dev/mem)\n" -"\n" -"Compare memory regions specified with addr1 and addr2\n" -"of size bytes. If source is a file count can\n" -"be left unspecified in which case the whole file is\n" -"compared\n"; - -BAREBOX_CMD_START(memcmp) - .cmd = do_mem_cmp, - .usage = "memory compare", - BAREBOX_CMD_HELP(cmd_memcmp_help) -BAREBOX_CMD_END - -static int do_mem_cp(int argc, char *argv[]) -{ - loff_t count, dest, src; - char *sourcefile = DEVMEM; - char *destfile = DEVMEM; - int sourcefd, destfd; - int mode = 0; - struct stat statbuf; - int ret = 0; - - if (mem_parse_options(argc, argv, "bwls:d:", &mode, &sourcefile, - &destfile, NULL) < 0) - return 1; - - if (optind + 2 > argc) - return COMMAND_ERROR_USAGE; - - src = strtoull_suffix(argv[optind], NULL, 0); - dest = strtoull_suffix(argv[optind + 1], NULL, 0); - - if (optind + 2 == argc) { - if (sourcefile == DEVMEM) { - printf("source and count not given\n"); - return 1; - } - if (stat(sourcefile, &statbuf)) { - perror("stat"); - return 1; - } - count = statbuf.st_size - src; - } else { - count = strtoull_suffix(argv[optind + 2], NULL, 0); - } - - sourcefd = open_and_lseek(sourcefile, mode | O_RDONLY, src); - if (sourcefd < 0) - return 1; - - destfd = open_and_lseek(destfile, O_WRONLY | O_CREAT | mode, dest); - if (destfd < 0) { - close(sourcefd); - return 1; - } - - while (count > 0) { - int now, r, w, tmp; - - now = min((loff_t)RW_BUF_SIZE, count); - - r = read(sourcefd, rw_buf, now); - if (r < 0) { - perror("read"); - goto out; - } - - if (!r) - break; - - tmp = 0; - now = r; - while (now) { - w = write(destfd, rw_buf + tmp, now); - if (w < 0) { - perror("write"); - goto out; - } - if (!w) - break; - - now -= w; - tmp += w; - } - - count -= r; - - if (ctrlc()) - goto out; - } - - if (count) { - printf("ran out of data\n"); - ret = 1; - } - -out: - close(sourcefd); - close(destfd); - - return ret; -} - -static const __maybe_unused char cmd_memcpy_help[] = -"Usage: memcpy [OPTIONS] \n" -"\n" -"options:\n" -" -b, -w, -l use byte, halfword, or word accesses\n" -" -s source file (default /dev/mem)\n" -" -d destination file (default /dev/mem)\n" -"\n" -"Copy memory at of bytes to \n"; - -BAREBOX_CMD_START(memcpy) - .cmd = do_mem_cp, - .usage = "memory copy", - BAREBOX_CMD_HELP(cmd_memcpy_help) -BAREBOX_CMD_END - -static int do_memset(int argc, char *argv[]) -{ - loff_t s, c, n; - int fd; - char *buf; - int mode = O_RWSIZE_1; - int ret = 1; - char *file = DEVMEM; - - if (mem_parse_options(argc, argv, "bwld:", &mode, NULL, &file, - NULL) < 0) - return 1; - - if (optind + 3 > argc) - return COMMAND_ERROR_USAGE; - - s = strtoull_suffix(argv[optind], NULL, 0); - c = strtoull_suffix(argv[optind + 1], NULL, 0); - n = strtoull_suffix(argv[optind + 2], NULL, 0); - - fd = open_and_lseek(file, mode | O_WRONLY, s); - if (fd < 0) - return 1; - - buf = xmalloc(RW_BUF_SIZE); - memset(buf, c, RW_BUF_SIZE); - - while (n > 0) { - int now; - - now = min((loff_t)RW_BUF_SIZE, n); - - ret = write(fd, buf, now); - if (ret < 0) { - perror("write"); - ret = 1; - goto out; - } - - n -= now; - } - - ret = 0; -out: - close(fd); - free(buf); - - return ret; -} - -static const __maybe_unused char cmd_memset_help[] = -"Usage: memset [OPTIONS] \n" -"\n" -"options:\n" -" -b, -w, -l use byte, halfword, or word accesses\n" -" -d destination file (default /dev/mem)\n" -"\n" -"Fill the first bytes at offset with byte \n"; - -BAREBOX_CMD_START(memset) - .cmd = do_memset, - .usage = "memory fill", - BAREBOX_CMD_HELP(cmd_memset_help) -BAREBOX_CMD_END - static struct file_operations memops = { .read = mem_read, .write = mem_write, @@ -631,16 +134,11 @@ static struct driver_d mem_drv = { static int mem_init(void) { - rw_buf = malloc(RW_BUF_SIZE); - if(!rw_buf) { - printf("%s: Out of memory\n", __FUNCTION__); - return -1; - } + mem_rw_buf = malloc(RW_BUF_SIZE); + if(!mem_rw_buf) + return -ENOMEM; add_mem_device("mem", 0, ~0, IORESOURCE_MEM_WRITEABLE); - platform_driver_register(&mem_drv); - - return 0; + return platform_driver_register(&mem_drv); } - device_initcall(mem_init); diff --git a/commands/memcmp.c b/commands/memcmp.c new file mode 100644 index 000000000..4a0386254 --- /dev/null +++ b/commands/memcmp.c @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2011 Sascha Hauer , Pengutronix + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +/* + * Memory Functions + * + * Copied from FADS ROM, Dan Malek (dmalek@jlc.net) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern char *mem_rw_buf; + +static char *devmem = "/dev/mem"; + +static int do_memcmp(int argc, char *argv[]) +{ + loff_t addr1, addr2, count = ~0; + int mode = O_RWSIZE_1; + char *sourcefile = devmem; + char *destfile = devmem; + int sourcefd, destfd; + char *rw_buf1; + int ret = 1; + int offset = 0; + struct stat statbuf; + + if (mem_parse_options(argc, argv, "bwls:d:", &mode, &sourcefile, + &destfile, NULL) < 0) + return 1; + + if (optind + 2 > argc) + return COMMAND_ERROR_USAGE; + + addr1 = strtoull_suffix(argv[optind], NULL, 0); + addr2 = strtoull_suffix(argv[optind + 1], NULL, 0); + + if (optind + 2 == argc) { + if (sourcefile == devmem) { + printf("source and count not given\n"); + return 1; + } + if (stat(sourcefile, &statbuf)) { + perror("stat"); + return 1; + } + count = statbuf.st_size - addr1; + } else { + count = strtoull_suffix(argv[optind + 2], NULL, 0); + } + + sourcefd = open_and_lseek(sourcefile, mode | O_RDONLY, addr1); + if (sourcefd < 0) + return 1; + + destfd = open_and_lseek(destfile, mode | O_RDONLY, addr2); + if (destfd < 0) { + close(sourcefd); + return 1; + } + + rw_buf1 = xmalloc(RW_BUF_SIZE); + + while (count > 0) { + int now, r1, r2, i; + + now = min((loff_t)RW_BUF_SIZE, count); + + r1 = read(sourcefd, mem_rw_buf, now); + if (r1 < 0) { + perror("read"); + goto out; + } + + r2 = read(destfd, rw_buf1, now); + if (r2 < 0) { + perror("read"); + goto out; + } + + if (r1 != now || r2 != now) { + printf("regions differ in size\n"); + goto out; + } + + for (i = 0; i < now; i++) { + if (mem_rw_buf[i] != rw_buf1[i]) { + printf("files differ at offset %d\n", offset); + goto out; + } + offset++; + } + + count -= now; + } + + printf("OK\n"); + ret = 0; +out: + close(sourcefd); + close(destfd); + free(rw_buf1); + + return ret; +} + +static const __maybe_unused char cmd_memcmp_help[] = +"Usage: memcmp [OPTIONS] \n" +"\n" +"options:\n" +" -b, -w, -l use byte, halfword, or word accesses\n" +" -s source file (default /dev/mem)\n" +" -d destination file (default /dev/mem)\n" +"\n" +"Compare memory regions specified with addr1 and addr2\n" +"of size bytes. If source is a file count can\n" +"be left unspecified in which case the whole file is\n" +"compared\n"; + +BAREBOX_CMD_START(memcmp) + .cmd = do_memcmp, + .usage = "memory compare", + BAREBOX_CMD_HELP(cmd_memcmp_help) +BAREBOX_CMD_END diff --git a/commands/memcpy.c b/commands/memcpy.c new file mode 100644 index 000000000..98f099f18 --- /dev/null +++ b/commands/memcpy.c @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2011 Sascha Hauer , Pengutronix + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +/* + * Memory Functions + * + * Copied from FADS ROM, Dan Malek (dmalek@jlc.net) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern char *mem_rw_buf; + +static char *devmem = "/dev/mem"; + +static int do_memcpy(int argc, char *argv[]) +{ + loff_t count, dest, src; + char *sourcefile = devmem; + char *destfile = devmem; + int sourcefd, destfd; + int mode = 0; + struct stat statbuf; + int ret = 0; + + if (mem_parse_options(argc, argv, "bwls:d:", &mode, &sourcefile, + &destfile, NULL) < 0) + return 1; + + if (optind + 2 > argc) + return COMMAND_ERROR_USAGE; + + src = strtoull_suffix(argv[optind], NULL, 0); + dest = strtoull_suffix(argv[optind + 1], NULL, 0); + + if (optind + 2 == argc) { + if (sourcefile == devmem) { + printf("source and count not given\n"); + return 1; + } + if (stat(sourcefile, &statbuf)) { + perror("stat"); + return 1; + } + count = statbuf.st_size - src; + } else { + count = strtoull_suffix(argv[optind + 2], NULL, 0); + } + + sourcefd = open_and_lseek(sourcefile, mode | O_RDONLY, src); + if (sourcefd < 0) + return 1; + + destfd = open_and_lseek(destfile, O_WRONLY | O_CREAT | mode, dest); + if (destfd < 0) { + close(sourcefd); + return 1; + } + + while (count > 0) { + int now, r, w, tmp; + + now = min((loff_t)RW_BUF_SIZE, count); + + r = read(sourcefd, mem_rw_buf, now); + if (r < 0) { + perror("read"); + goto out; + } + + if (!r) + break; + + tmp = 0; + now = r; + while (now) { + w = write(destfd, mem_rw_buf + tmp, now); + if (w < 0) { + perror("write"); + goto out; + } + if (!w) + break; + + now -= w; + tmp += w; + } + + count -= r; + + if (ctrlc()) + goto out; + } + + if (count) { + printf("ran out of data\n"); + ret = 1; + } + +out: + close(sourcefd); + close(destfd); + + return ret; +} + +static const __maybe_unused char cmd_memcpy_help[] = +"Usage: memcpy [OPTIONS] \n" +"\n" +"options:\n" +" -b, -w, -l use byte, halfword, or word accesses\n" +" -s source file (default /dev/mem)\n" +" -d destination file (default /dev/mem)\n" +"\n" +"Copy memory at of bytes to \n"; + +BAREBOX_CMD_START(memcpy) + .cmd = do_memcpy, + .usage = "memory copy", + BAREBOX_CMD_HELP(cmd_memcpy_help) +BAREBOX_CMD_END diff --git a/commands/memset.c b/commands/memset.c new file mode 100644 index 000000000..48e55bc68 --- /dev/null +++ b/commands/memset.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2011 Sascha Hauer , Pengutronix + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +/* + * Memory Functions + * + * Copied from FADS ROM, Dan Malek (dmalek@jlc.net) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern char *mem_rw_buf; + +static int do_memset(int argc, char *argv[]) +{ + loff_t s, c, n; + int fd; + char *buf; + int mode = O_RWSIZE_1; + int ret = 1; + char *file = "/dev/mem"; + + if (mem_parse_options(argc, argv, "bwld:", &mode, NULL, &file, + NULL) < 0) + return 1; + + if (optind + 3 > argc) + return COMMAND_ERROR_USAGE; + + s = strtoull_suffix(argv[optind], NULL, 0); + c = strtoull_suffix(argv[optind + 1], NULL, 0); + n = strtoull_suffix(argv[optind + 2], NULL, 0); + + fd = open_and_lseek(file, mode | O_WRONLY, s); + if (fd < 0) + return 1; + + buf = xmalloc(RW_BUF_SIZE); + memset(buf, c, RW_BUF_SIZE); + + while (n > 0) { + int now; + + now = min((loff_t)RW_BUF_SIZE, n); + + ret = write(fd, buf, now); + if (ret < 0) { + perror("write"); + ret = 1; + goto out; + } + + n -= now; + } + + ret = 0; +out: + close(fd); + free(buf); + + return ret; +} + +static const __maybe_unused char cmd_memset_help[] = +"Usage: memset [OPTIONS] \n" +"\n" +"options:\n" +" -b, -w, -l use byte, halfword, or word accesses\n" +" -d destination file (default /dev/mem)\n" +"\n" +"Fill the first bytes at offset with byte \n"; + +BAREBOX_CMD_START(memset) + .cmd = do_memset, + .usage = "memory fill", + BAREBOX_CMD_HELP(cmd_memset_help) +BAREBOX_CMD_END diff --git a/commands/mm.c b/commands/mm.c new file mode 100644 index 000000000..f51fd27cb --- /dev/null +++ b/commands/mm.c @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2013 Sascha Hauer , Pengutronix + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int do_mem_mm(int argc, char *argv[]) +{ + int ret = 0; + int fd; + char *filename = "/dev/mem"; + int mode = O_RWSIZE_4; + loff_t adr; + int swab = 0; + u8 val8; + u16 val16; + u32 val32; + u32 value, mask; + + if (mem_parse_options(argc, argv, "bwld:", &mode, NULL, &filename, + &swab) < 0) + return 1; + + if (optind + 2 >= argc) + return COMMAND_ERROR_USAGE; + + adr = strtoull_suffix(argv[optind++], NULL, 0); + value = simple_strtoul(argv[optind++], NULL, 0); + mask = simple_strtoul(argv[optind++], NULL, 0); + + fd = open_and_lseek(filename, mode | O_RDWR, adr); + if (fd < 0) + return 1; + + switch (mode) { + case O_RWSIZE_1: + ret = pread(fd, &val8, 1, adr); + if (ret < 0) + goto out_read; + val8 &= ~mask; + val8 |= (value & mask); + ret = pwrite(fd, &val8, 1, adr); + if (ret < 0) + goto out_write; + break; + case O_RWSIZE_2: + ret = pread(fd, &val16, 2, adr); + if (ret < 0) + goto out_read; + val16 &= ~mask; + val16 |= (value & mask); + ret = pwrite(fd, &val16, 2, adr); + if (ret < 0) + goto out_write; + break; + case O_RWSIZE_4: + if (ret < 0) + goto out_read; + ret = pread(fd, &val32, 4, adr); + val32 &= ~mask; + val32 |= (value & mask); + ret = pwrite(fd, &val32, 4, adr); + if (ret < 0) + goto out_write; + break; + } + + close(fd); + + return 0; + +out_read: + perror("read"); + close(fd); + return 1; + +out_write: + perror("write"); + close(fd); + return 1; +} + +static const __maybe_unused char cmd_mm_help[] = +"Usage: mm [OPTIONS] \n" +"set/clear bits specified with in to \n" +"options:\n" +" -b, -w, -l use byte, halfword, or word accesses\n" +" -d write file (default /dev/mem)\n"; + +BAREBOX_CMD_START(mm) + .cmd = do_mem_mm, + .usage = "memory modify write with mask", + BAREBOX_CMD_HELP(cmd_mm_help) +BAREBOX_CMD_END diff --git a/commands/mw.c b/commands/mw.c new file mode 100644 index 000000000..d7d73a8f4 --- /dev/null +++ b/commands/mw.c @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2011 Sascha Hauer , Pengutronix + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +/* + * Memory Functions + * + * Copied from FADS ROM, Dan Malek (dmalek@jlc.net) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int do_mem_mw(int argc, char *argv[]) +{ + int ret = 0; + int fd; + char *filename = "/dev/mem"; + int mode = O_RWSIZE_4; + loff_t adr; + int swab = 0; + + if (mem_parse_options(argc, argv, "bwld:x", &mode, NULL, &filename, + &swab) < 0) + return 1; + + if (optind + 1 >= argc) + return COMMAND_ERROR_USAGE; + + adr = strtoull_suffix(argv[optind++], NULL, 0); + + fd = open_and_lseek(filename, mode | O_WRONLY, adr); + if (fd < 0) + return 1; + + while (optind < argc) { + u8 val8; + u16 val16; + u32 val32; + switch (mode) { + case O_RWSIZE_1: + val8 = simple_strtoul(argv[optind], NULL, 0); + ret = write(fd, &val8, 1); + break; + case O_RWSIZE_2: + val16 = simple_strtoul(argv[optind], NULL, 0); + if (swab) + val16 = __swab16(val16); + ret = write(fd, &val16, 2); + break; + case O_RWSIZE_4: + val32 = simple_strtoul(argv[optind], NULL, 0); + if (swab) + val32 = __swab32(val32); + ret = write(fd, &val32, 4); + break; + } + if (ret < 0) { + perror("write"); + break; + } + ret = 0; + optind++; + } + + close(fd); + + return ret ? 1 : 0; +} + +static const __maybe_unused char cmd_mw_help[] = +"Usage: mw [OPTIONS] \n" +"Write value(s) to the specifies region.\n" +"options:\n" +" -b, -w, -l use byte, halfword, or word accesses\n" +" -d write file (default /dev/mem)\n"; + +BAREBOX_CMD_START(mw) + .cmd = do_mem_mw, + .usage = "memory write (fill)", + BAREBOX_CMD_HELP(cmd_mw_help) +BAREBOX_CMD_END diff --git a/common/Makefile b/common/Makefile index dcb07c271..94601728d 100644 --- a/common/Makefile +++ b/common/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_CMD_LOADS) += s_record.o obj-$(CONFIG_OFTREE) += oftree.o obj-y += memory.o +obj-y += memory_display.o obj-$(CONFIG_MALLOC_DLMALLOC) += dlmalloc.o obj-$(CONFIG_MALLOC_TLSF) += tlsf_malloc.o obj-$(CONFIG_MALLOC_TLSF) += tlsf.o diff --git a/common/memory_display.c b/common/memory_display.c new file mode 100644 index 000000000..eb188e1d7 --- /dev/null +++ b/common/memory_display.c @@ -0,0 +1,64 @@ +#include + +#define DISP_LINE_LEN 16 + +int memory_display(char *addr, loff_t offs, unsigned nbytes, int size, int swab) +{ + ulong linebytes, i; + u_char *cp; + + /* Print the lines. + * + * We buffer all read data, so we can make sure data is read only + * once, and all accesses are with the specified bus width. + */ + do { + char linebuf[DISP_LINE_LEN]; + uint32_t *uip = (uint *)linebuf; + uint16_t *usp = (ushort *)linebuf; + uint8_t *ucp = (u_char *)linebuf; + unsigned count = 52; + + printf("%08llx:", offs); + linebytes = (nbytes > DISP_LINE_LEN) ? DISP_LINE_LEN : nbytes; + + for (i = 0; i < linebytes; i += size) { + if (size == 4) { + u32 res; + res = (*uip++ = *((uint *)addr)); + if (swab) + res = __swab32(res); + count -= printf(" %08x", res); + } else if (size == 2) { + u16 res; + res = (*usp++ = *((ushort *)addr)); + if (swab) + res = __swab16(res); + count -= printf(" %04x", res); + } else { + count -= printf(" %02x", (*ucp++ = *((u_char *)addr))); + } + addr += size; + offs += size; + } + + while (count--) + putchar(' '); + + cp = (uint8_t *)linebuf; + for (i = 0; i < linebytes; i++) { + if ((*cp < 0x20) || (*cp > 0x7e)) + putchar('.'); + else + printf("%c", *cp); + cp++; + } + + putchar('\n'); + nbytes -= linebytes; + if (ctrlc()) + return -EINTR; + } while (nbytes > 0); + + return 0; +} diff --git a/include/common.h b/include/common.h index e559b94a7..59fcd35ac 100644 --- a/include/common.h +++ b/include/common.h @@ -219,7 +219,12 @@ int run_shell(void); #define PAGE_ALIGN(s) (((s) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)) #define PAGE_ALIGN_DOWN(x) ((x) & ~(PAGE_SIZE - 1)) -int memory_display(char *addr, loff_t offs, ulong nbytes, int size, int swab); +int memory_display(char *addr, loff_t offs, unsigned nbytes, int size, int swab); + +int mem_parse_options(int argc, char *argv[], char *optstr, int *mode, + char **sourcefile, char **destfile, int *swab); +int open_and_lseek(const char *filename, int mode, loff_t pos); +#define RW_BUF_SIZE (unsigned)4096 extern const char version_string[]; #ifdef CONFIG_BANNER diff --git a/lib/copy_file.c b/lib/copy_file.c index 484b2ca72..ab3d845a5 100644 --- a/lib/copy_file.c +++ b/lib/copy_file.c @@ -6,8 +6,6 @@ #include #include -#define RW_BUF_SIZE (ulong)4096 - /** * @param[in] src FIXME * @param[out] dst FIXME