From d91b7772c48fa47bbd73857471e91a5d0cc8b876 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 17 Apr 2013 10:46:42 +0200 Subject: [PATCH 1/7] memory commands: export common functions The memory commands all use open_and_lseek and mem_parse_options. Export them to be able to split the memory commands into separate files. Signed-off-by: Sascha Hauer --- commands/mem.c | 8 ++++++-- include/common.h | 4 ++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/commands/mem.c b/commands/mem.c index 51aa04daa..f25c6b625 100644 --- a/commands/mem.c +++ b/commands/mem.c @@ -112,7 +112,7 @@ int memory_display(char *addr, loff_t offs, ulong nbytes, int size, int swab) 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 +135,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; diff --git a/include/common.h b/include/common.h index e559b94a7..2263c0068 100644 --- a/include/common.h +++ b/include/common.h @@ -221,6 +221,10 @@ int run_shell(void); int memory_display(char *addr, loff_t offs, ulong 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); + extern const char version_string[]; #ifdef CONFIG_BANNER void barebox_banner(void); From 255e5b4c4231ec381f87992109a15098ec00f8d6 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 17 Apr 2013 13:35:14 +0200 Subject: [PATCH 2/7] memory commands: move memory_display to separate file memory_display is a function which should generally be available. Currently it depends on memory command support being compiled in, so move the function to a separate file. Signed-off-by: Sascha Hauer --- commands/mem.c | 68 ----------------------------------------- common/Makefile | 1 + common/memory_display.c | 64 ++++++++++++++++++++++++++++++++++++++ include/common.h | 2 +- 4 files changed, 66 insertions(+), 69 deletions(-) create mode 100644 common/memory_display.c diff --git a/commands/mem.c b/commands/mem.c index f25c6b625..a4a16583c 100644 --- a/commands/mem.c +++ b/commands/mem.c @@ -44,74 +44,6 @@ static char *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; -} - int open_and_lseek(const char *filename, int mode, loff_t pos) { int fd, ret; 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 2263c0068..11904ab91 100644 --- a/include/common.h +++ b/include/common.h @@ -219,7 +219,7 @@ 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); From 4e3ce289731586e0374a57801f68ac69875ec9d8 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 17 Apr 2013 10:53:18 +0200 Subject: [PATCH 3/7] Use a common define for RW_BUF_SIZE Signed-off-by: Sascha Hauer --- commands/mem.c | 1 - include/common.h | 1 + lib/copy_file.c | 2 -- 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/commands/mem.c b/commands/mem.c index a4a16583c..d48f92ef1 100644 --- a/commands/mem.c +++ b/commands/mem.c @@ -39,7 +39,6 @@ #define PRINTF(fmt,args...) #endif -#define RW_BUF_SIZE 4096 static char *rw_buf; static char *DEVMEM = "/dev/mem"; diff --git a/include/common.h b/include/common.h index 11904ab91..59fcd35ac 100644 --- a/include/common.h +++ b/include/common.h @@ -224,6 +224,7 @@ 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 From c065be27a10746a338c54bf396ba5de2def56c31 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 17 Apr 2013 10:54:33 +0200 Subject: [PATCH 4/7] memory commands: cleanup initialization - return -ENOMEM instead of -1 - return the result of platform_driver_register Signed-off-by: Sascha Hauer --- commands/mem.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/commands/mem.c b/commands/mem.c index d48f92ef1..5bef3f763 100644 --- a/commands/mem.c +++ b/commands/mem.c @@ -567,15 +567,10 @@ 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; - } + if(!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); From 81c118aa9e2090d7bca7f164c6917ae2912d31ff Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 17 Apr 2013 10:58:33 +0200 Subject: [PATCH 5/7] memory commands: make rw_buf global The rw_buf is used by several memory commands. Make it global since we want to split the memory commands into separate files. Also rename it to mem_rw_buf. Signed-off-by: Sascha Hauer --- commands/mem.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/commands/mem.c b/commands/mem.c index 5bef3f763..a531bd5c0 100644 --- a/commands/mem.c +++ b/commands/mem.c @@ -39,7 +39,7 @@ #define PRINTF(fmt,args...) #endif -static char *rw_buf; +char *mem_rw_buf; static char *DEVMEM = "/dev/mem"; @@ -135,7 +135,7 @@ static int do_mem_md(int argc, char *argv[]) do { now = min(size, (loff_t)RW_BUF_SIZE); - r = read(fd, rw_buf, now); + r = read(fd, mem_rw_buf, now); if (r < 0) { perror("read"); goto out; @@ -143,7 +143,7 @@ static int do_mem_md(int argc, char *argv[]) if (!r) goto out; - if ((ret = memory_display(rw_buf, start, r, + if ((ret = memory_display(mem_rw_buf, start, r, mode >> O_RWSIZE_SHIFT, swab))) goto out; @@ -306,7 +306,7 @@ static int do_mem_cmp(int argc, char *argv[]) now = min((loff_t)RW_BUF_SIZE, count); - r1 = read(sourcefd, rw_buf, now); + r1 = read(sourcefd, mem_rw_buf, now); if (r1 < 0) { perror("read"); goto out; @@ -324,7 +324,7 @@ static int do_mem_cmp(int argc, char *argv[]) } for (i = 0; i < now; i++) { - if (rw_buf[i] != rw_buf1[i]) { + if (mem_rw_buf[i] != rw_buf1[i]) { printf("files differ at offset %d\n", offset); goto out; } @@ -412,7 +412,7 @@ static int do_mem_cp(int argc, char *argv[]) now = min((loff_t)RW_BUF_SIZE, count); - r = read(sourcefd, rw_buf, now); + r = read(sourcefd, mem_rw_buf, now); if (r < 0) { perror("read"); goto out; @@ -424,7 +424,7 @@ static int do_mem_cp(int argc, char *argv[]) tmp = 0; now = r; while (now) { - w = write(destfd, rw_buf + tmp, now); + w = write(destfd, mem_rw_buf + tmp, now); if (w < 0) { perror("write"); goto out; @@ -566,8 +566,8 @@ static struct driver_d mem_drv = { static int mem_init(void) { - rw_buf = malloc(RW_BUF_SIZE); - if(!rw_buf) + mem_rw_buf = malloc(RW_BUF_SIZE); + if(!mem_rw_buf) return -ENOMEM; add_mem_device("mem", 0, ~0, IORESOURCE_MEM_WRITEABLE); From e10c1845b2351099c2097fe29629983002b63a37 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 17 Apr 2013 11:10:43 +0200 Subject: [PATCH 6/7] memory commands: separate into one file per command Normally in commands we have one file per command which is named like the command itself. The memory commands are an exception to this. This patch changes this by separating the memory commands. This also has the effect that the memory commands can now be selected individually. Along the way we add some Kconfig help text for the commmands. Signed-off-by: Sascha Hauer --- commands/Kconfig | 42 ++++- commands/Makefile | 5 + commands/md.c | 116 +++++++++++++ commands/mem.c | 432 ---------------------------------------------- commands/memcmp.c | 148 ++++++++++++++++ commands/memcpy.c | 145 ++++++++++++++++ commands/memset.c | 101 +++++++++++ commands/mw.c | 104 +++++++++++ 8 files changed, 660 insertions(+), 433 deletions(-) create mode 100644 commands/md.c create mode 100644 commands/memcmp.c create mode 100644 commands/memcpy.c create mode 100644 commands/memset.c create mode 100644 commands/mw.c diff --git a/commands/Kconfig b/commands/Kconfig index 00627580e..fe171d858 100644 --- a/commands/Kconfig +++ b/commands/Kconfig @@ -303,7 +303,47 @@ 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_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..beec8e963 100644 --- a/commands/Makefile +++ b/commands/Makefile @@ -7,6 +7,11 @@ 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_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 a531bd5c0..7eb60afec 100644 --- a/commands/mem.c +++ b/commands/mem.c @@ -103,438 +103,6 @@ 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, 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 - -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, 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_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, 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_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, 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/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 From 67c6eeda9e5dea544cdeddb666f141c8467ab8d4 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 17 Apr 2013 11:13:55 +0200 Subject: [PATCH 7/7] Add memory modify command (mm) As of now we have no way to manipulate individual bits of registers on the command line. This introduces a memory modify command which allows this. It has the syntax: mm [OPTIONS] With [OPTIONS] being the usual memory command options (-b, -w, -l, -d ). Signed-off-by: Sascha Hauer --- commands/Kconfig | 8 ++++ commands/Makefile | 1 + commands/mm.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 126 insertions(+) create mode 100644 commands/mm.c diff --git a/commands/Kconfig b/commands/Kconfig index fe171d858..e6168cede 100644 --- a/commands/Kconfig +++ b/commands/Kconfig @@ -320,6 +320,14 @@ config CMD_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 diff --git a/commands/Makefile b/commands/Makefile index beec8e963..953ecc284 100644 --- a/commands/Makefile +++ b/commands/Makefile @@ -8,6 +8,7 @@ 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 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