This is an automated email from Gerrit.

Eric Hoffman ([email protected]) just uploaded a new patch set to Gerrit, 
which you can find at http://openocd.zylin.com/4224

-- gerrit

commit 28d856a607471e95d39815faf070b04143699bc0
Author: Eric Hoffman <[email protected]>
Date:   Mon Sep 11 12:07:43 2017 -0400

    mips32 - Handle PrAcc execution exceptions
    
    The PrAcc low-level routine now handle execution exceptions.
    
    Doing a simple thing as a memory read/write to an unmapped address
    will create an exception (nested debug exception).  Before the fix,
    when this occurred, this would leave the MIPS in a state in which
    the PrAcc execution handler would not recover, and, as a result,
    you would lose any further possibility to execute debug instructions
    on the target, including resuming the target.  So, basically, you
    would lose the target until it was hard-rebooted.
    
    The fix simply handle the possibiliy that an exception can occur
    while executing debug instructions (whatever the nature of the
    intruction queue is), recover gracefully and transparently, and
    report a new error type: ERROR_EXCEPTION.
    
    Plus, I added, to the 'md' and 'mw' CLI commands a proper error
    message if this is detected:
    
    > mwb 0 1
    Memory write exception
    
    > mdw 0
    Memory read exception!
    
    > mdw 0x80000000
    0x80000000: 00000001
    
    Change-Id: Ib1d47b622b20d8bc71adf2c2a9960e48c0202ed5
    Signed-off-by: Eric Hoffman <[email protected]>

diff --git a/src/helper/log.h b/src/helper/log.h
index 512bcc5..a3fdbcc 100644
--- a/src/helper/log.h
+++ b/src/helper/log.h
@@ -149,6 +149,7 @@ extern int debug_level;
  */
 #define ERROR_FAIL                                             (-4)
 #define ERROR_WAIT                                             (-5)
+#define ERROR_EXCEPTION                                        (-6)
 
 
 #endif /* OPENOCD_HELPER_LOG_H */
