target: add support for 64bit data in mem2array and array2mem 86/6286/5
authorJan Matyas <matyas@codasip.com>
Thu, 3 Jun 2021 14:26:37 +0000 (16:26 +0200)
committerAntonio Borneo <borneo.antonio@gmail.com>
Sat, 10 Jul 2021 14:31:38 +0000 (15:31 +0100)
- Added support for reading and writing 64-bit data items
  using TCL commands "mem2array" and "array2mem". Until now,
  data items only up to 32 bits were supportd.

- Cleaned up functions target_array2mem() and
  target_mem2array(), especially data types of variables
  and variable declarations (scope).

Change-Id: Ia0ba427804f8fd8d7568f12714ab36984d6d5e24
Signed-off-by: Jan Matyas <matyas@codasip.com>
Reviewed-on: http://openocd.zylin.com/6286
Tested-by: jenkins
Reviewed-by: Marc Schink <dev@zapb.de>
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
doc/openocd.texi
src/target/target.c

index daf0a6aa14f106a34166ad6752c6c0eb76e7947e..1eebe14254c375e52af47df10c9b67908efe0953 100644 (file)
@@ -4821,8 +4821,8 @@ They are not otherwise documented here.
 @deffn {Command} {$target_name array2mem} arrayname width address count
 @deffnx {Command} {$target_name mem2array} arrayname width address count
 These provide an efficient script-oriented interface to memory.
-The @code{array2mem} primitive writes bytes, halfwords, or words;
-while @code{mem2array} reads them.
+The @code{array2mem} primitive writes bytes, halfwords, words
+or double-words; while @code{mem2array} reads them.
 In both cases, the TCL side uses an array, and
 the target side uses raw memory.
 
@@ -4835,7 +4835,7 @@ and neither store nor return those values.
 
 @itemize
 @item @var{arrayname} ... is the name of an array variable
-@item @var{width} ... is 8/16/32 - indicating the memory access size
+@item @var{width} ... is 8/16/32/64 - indicating the memory access size
 @item @var{address} ... is the target memory address
 @item @var{count} ... is the number of elements to process
 @end itemize
index 6b53ebd98087a96fa6878b1e5e612656e2039ac4..3772f8e3ec3bdbc6147845c86d2b294d97b51715 100644 (file)
@@ -4372,7 +4372,7 @@ COMMAND_HANDLER(handle_profile_command)
        return retval;
 }
 