diff --git a/src/target/mips32_pracc.c b/src/target/mips32_pracc.c
index 790c8dc..d3b6d9d 100644
--- a/src/target/mips32_pracc.c
+++ b/src/target/mips32_pracc.c
@@ -172,6 +172,32 @@ int mips32_pracc_exec(struct mips_ejtag *ejtag_info, 
struct pracc_queue_info *ct
        bool pass = 0;                  /* to check the pass through pracc text 
after function code sent */
        int retval;
 
+       /* Ensure we are at text start.  Don't assume that the last run left us 
at
+          text start.  In fact that DOES occur in normal circumstances, and 
it's
+          not because of error in the previous caller's code.  This most 
usually
+          occur because of a read/write memory access exception, creating a 
nested
+          exception (execption occuring while already in debug mode), which 
jump
+          us back to text start while queuing our PrAcc stream.  And in turn,
+          those memory access exception usually occur because the GDB client 
sent
+          a request to our server part to read/write somewhere in memory that
+          does not exists (no mapped TLB), or which there's no write 
priviledge. */
+       retval = mips32_pracc_read_ctrl_addr(ejtag_info); /* update current pa 
info: control and address */
+       if (retval != ERROR_OK) {
+               LOG_ERROR("Unable to get pracc ctrl/addr");
+               return retval;
+       }
+
+       if ((ejtag_info->pa_ctrl & EJTAG_CTRL_PRNW) ||
+               (ejtag_info->pa_addr != MIPS32_PRACC_TEXT)) {
+               /* Unclean state.  Do a clean jump to to text start. */
+               LOG_DEBUG("Last operation did not return to dmseg text start, 
attempting to jump to it...");
+               retval = mips32_pracc_clean_text_jump(ejtag_info);
+               if (retval != ERROR_OK) {
+                       LOG_ERROR("Unable to jump to pracc text start");
+                       return retval;
+               }
+       }
+
        while (1) {
                if (restart) {
                        if (restart_count < 3) {                                
        /* max 3 restarts allowed */
@@ -223,21 +249,30 @@ int mips32_pracc_exec(struct mips_ejtag *ejtag_info, 
struct pracc_queue_info *ct
                         if (!final_check) {                    /* executing 
function code */
                                /* check address */
                                if (ejtag_info->pa_addr != (MIPS32_PRACC_TEXT + 
code_count * 4)) {
-                                       LOG_DEBUG("reading at unexpected 
address %" PRIx32 ", expected %x",
-                                                       ejtag_info->pa_addr, 
MIPS32_PRACC_TEXT + code_count * 4);
-
-                                       /* restart code execution only in some 
cases */
-                                       if (code_count == 1 && 
ejtag_info->pa_addr == MIPS32_PRACC_TEXT &&
-                                                                               
restart_count == 0) {
-                                               LOG_DEBUG("restarting, without 
clean jump");
-                                               restart_count++;
-                                               code_count = 0;
-                                               continue;
-                                       } else if (code_count < 2) {
-                                               restart = 1;
-                                               continue;
+                                       /* This can occur if the last 
instruction created an exception,
+                                          in which case the CPU create nested 
debug exception, and
+                                          jump back to pracc text start. */
+                                       if (ejtag_info->pa_addr == 
MIPS32_PRACC_TEXT) {
+                                               /* We can reasonably assume 
we've got an exception */
+                                               LOG_DEBUG("Exception during 
pracc execution");
+                                               retval = ERROR_EXCEPTION;
+                                       } else {
+                                               LOG_DEBUG("reading at 
unexpected address %" PRIx32 ", expected %x",
+                                                               
ejtag_info->pa_addr, MIPS32_PRACC_TEXT + code_count * 4);
+
+                                               /* restart code execution only 
in some cases */
+                                               if (code_count < 2) {   /* 
allow for restart */
+                                                       restart = 1;
+                                                       continue;
+                                               } else {
+                                                       retval = 
ERROR_JTAG_DEVICE_ERROR;
+                                               }
                                        }
-                                       return ERROR_JTAG_DEVICE_ERROR;
+                                       /* Unclean state.  Do a clean jump to 
to text start before we leave */
+                                       /* Do not check for error, return the 
error code we set above */
+                                       if 
(mips32_pracc_clean_text_jump(ejtag_info) != ERROR_OK)
+                                               LOG_ERROR("Unable to jump to 
dmseg text start");
+                                       return retval;
                                }
                                /* check for store instruction at dmseg */
                                uint32_t store_addr = 
ctx->pracc_list[code_count].addr;
@@ -353,6 +388,8 @@ inline void pracc_queue_free(struct pracc_queue_info *ctx)
 int mips32_pracc_queue_exec(struct mips_ejtag *ejtag_info, struct 
pracc_queue_info *ctx,
                                        uint32_t *buf, bool check_last)
 {
+       int retval = ERROR_OK;
+
        if (ctx->retval != ERROR_OK) {
                LOG_ERROR("Out of memory");
                return ERROR_FAIL;
@@ -365,6 +402,32 @@ int mips32_pracc_queue_exec(struct mips_ejtag *ejtag_info, 
struct pracc_queue_in
        if (ejtag_info->mode == 0)
                return mips32_pracc_exec(ejtag_info, ctx, buf, check_last);
 
+       /* Ensure we are at text start.  Don't assume that the last run left us 
at
+          text start.  In fact that DOES occur in normal circumstances, and 
it's
+          not because of error in the previous caller's code.  This most 
usually
+          occur because of a read/write memory access exception, creating a 
nested
+          exception (execption occuring while already in debug mode), which 
jump
+          us back to text start while queuing our PrAcc stream.  And in turn,
+          those memory access exception usually occur because the GDB client 
sent
+          a request to our server part to read/write somewhere in memory that
+          does not exists (no mapped TLB), or which there's no write 
priviledge. */
+       retval = mips32_pracc_read_ctrl_addr(ejtag_info); /* update current pa 
info: control and address */
+       if (retval != ERROR_OK) {
+               LOG_ERROR("Unable to get pracc ctrl/addr");
+               return retval;
+       }
+
+       if ((ejtag_info->pa_ctrl & EJTAG_CTRL_PRNW) ||
+               (ejtag_info->pa_addr != MIPS32_PRACC_TEXT)) {
+               /* Unclean state.  Do a clean jump to to text start. */
+               LOG_DEBUG("Last operation did not return to dmseg text start, 
attempting to jump to it...");
+               retval = mips32_pracc_clean_text_jump(ejtag_info);
+               if (retval != ERROR_OK) {
+                       LOG_ERROR("Unable to jump to pracc text start");
+                       return retval;
+               }
+       }
+
        union scan_in {
                uint8_t scan_96[12];
                struct {
@@ -398,7 +461,7 @@ int mips32_pracc_queue_exec(struct mips_ejtag *ejtag_info, 
struct pracc_queue_in
                }
        }
 
-       int retval = jtag_execute_queue();              /* execute queued scans 
*/
+       retval = jtag_execute_queue();          /* execute queued scans */
        if (retval != ERROR_OK)
                goto exit;
 
@@ -419,9 +482,22 @@ int mips32_pracc_queue_exec(struct mips_ejtag *ejtag_info, 
struct pracc_queue_in
                        goto exit;
                }
                if (addr != fetch_addr) {
-                       LOG_ERROR("Fetch addr mismatch, read: %" PRIx32 " 
expected: %" PRIx32 " count: %d",
-                                         addr, fetch_addr, scan_count);
-                       retval = ERROR_FAIL;
+                       /* This can occur if the last instruction created an 
exception,
+                          in which case the CPU create nested debug exception, 
and
+                          jump back to pracc text start. */
+                       if (addr == MIPS32_PRACC_TEXT) {
+                               /* We can reasonably assume we've got an 
exception */
+                               LOG_DEBUG("Exception during pracc execution");
+                               retval = ERROR_EXCEPTION;
+                       } else {
+                               LOG_ERROR("Fetch addr mismatch, read: %" PRIx32 
" expected: %" PRIx32 " count: %d",
+                                                 addr, fetch_addr, scan_count);
+                               retval = ERROR_FAIL;
+                       }
+                       /* Unclean state.  Do a clean jump to to text start. */
+                       /* Do not check for error, return the error code we set 
above */
+                       if (mips32_pracc_clean_text_jump(ejtag_info) != 
ERROR_OK)
+                               LOG_ERROR("Unable to jump to dmseg text start");
                        goto exit;
                }
                fetch_addr += 4;
diff --git a/src/target/target.c b/src/target/target.c
index 8f97666..8b8bfa7 100644
--- a/src/target/target.c
+++ b/src/target/target.c
@@ -3123,6 +3123,10 @@ COMMAND_HANDLER(handle_md_command)
        int retval = fn(target, address, size, count, buffer);
        if (ERROR_OK == retval)
                handle_md_output(CMD_CTX, target, address, size, count, buffer);
+       else {
+               if (ERROR_EXCEPTION == retval)
+                       command_print(CMD_CTX, "Memory read exception!");
+       }
 
        free(buffer);
 
@@ -3190,6 +3194,8 @@ static int target_fill_mem(struct target *target,
 
 COMMAND_HANDLER(handle_mw_command)
 {
+       int retval = ERROR_OK;
+
        if (CMD_ARGC < 2)
                return ERROR_COMMAND_SYNTAX_ERROR;
        bool physical = strcmp(CMD_ARGV[0], "phys") == 0;
@@ -3232,7 +3238,13 @@ COMMAND_HANDLER(handle_mw_command)
                        return ERROR_COMMAND_SYNTAX_ERROR;
        }
 
-       return target_fill_mem(target, address, fn, wordsize, value, count);
+       retval = target_fill_mem(target, address, fn, wordsize, value, count);
+       if (retval != ERROR_OK) {
+               if (ERROR_EXCEPTION == retval)
+                       command_print(CMD_CTX, "Memory write exception");
+       }
+
+       return retval;
 }
 
 static COMMAND_HELPER(parse_load_image_command_CMD_ARGV, struct image *image,

-- 

------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
OpenOCD-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/openocd-devel

Reply via email to