-static int new_int_array_element(Jim_Interp *interp, const char *varname, int idx, uint32_t val)
+static int new_u64_array_element(Jim_Interp *interp, const char *varname, int idx, uint64_t val)
 {
        char *namebuf;
        Jim_Obj *nameObjPtr, *valObjPtr;
@@ -4383,7 +4383,8 @@ static int new_int_array_element(Jim_Interp *interp, const char *varname, int id
                return JIM_ERR;
 
        nameObjPtr = Jim_NewStringObj(interp, namebuf, -1);
-       valObjPtr = Jim_NewIntObj(interp, val);
+       jim_wide wide_val = val;
+       valObjPtr = Jim_NewWideObj(interp, wide_val);
        if (!nameObjPtr || !valObjPtr) {
                free(namebuf);
                return JIM_ERR;
@@ -4418,68 +4419,65 @@ static int jim_mem2array(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 
 static int target_mem2array(Jim_Interp *interp, struct target *target, int argc, Jim_Obj *const *argv)
 {
-       long l;
-       jim_wide wide_addr;
-       uint32_t width;
-       int len;
-       target_addr_t addr;
-       uint32_t count;
-       uint32_t v;
-       const char *varname;
-       const char *phys;
-       bool is_phys;
-       int  n, e, retval;
-       uint32_t i;
+       int e;
 
-       /* argv[1] = name of array to receive the data
-        * argv[2] = desired width
-        * argv[3] = memory address
-        * argv[4] = count of times to read
+       /* argv[0] = name of array to receive the data
+        * argv[1] = desired element width in bits
+        * argv[2] = memory address
+        * argv[3] = count of times to read
+        * argv[4] = optional "phys"
         */
-
        if (argc < 4 || argc > 5) {
                Jim_WrongNumArgs(interp, 0, argv, "varname width addr nelems [phys]");
                return JIM_ERR;
        }
-       varname = Jim_GetString(argv[0], &len);
-       /* given "foo" get space for worse case "foo(%d)" .. add 20 */
 
+       /* Arg 0: Name of the array variable */
+       const char *varname = Jim_GetString(argv[0], NULL);
+
+       /* Arg 1: Bit width of one element */
+       long l;
        e = Jim_GetLong(interp, argv[1], &l);
-       width = l;
        if (e != JIM_OK)
                return e;
+       const unsigned int width_bits = l;
+
+       if (width_bits != 8 &&
+                       width_bits != 16 &&
+                       width_bits != 32 &&
+                       width_bits != 64) {
+               Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
+               Jim_AppendStrings(interp, Jim_GetResult(interp),
+                               "Invalid width param. Must be one of: 8, 16, 32 or 64.", NULL);
+               return JIM_ERR;
+       }
+       const unsigned int width = width_bits / 8;
 
+       /* Arg 2: Memory address */
+       jim_wide wide_addr;
        e = Jim_GetWide(interp, argv[2], &wide_addr);
-       addr = (target_addr_t)wide_addr;
        if (e != JIM_OK)
                return e;
+       target_addr_t addr = (target_addr_t)wide_addr;
+
+       /* Arg 3: Number of elements to read */
        e = Jim_GetLong(interp, argv[3], &l);
-       len = l;
        if (e != JIM_OK)
                return e;
-       is_phys = false;
+       size_t len = l;
+
+       /* Arg 4: phys */
+       bool is_phys = false;
        if (argc > 4) {
-               phys = Jim_GetString(argv[4], &n);
-               if (!strncmp(phys, "phys", n))
+               int str_len = 0;
+               const char *phys = Jim_GetString(argv[4], &str_len);
+               if (!strncmp(phys, "phys", str_len))
                        is_phys = true;
                else
                        return JIM_ERR;
        }
-       switch (width) {
-               case 8:
-                       width = 1;
-                       break;
-               case 16:
-                       width = 2;
-                       break;
-               case 32:
-                       width = 4;
-                       break;
-               default:
-                       Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
-                       Jim_AppendStrings(interp, Jim_GetResult(interp), "Invalid width param, must be 8/16/32", NULL);
-                       return JIM_ERR;
-       }
+
+       /* Argument checks */
        if (len == 0) {
                Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
                Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: zero width read?", NULL);
@@ -4490,17 +4488,18 @@ static int target_mem2array(Jim_Interp *interp, struct target *target, int argc,
                Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: addr + len - wraps to zero?", NULL);
                return JIM_ERR;
        }
-       /* absurd transfer size? */
        if (len > 65536) {
                Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
-               Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: absurd > 64K item request", NULL);
+               Jim_AppendStrings(interp, Jim_GetResult(interp),
+                               "mem2array: too large read request, exceeds 64K items", NULL);
                return JIM_ERR;
        }
 
        if ((width == 1) ||
                ((width == 2) && ((addr & 1) == 0)) ||
-               ((width == 4) && ((addr & 3) == 0))) {
-               /* all is well */
+               ((width == 4) && ((addr & 3) == 0)) ||
+               ((width == 8) && ((addr & 7) == 0))) {
+               /* alignment correct */
        } else {
                char buf[100];
                Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
@@ -4514,9 +4513,9 @@ static int target_mem2array(Jim_Interp *interp, struct target *target, int argc,
        /* Transfer loop */
 
        /* index counter */
-       n = 0;
+       size_t idx = 0;
 
-       size_t buffersize = 4096;
+       const size_t buffersize = 4096;
        uint8_t *buffer = malloc(buffersize);
        if (buffer == NULL)
                return JIM_ERR;
@@ -4525,29 +4524,31 @@ static int target_mem2array(Jim_Interp *interp, struct target *target, int argc,
        e = JIM_OK;
        while (len) {
                /* Slurp... in buffer size chunks */
+               const unsigned int max_chunk_len = buffersize / width;
+               const size_t chunk_len = MIN(len, max_chunk_len); /* in elements.. */
 
-               count = len; /* in objects.. */
-               if (count > (buffersize / width))
-                       count = (buffersize / width);
-
+               int retval;
                if (is_phys)
-                       retval = target_read_phys_memory(target, addr, width, count, buffer);
+                       retval = target_read_phys_memory(target, addr, width, chunk_len, buffer);
                else
-                       retval = target_read_memory(target, addr, width, count, buffer);
+                       retval = target_read_memory(target, addr, width, chunk_len, buffer);
                if (retval != ERROR_OK) {
                        /* BOO !*/
-                       LOG_ERROR("mem2array: Read @ " TARGET_ADDR_FMT ", w=%" PRIu32 ", cnt=%" PRIu32 ", failed",
+                       LOG_ERROR("mem2array: Read @ " TARGET_ADDR_FMT ", w=%u, cnt=%zu, failed",
                                          addr,
                                          width,
-                                         count);
+                                         chunk_len);
                        Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
                        Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: cannot read memory", NULL);
                        e = JIM_ERR;
                        break;
                } else {
-                       v = 0; /* shut up gcc */
-                       for (i = 0; i < count ; i++, n++) {
+                       for (size_t i = 0; i < chunk_len ; i++, idx++) {
+                               uint64_t v = 0;
                                switch (width) {
+                                       case 8:
+                                               v = target_buffer_get_u64(target, &buffer[i*width]);
+                                               break;
                                        case 4:
                                                v = target_buffer_get_u32(target, &buffer[i*width]);
                                                break;
@@ -4558,10 +4559,10 @@ static int target_mem2array(Jim_Interp *interp, struct target *target, int argc,
                                                v = buffer[i] & 0x0ff;
                                                break;
                                }
-                               new_int_array_element(interp, varname, n, v);
+                               new_u64_array_element(interp, varname, idx, v);
                        }
-                       len -= count;
-                       addr += count * width;
+                       len -= chunk_len;
+                       addr += chunk_len * width;
                }
        }
 
@@ -4572,33 +4573,28 @@ static int target_mem2array(Jim_Interp *interp, struct target *target, int argc,
        return e;
 }
 
-static int get_int_array_element(Jim_Interp *interp, const char *varname, int idx, uint32_t *val)
+static int get_u64_array_element(Jim_Interp *interp, const char *varname, size_t idx, uint64_t *val)
 {
-       char *namebuf;
-       Jim_Obj *nameObjPtr, *valObjPtr;
-       int result;
-       long l;
-
-       namebuf = alloc_printf("%s(%d)", varname, idx);
+       char *namebuf = alloc_printf("%s(%zu)", varname, idx);
        if (!namebuf)
                return JIM_ERR;
 
-       nameObjPtr = Jim_NewStringObj(interp, namebuf, -1);
+       Jim_Obj *nameObjPtr = Jim_NewStringObj(interp, namebuf, -1);
        if (!nameObjPtr) {
                free(namebuf);
                return JIM_ERR;
        }
 
        Jim_IncrRefCount(nameObjPtr);
-       valObjPtr = Jim_GetVariable(interp, nameObjPtr, JIM_ERRMSG);
+       Jim_Obj *valObjPtr = Jim_GetVariable(interp, nameObjPtr, JIM_ERRMSG);
        Jim_DecrRefCount(interp, nameObjPtr);
        free(namebuf);
        if (valObjPtr == NULL)
                return JIM_ERR;
 
-       result = Jim_GetLong(interp, valObjPtr, &l);
-       /* printf("%s(%d) => 0%08x\n", varname, idx, val); */
-       *val = l;
+       jim_wide wide_val;
+       int result = Jim_GetWide(interp, valObjPtr, &wide_val);
+       *val = wide_val;
        return result;
 }
 
@@ -4622,92 +4618,91 @@ static int jim_array2mem(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 static int target_array2mem(Jim_Interp *interp, struct target *target,
                int argc, Jim_Obj *const *argv)
 {
-       long l;
-       jim_wide wide_addr;
-       uint32_t width;
-       int len;
-       target_addr_t addr;
-       uint32_t count;
-       uint32_t v;
-       const char *varname;
-       const char *phys;
-       bool is_phys;
-       int  n, e, retval;
-       uint32_t i;
+       int e;
 
-       /* argv[1] = name of array to get the data
-        * argv[2] = desired width
-        * argv[3] = memory address
-        * argv[4] = count to write
+       /* argv[0] = name of array from which to read the data
+        * argv[1] = desired element width in bits
+        * argv[2] = memory address
+        * argv[3] = number of elements to write
+        * argv[4] = optional "phys"
         */
        if (argc < 4 || argc > 5) {
                Jim_WrongNumArgs(interp, 0, argv, "varname width addr nelems [phys]");
                return JIM_ERR;
        }
-       varname = Jim_GetString(argv[0], &len);
-       /* given "foo" get space for worse case "foo(%d)" .. add 20 */
 
+       /* Arg 0: Name of the array variable */
+       const char *varname = Jim_GetString(argv[0], NULL);
+
+       /* Arg 1: Bit width of one element */
+       long l;
        e = Jim_GetLong(interp, argv[1], &l);
-       width = l;
        if (e != JIM_OK)
                return e;
+       const unsigned int width_bits = l;
+
+       if (width_bits != 8 &&
+                       width_bits != 16 &&
+                       width_bits != 32 &&
+                       width_bits != 64) {
+               Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
+               Jim_AppendStrings(interp, Jim_GetResult(interp),
+                               "Invalid width param. Must be one of: 8, 16, 32 or 64.", NULL);
+               return JIM_ERR;
+       }
+       const unsigned int width = width_bits / 8;
 
+       /* Arg 2: Memory address */
+       jim_wide wide_addr;
        e = Jim_GetWide(interp, argv[2], &wide_addr);
-       addr = (target_addr_t)wide_addr;
        if (e != JIM_OK)
                return e;
+       target_addr_t addr = (target_addr_t)wide_addr;
+
+       /* Arg 3: Number of elements to write */
        e = Jim_GetLong(interp, argv[3], &l);
-       len = l;
        if (e != JIM_OK)
                return e;
-       is_phys = false;
+       size_t len = l;
+
+       /* Arg 4: Phys */
+       bool is_phys = false;
        if (argc > 4) {
-               phys = Jim_GetString(argv[4], &n);
-               if (!strncmp(phys, "phys", n))
+               int str_len = 0;
+               const char *phys = Jim_GetString(argv[4], &str_len);
+               if (!strncmp(phys, "phys", str_len))
                        is_phys = true;
                else
                        return JIM_ERR;
        }
-       switch (width) {
-               case 8:
-                       width = 1;
-                       break;
-               case 16:
-                       width = 2;
-                       break;
-               case 32:
-                       width = 4;
-                       break;
-               default:
-                       Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
-                       Jim_AppendStrings(interp, Jim_GetResult(interp),
-                                       "Invalid width param, must be 8/16/32", NULL);
-                       return JIM_ERR;
-       }
+
+       /* Argument checks */
        if (len == 0) {
                Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
                Jim_AppendStrings(interp, Jim_GetResult(interp),
                                "array2mem: zero width read?", NULL);
                return JIM_ERR;
        }
+
        if ((addr + (len * width)) < addr) {
                Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
                Jim_AppendStrings(interp, Jim_GetResult(interp),
                                "array2mem: addr + len - wraps to zero?", NULL);
                return JIM_ERR;
        }
-       /* absurd transfer size? */
+
        if (len > 65536) {
                Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
                Jim_AppendStrings(interp, Jim_GetResult(interp),
-                               "array2mem: absurd > 64K item request", NULL);
+                               "array2mem: too large memory write request, exceeds 64K items", NULL);
                return JIM_ERR;
        }
 
        if ((width == 1) ||
                ((width == 2) && ((addr & 1) == 0)) ||
-               ((width == 4) && ((addr & 3) == 0))) {
-               /* all is well */
+               ((width == 4) && ((addr & 3) == 0)) ||
+               ((width == 8) && ((addr & 7) == 0))) {
+               /* alignment correct */
        } else {
                char buf[100];
                Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
@@ -4720,27 +4715,34 @@ static int target_array2mem(Jim_Interp *interp, struct target *target,
 
        /* Transfer loop */
 
-       /* index counter */
-       n = 0;
        /* assume ok */
        e = JIM_OK;
 
-       size_t buffersize = 4096;
+       const size_t buffersize = 4096;
        uint8_t *buffer = malloc(buffersize);
        if (buffer == NULL)
                return JIM_ERR;
 
+       /* index counter */
+       size_t idx = 0;
+
        while (len) {
                /* Slurp... in buffer size chunks */
+               const unsigned int max_chunk_len = buffersize / width;
 
-               count = len; /* in objects.. */
-               if (count > (buffersize / width))
-                       count = (buffersize / width);
+               const size_t chunk_len = MIN(len, max_chunk_len); /* in elements.. */
 
-               v = 0; /* shut up gcc */
-               for (i = 0; i < count; i++, n++) {
-                       get_int_array_element(interp, varname, n, &v);
+               /* Fill the buffer */
+               for (size_t i = 0; i < chunk_len; i++, idx++) {
+                       uint64_t v = 0;
+                       if (get_u64_array_element(interp, varname, idx, &v) != JIM_OK) {
+                               free(buffer);
+                               return JIM_ERR;
+                       }
                        switch (width) {
+                       case 8:
+                               target_buffer_set_u64(target, &buffer[i * width], v);
+                               break;
                        case 4:
                                target_buffer_set_u32(target, &buffer[i * width], v);
                                break;
@@ -4752,24 +4754,26 @@ static int target_array2mem(Jim_Interp *interp, struct target *target,
                                break;
                        }
                }
-               len -= count;
+               len -= chunk_len;
 
+               /* Write the buffer to memory */
+               int retval;
                if (is_phys)
-                       retval = target_write_phys_memory(target, addr, width, count, buffer);
+                       retval = target_write_phys_memory(target, addr, width, chunk_len, buffer);
                else
-                       retval = target_write_memory(target, addr, width, count, buffer);
+                       retval = target_write_memory(target, addr, width, chunk_len, buffer);
                if (retval != ERROR_OK) {
                        /* BOO !*/
-                       LOG_ERROR("array2mem: Write @ " TARGET_ADDR_FMT ", w=%" PRIu32 ", cnt=%" PRIu32 ", failed",
+                       LOG_ERROR("array2mem: Write @ " TARGET_ADDR_FMT ", w=%u, cnt=%zu, failed",
                                          addr,
                                          width,
-                                         count);
+                                         chunk_len);
                        Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
                        Jim_AppendStrings(interp, Jim_GetResult(interp), "array2mem: cannot read memory", NULL);
                        e = JIM_ERR;
                        break;
                }
-               addr += count * width;
+               addr += chunk_len * width;
        }
 
        free(buffer);

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)