diff options
Diffstat (limited to 'sys/contrib/octeon-sdk/cvmx-debug.c')
-rw-r--r-- | sys/contrib/octeon-sdk/cvmx-debug.c | 534 |
1 files changed, 349 insertions, 185 deletions
diff --git a/sys/contrib/octeon-sdk/cvmx-debug.c b/sys/contrib/octeon-sdk/cvmx-debug.c index e615cbc..223f7eb 100644 --- a/sys/contrib/octeon-sdk/cvmx-debug.c +++ b/sys/contrib/octeon-sdk/cvmx-debug.c @@ -1,5 +1,5 @@ /***********************license start*************** - * Copyright (c) 2003-2010 Cavium Networks (support@cavium.com). All rights + * Copyright (c) 2003-2010 Cavium Inc. (support@cavium.com). All rights * reserved. * * @@ -15,7 +15,7 @@ * disclaimer in the documentation and/or other materials provided * with the distribution. - * * Neither the name of Cavium Networks nor the names of + * * Neither the name of Cavium Inc. nor the names of * its contributors may be used to endorse or promote products * derived from this software without specific prior written * permission. @@ -26,7 +26,7 @@ * countries. * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" - * AND WITH ALL FAULTS AND CAVIUM NETWORKS MAKES NO PROMISES, REPRESENTATIONS OR + * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM @@ -42,6 +42,9 @@ * @file * * Interface to debug exception handler + * NOTE: CARE SHOULD BE TAKE WHEN USING STD C LIBRARY FUNCTIONS IN + * THIS FILE IF SOMEONE PUTS A BREAKPOINT ON THOSE FUNCTIONS + * DEBUGGING WILL FAIL. * * <hr>$Revision: 50060 $<hr> */ @@ -56,21 +59,14 @@ #include <asm/octeon/octeon-boot-info.h> #else #include <stdint.h> -#include "executive-config.h" #include "cvmx.h" #include "cvmx-debug.h" #include "cvmx-bootmem.h" #include "cvmx-core.h" #include "cvmx-coremask.h" - -#ifndef __OCTEON_NEWLIB__ -#include "../../bootloader/u-boot/include/octeon_mem_map.h" -#else #include "octeon-boot-info.h" #endif -#endif - #ifdef CVMX_DEBUG_LOGGING # undef CVMX_DEBUG_LOGGING # define CVMX_DEBUG_LOGGING 1 @@ -119,33 +115,84 @@ volatile uint64_t __cvmx_debug_mode_exception_occured; static char cvmx_debug_stack[8*1024] __attribute ((aligned (16))); char *__cvmx_debug_stack_top = &cvmx_debug_stack[8*1024]; -#ifndef __OCTEON_NEWLIB__ +#ifndef CVMX_BUILD_FOR_TOOLCHAIN extern int cvmx_interrupt_in_isr; #else #define cvmx_interrupt_in_isr 0 #endif #else -uint64_t __cvmx_debug_save_regs_area_all[OCTEON_NUM_CORES][32]; +uint64_t __cvmx_debug_save_regs_area_all[CVMX_MAX_CORES][32]; #define __cvmx_debug_save_regs_area __cvmx_debug_save_regs_area_all[cvmx_get_core_num()] -volatile uint64_t __cvmx_debug_mode_exception_ignore_all[OCTEON_NUM_CORES]; +volatile uint64_t __cvmx_debug_mode_exception_ignore_all[CVMX_MAX_CORES]; #define __cvmx_debug_mode_exception_ignore __cvmx_debug_mode_exception_ignore_all[cvmx_get_core_num()] -volatile uint64_t __cvmx_debug_mode_exception_occured_all[OCTEON_NUM_CORES]; +volatile uint64_t __cvmx_debug_mode_exception_occured_all[CVMX_MAX_CORES]; #define __cvmx_debug_mode_exception_occured __cvmx_debug_mode_exception_occured_all[cvmx_get_core_num()] -static char cvmx_debug_stack_all[OCTEON_NUM_CORES][8*1024] __attribute ((aligned (16))); -char *__cvmx_debug_stack_top_all[OCTEON_NUM_CORES]; +static char cvmx_debug_stack_all[CVMX_MAX_CORES][8*1024] __attribute ((aligned (16))); +char *__cvmx_debug_stack_top_all[CVMX_MAX_CORES]; #define cvmx_interrupt_in_isr 0 #endif +static size_t cvmx_debug_strlen (const char *str) +{ + size_t size = 0; + while (*str) + { + size++; + str++; + } + return size; +} +static void cvmx_debug_strcpy (char *dest, const char *src) +{ + while (*src) + { + *dest = *src; + src++; + dest++; + } + *dest = 0; +} + +static void cvmx_debug_memcpy_align (void *dest, const void *src, int size) __attribute__ ((__noinline__)); +static void cvmx_debug_memcpy_align (void *dest, const void *src, int size) +{ + long long *dest1 = (long long*)dest; + const long long *src1 = (const long long*)src; + int i; + if (size == 40) + { + long long a0, a1, a2, a3, a4; + a0 = src1[0]; + a1 = src1[1]; + a2 = src1[2]; + a3 = src1[3]; + a4 = src1[4]; + dest1[0] = a0; + dest1[1] = a1; + dest1[2] = a2; + dest1[3] = a3; + dest1[4] = a4; + return; + } + for(i = 0;i < size;i+=8) + { + *dest1 = *src1; + dest1++; + src1++; + } +} + + static inline uint32_t cvmx_debug_core_mask(void) { #ifndef CVMX_BUILD_FOR_LINUX_KERNEL -#ifdef __OCTEON_NEWLIB__ +#ifdef CVMX_BUILD_FOR_TOOLCHAIN extern int __octeon_core_mask; return __octeon_core_mask; #endif @@ -157,13 +204,13 @@ return octeon_get_boot_coremask (); static inline void cvmx_debug_update_state(cvmx_debug_state_t state) { - memcpy(cvmx_debug_globals->state, &state, sizeof(cvmx_debug_state_t)); + cvmx_debug_memcpy_align(cvmx_debug_globals->state, &state, sizeof(cvmx_debug_state_t)); } static inline cvmx_debug_state_t cvmx_debug_get_state(void) { cvmx_debug_state_t state; - memcpy(&state, cvmx_debug_globals->state, sizeof(cvmx_debug_state_t)); + cvmx_debug_memcpy_align(&state, cvmx_debug_globals->state, sizeof(cvmx_debug_state_t)); return state; } @@ -201,53 +248,31 @@ static int cvmx_debug_enabled(void) return cvmx_debug_booted() || CVMX_DEBUG_ATTACH; } +static void cvmx_debug_init_global_ptr (void *ptr) +{ + uint64_t phys = cvmx_ptr_to_phys (ptr); + cvmx_debug_globals_t *p; + /* Since at this point, TLBs are not mapped 1 to 1, we should just use KSEG0 accesses. */ + p = CASTPTR(cvmx_debug_globals_t, CVMX_ADD_SEG32(CVMX_MIPS32_SPACE_KSEG0, phys)); + memset (p, 0, sizeof(cvmx_debug_globals_t)); + p->version = CVMX_DEBUG_GLOBALS_VERSION; + p->tlb_entries = cvmx_core_get_tlb_entries(); +} + static void cvmx_debug_init_globals(void) { - int toclear = 0; uint64_t phys; - void *a; + void *ptr; if (cvmx_debug_globals) return; + ptr = cvmx_bootmem_alloc_named_range_once(sizeof(cvmx_debug_globals_t), 0, /* KSEG0 max, 512MB=*/0/*1024*1024*512*/, 8, + CVMX_DEBUG_GLOBALS_BLOCK_NAME, cvmx_debug_init_global_ptr); + phys = cvmx_ptr_to_phys (ptr); - if (cvmx_get_core_num() != 0) - { - volatile size_t i; - /* Delay here just enough for the writing of the version. */ - for(i = 0; i < sizeof(cvmx_debug_globals_t)/2 + 8; i++) - ; - } - - a = cvmx_bootmem_alloc_named(sizeof(cvmx_debug_globals_t), 8, CVMX_DEBUG_GLOBALS_BLOCK_NAME); - if (a) - { - phys = cvmx_ptr_to_phys(a); - toclear = 1; - } - else - { - const cvmx_bootmem_named_block_desc_t *debug_globals_nblk; - debug_globals_nblk = cvmx_bootmem_find_named_block (CVMX_DEBUG_GLOBALS_BLOCK_NAME); - phys = debug_globals_nblk->base_addr; - } + /* Since TLBs are not always mapped 1 to 1, we should just use access via KSEG0. */ cvmx_debug_globals = CASTPTR(cvmx_debug_globals_t, CVMX_ADD_SEG32(CVMX_MIPS32_SPACE_KSEG0, phys)); cvmx_debug_printf("Debug named block at %p\n", cvmx_debug_globals); - if (toclear) - cvmx_debug_printf("Debug named block cleared\n"); - - if (toclear) - { - memset (cvmx_debug_globals, 0, sizeof(cvmx_debug_globals_t)); - cvmx_debug_globals->version = CVMX_DEBUG_GLOBALS_VERSION; - cvmx_debug_globals->tlb_entries = cvmx_core_get_tlb_entries(); - } - else - { - volatile size_t i; - /* Delay here just enough for the writing of the version. */ - for(i = 0; i < sizeof(cvmx_debug_globals_t) + 8; i++) - ; - } } @@ -265,7 +290,7 @@ static void cvmx_debug_globals_check_version(void) } static inline volatile cvmx_debug_core_context_t *cvmx_debug_core_context(void); -static inline void cvmx_debug_save_core_context(volatile cvmx_debug_core_context_t *context); +static inline void cvmx_debug_save_core_context(volatile cvmx_debug_core_context_t *context, uint64_t hi, uint64_t lo); void cvmx_debug_init(void) { @@ -295,9 +320,9 @@ void cvmx_debug_init(void) /* Install the debugger handler on the cores. */ { int core1 = 0; - for (core1 = 0; core1 < OCTEON_NUM_CORES; core1++) + for (core1 = 0; core1 < CVMX_MAX_CORES; core1++) { - if ((1<<core1) & coremask) + if ((1u<<core1) & coremask) cvmx_debug_install_handler(core1); } } @@ -315,8 +340,8 @@ void cvmx_debug_init(void) state.known_cores |= coremask; state.core_finished &= ~coremask; #else - state.known_cores |= (1 << core); - state.core_finished &= ~(1 << core); + state.known_cores |= (1u << core); + state.core_finished &= ~(1u << core); #endif cvmx_debug_update_state(state); cvmx_spinlock_unlock(lock); @@ -342,7 +367,7 @@ void cvmx_debug_init(void) #ifdef CVMX_BUILD_FOR_LINUX_KERNEL { int i; - for (i = 0; i < OCTEON_NUM_CORES; i++) + for (i = 0; i < CVMX_MAX_CORES; i++) __cvmx_debug_stack_top_all[i] = &cvmx_debug_stack_all[i][8*1024]; } #endif @@ -367,27 +392,34 @@ void cvmx_debug_init(void) } } -static int cvmx_debug_putpacket_noformat(char *packet); - -static __attribute__ ((format (printf, 1, 2))) int cvmx_debug_putpacket(char *format, ...) +static const char cvmx_debug_hexchar[] = "0123456789ABCDEF"; +/* Put the hex value of t into str. */ +static void cvmx_debug_int8_to_strhex(char *str, unsigned char t) { - va_list ap; - size_t n; - char packet[CVMX_DEBUG_MAX_RESPONSE_SIZE]; - - if (cvmx_debug_comms[cvmx_debug_globals->comm_type]->putpacket == NULL) - return 0; - - va_start(ap, format); - n = vsnprintf(packet, sizeof(packet), format, ap); - va_end(ap); + str[0] = cvmx_debug_hexchar[(t>>4)&0xf]; + str[1] = cvmx_debug_hexchar[t&0xF]; + str[2] = 0; +} - if (n >= sizeof(packet)) - { - cvmx_debug_printf("packet truncated (needed %d bytes): %s\n", (int)n, packet); - return 0; - } - return cvmx_debug_putpacket_noformat(packet); +static void cvmx_debug_int64_to_strhex(char *str, uint64_t t) +{ + str[0] = cvmx_debug_hexchar[(t>>60)&0xF]; + str[1] = cvmx_debug_hexchar[(t>>56)&0xF]; + str[2] = cvmx_debug_hexchar[(t>>52)&0xF]; + str[3] = cvmx_debug_hexchar[(t>>48)&0xF]; + str[4] = cvmx_debug_hexchar[(t>>44)&0xF]; + str[5] = cvmx_debug_hexchar[(t>>40)&0xF]; + str[6] = cvmx_debug_hexchar[(t>>36)&0xF]; + str[7] = cvmx_debug_hexchar[(t>>32)&0xF]; + str[8] = cvmx_debug_hexchar[(t>>28)&0xF]; + str[9] = cvmx_debug_hexchar[(t>>24)&0xF]; + str[10] = cvmx_debug_hexchar[(t>>20)&0xF]; + str[11] = cvmx_debug_hexchar[(t>>16)&0xF]; + str[12] = cvmx_debug_hexchar[(t>>12)&0xF]; + str[13] = cvmx_debug_hexchar[(t>>8)&0xF]; + str[14] = cvmx_debug_hexchar[(t>>4)&0xF]; + str[15] = cvmx_debug_hexchar[(t>>0)&0xF]; + str[16] = 0; } static int cvmx_debug_putpacket_noformat(char *packet) @@ -398,9 +430,50 @@ static int cvmx_debug_putpacket_noformat(char *packet) return cvmx_debug_comms[cvmx_debug_globals->comm_type]->putpacket(packet); } -static int cvmx_debug_active_core(cvmx_debug_state_t state, int core) +static int cvmx_debug_putcorepacket(char *buf, int core) { - return state.active_cores & (1 << core); + char *tmp = "!Core XX "; + int tmpsize = cvmx_debug_strlen(tmp); + int bufsize = cvmx_debug_strlen(buf); + char *packet = __builtin_alloca(tmpsize + bufsize + 1); + cvmx_debug_strcpy(packet, tmp); + cvmx_debug_strcpy(&packet[tmpsize], buf); + if (core < 10) + { + packet[6] = ' '; + packet[7] = core + '0'; + } + else if (core < 20) + { + packet[6] = '1'; + packet[7] = core - 10 + '0'; + } + else if (core < 30) + { + packet[6] = '2'; + packet[7] = core - 20 + '0'; + } + else + { + packet[6] = '3'; + packet[7] = core - 30 + '0'; + } + return cvmx_debug_putpacket_noformat(packet); +} + +/* Put a buf followed by an integer formated as a hex. */ +static int cvmx_debug_putpacket_hexint(char *buf, uint64_t value) +{ + size_t size = cvmx_debug_strlen(buf); + char *packet = __builtin_alloca(size + 16 + 1); + cvmx_debug_strcpy(packet, buf); + cvmx_debug_int64_to_strhex(&packet[size], value); + return cvmx_debug_putpacket_noformat(packet); +} + +static int cvmx_debug_active_core(cvmx_debug_state_t state, unsigned core) +{ + return state.active_cores & (1u << core); } static volatile cvmx_debug_core_context_t *cvmx_debug_core_context(void) @@ -470,22 +543,59 @@ static int cvmx_debug_probe_store(unsigned char *ptr) return ok; } -/* Put the hex value of t into str. */ -static void strhex(char *str, unsigned char t) + +/** + * Routines to handle hex data + * + * @param ch + * @return + */ +static inline int cvmx_debug_hex(char ch) { - char a[] = "0123456789ABCDEF"; - str[0] = a[(t>>4)]; - str[1] = a[t&0xF]; - str[2] = 0; + if ((ch >= 'a') && (ch <= 'f')) + return(ch - 'a' + 10); + if ((ch >= '0') && (ch <= '9')) + return(ch - '0'); + if ((ch >= 'A') && (ch <= 'F')) + return(ch - 'A' + 10); + return(-1); +} + +/** + * While we find nice hex chars, build an int. + * Return number of chars processed. + * + * @param ptr + * @param intValue + * @return + */ +static int cvmx_debug_hexToLong(const char **ptr, uint64_t *intValue) +{ + int numChars = 0; + long hexValue; + + *intValue = 0; + while (**ptr) + { + hexValue = cvmx_debug_hex(**ptr); + if (hexValue < 0) + break; + + *intValue = (*intValue << 4) | hexValue; + numChars ++; + + (*ptr)++; + } + + return(numChars); } /** * Initialize the performance counter control registers. * */ -static void cvmx_debug_set_perf_control_reg (int perf_event, int perf_counter) +static void cvmx_debug_set_perf_control_reg (volatile cvmx_debug_core_context_t *context, int perf_event, int perf_counter) { - volatile cvmx_debug_core_context_t *context = cvmx_debug_core_context(); cvmx_core_perf_control_t control; control.u32 = 0; @@ -500,7 +610,7 @@ static void cvmx_debug_set_perf_control_reg (int perf_event, int perf_counter) context->cop0.perfctrl[perf_counter] = control.u32; } -static cvmx_debug_command_t cvmx_debug_process_packet(char *packet) +static cvmx_debug_command_t cvmx_debug_process_packet(const char *packet) { const char *buf = packet; cvmx_debug_command_t result = COMMAND_NOP; @@ -519,18 +629,20 @@ static cvmx_debug_command_t cvmx_debug_process_packet(char *packet) case 'F': /* Change the focus core */ { - int core; - sscanf(buf, "%x", &core); - + uint64_t core; + if (!cvmx_debug_hexToLong(&buf, &core)) + { + cvmx_debug_putpacket_noformat("!Uknown core. Focus not changed."); + } /* Only cores in the exception handler may become the focus. - If a core not in the exception handler got focus the - debugger would hang since nobody would talk to it. */ - if (state.handler_cores & (1 << core)) + If a core not in the exception handler got focus the + debugger would hang since nobody would talk to it. */ + else if (state.handler_cores & (1u << core)) { /* Focus change reply must be sent before the focus - changes. Otherwise the new focus core will eat our ACK - from the debugger. */ - cvmx_debug_putpacket("F%02x", core); + changes. Otherwise the new focus core will eat our ACK + from the debugger. */ + cvmx_debug_putpacket_hexint("F", core); cvmx_debug_comms[cvmx_debug_globals->comm_type]->change_core(state.focus_core, core); state.focus_core = core; cvmx_debug_update_state(state); @@ -542,7 +654,7 @@ static cvmx_debug_command_t cvmx_debug_process_packet(char *packet) } /* fall through */ case 'f': /* Get the focus core */ - cvmx_debug_putpacket("F%02x", (unsigned)state.focus_core); + cvmx_debug_putpacket_hexint("F", state.focus_core); break; case 'J': /* Set the flag for skip-over-isr in Single-Stepping mode */ @@ -557,14 +669,15 @@ static cvmx_debug_command_t cvmx_debug_process_packet(char *packet) same as the get step-isr command */ case 'j': /* Reply with step_isr status */ - cvmx_debug_putpacket("J%x", (unsigned)state.step_isr); + cvmx_debug_putpacket_hexint("J", (unsigned)state.step_isr); break; case 'I': /* Set the active cores */ { - long long active_cores; - sscanf(buf, "%llx", &active_cores); + uint64_t active_cores; + if (!cvmx_debug_hexToLong(&buf, &active_cores)) + active_cores = 0; /* Limit the active mask to the known to exist cores */ state.active_cores = active_cores & state.known_cores; @@ -573,10 +686,10 @@ static cvmx_debug_command_t cvmx_debug_process_packet(char *packet) state.active_cores = state.known_cores; /* The focus core must be in the active_cores mask */ - if ((state.active_cores & (1 << state.focus_core)) == 0) + if ((state.active_cores & (1u << state.focus_core)) == 0) { cvmx_debug_putpacket_noformat("!Focus core was added to the masked."); - state.active_cores |= 1 << state.focus_core; + state.active_cores |= 1u << state.focus_core; } cvmx_debug_update_state(state); @@ -585,7 +698,7 @@ static cvmx_debug_command_t cvmx_debug_process_packet(char *packet) same as the get active cores command */ case 'i': /* Get the active cores */ - cvmx_debug_putpacket("I%llx", (long long) state.active_cores); + cvmx_debug_putpacket_hexint("I", state.active_cores); break; case 'A': /* Setting the step mode all or one */ @@ -600,34 +713,46 @@ static cvmx_debug_command_t cvmx_debug_process_packet(char *packet) same as the get step-all command */ case 'a': /* Getting the current step mode */ - cvmx_debug_putpacket("A%x", (unsigned)state.step_all); + cvmx_debug_putpacket_hexint("A", state.step_all); break; case 'g': /* read a register from global place. */ { volatile cvmx_debug_core_context_t *context = cvmx_debug_core_context(); - int regno; + uint64_t regno; volatile uint64_t *reg; /* Get the register number to read */ - sscanf(buf, "%x", ®no); + if (!cvmx_debug_hexToLong(&buf, ®no)) + { + cvmx_debug_printf("Register number cannot be read.\n"); + cvmx_debug_putpacket_hexint("", 0xDEADBEEF); + break; + } reg = cvmx_debug_regnum_to_context_ref(regno, context); if (!reg) - cvmx_debug_printf("Register #%d is not valid\n", regno); - cvmx_debug_putpacket("%llx", (unsigned long long) *reg); + { + cvmx_debug_printf("Register #%d is not valid\n", (int)regno); + cvmx_debug_putpacket_hexint("", 0xDEADBEEF); + break; + } + cvmx_debug_putpacket_hexint("", *reg); } break; case 'G': /* set the value of a register. */ { volatile cvmx_debug_core_context_t *context = cvmx_debug_core_context(); - int regno; + uint64_t regno; volatile uint64_t *reg; - long long value; + uint64_t value; - /* Get the register number to read */ - if (sscanf(buf, "%x,%llx", ®no, &value) != 2) + /* Get the register number to write. It should be followed by + a comma */ + if (!cvmx_debug_hexToLong(&buf, ®no) + || (*buf++ != ',') + || !cvmx_debug_hexToLong(&buf, &value)) { cvmx_debug_printf("G packet corrupt: %s\n", buf); goto error_packet; @@ -636,7 +761,7 @@ static cvmx_debug_command_t cvmx_debug_process_packet(char *packet) reg = cvmx_debug_regnum_to_context_ref(regno, context); if (!reg) { - cvmx_debug_printf("Register #%d is not valid\n", regno); + cvmx_debug_printf("Register #%d is not valid\n", (int)regno); goto error_packet; } *reg = value; @@ -645,18 +770,21 @@ static cvmx_debug_command_t cvmx_debug_process_packet(char *packet) case 'm': /* Memory read. mAA..AA,LLLL Read LLLL bytes at address AA..AA */ { - long long addr, i, length; + uint64_t addr, i, length; unsigned char *ptr; char *reply; - if (sscanf(buf, "%llx,%llx", &addr, &length) != 2) + /* Get the memory address, a comma, and the length */ + if (!cvmx_debug_hexToLong(&buf, &addr) + || (*buf++ != ',') + || !cvmx_debug_hexToLong(&buf, &length)) { cvmx_debug_printf("m packet corrupt: %s\n", buf); goto error_packet; } if (length >= 1024) { - cvmx_debug_printf("m packet length out of range: %lld\n", length); + cvmx_debug_printf("m packet length out of range: %lld\n", (long long)length); goto error_packet; } @@ -668,7 +796,7 @@ static cvmx_debug_command_t cvmx_debug_process_packet(char *packet) unsigned char t; if (!cvmx_debug_probe_load(&ptr[i], &t)) goto error_packet; - strhex(&reply[i * 2], t); + cvmx_debug_int8_to_strhex(&reply[i * 2], t); } cvmx_debug_putpacket_noformat(reply); } @@ -676,28 +804,31 @@ static cvmx_debug_command_t cvmx_debug_process_packet(char *packet) case 'M': /* Memory write. MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */ { - long long addr, i, length; + uint64_t addr, i, length; unsigned char *ptr; - char value[1024]; - if (sscanf(buf, "%llx,%llx:%1024s", &addr, &length, value) != 3) + if (!cvmx_debug_hexToLong(&buf, &addr) + || *buf++ != ',' + || !cvmx_debug_hexToLong(&buf, &length) + || *buf++ != ':') { cvmx_debug_printf("M packet corrupt: %s\n", buf); goto error_packet; } - + ptr = (unsigned char *)(long)addr; for (i = 0; i < length; i++) { - int c; - int n; - char tempstr[3] = {0, 0, 0}; - memcpy (tempstr, &value[i * 2], 2); + int n, n1; + unsigned char c; + + n = cvmx_debug_hex(buf[i * 2]); + n1 = cvmx_debug_hex(buf[i * 2 + 1]); + c = (n << 4) | n1; - n = sscanf(tempstr, "%2x", &c); - if (n != 1) + if (n == -1 || n1 == -1) { - cvmx_debug_printf("M packet corrupt: %s\n", &value[i * 2]); + cvmx_debug_printf("M packet corrupt: %s\n", &buf[i * 2]); goto error_packet; } /* Probe memory. If not accessible fail. */ @@ -716,30 +847,38 @@ static cvmx_debug_command_t cvmx_debug_process_packet(char *packet) is the performance counter to set X is the performance event. [34] is to get the same thing. */ { - int perf_event = 0; - int counter, encoded_counter; + uint64_t perf_event = 0; + char encoded_counter = *buf++; + uint64_t counter; volatile cvmx_debug_core_context_t *context = cvmx_debug_core_context(); - sscanf(buf, "%1d%x", &encoded_counter, &perf_event); + + /* Ignore errors from the packet. */ + cvmx_debug_hexToLong(&buf, &perf_event); switch (encoded_counter) { - case 1: /* Set performance counter0 event. */ - case 2: /* Set performance counter1 event. */ + case '1': /* Set performance counter0 event. */ + case '2': /* Set performance counter1 event. */ - counter = encoded_counter - 1; + counter = encoded_counter - '1'; context->cop0.perfval[counter] = 0; - cvmx_debug_set_perf_control_reg(perf_event, counter); + cvmx_debug_set_perf_control_reg(context, perf_event, counter); break; - case 3: /* Get performance counter0 event. */ - case 4: /* Get performance counter1 event. */ + case '3': /* Get performance counter0 event. */ + case '4': /* Get performance counter1 event. */ { cvmx_core_perf_control_t c; - counter = encoded_counter - 3; + char outpacket[16*2 +2]; + counter = encoded_counter - '3'; /* Pass performance counter0 event and counter to the debugger. */ c.u32 = context->cop0.perfctrl[counter]; - cvmx_debug_putpacket("%llx,%llx", (long long) context->cop0.perfval[counter], (long long) c.s.event); + cvmx_debug_int64_to_strhex(outpacket, context->cop0.perfval[counter]); + outpacket[16] = ','; + cvmx_debug_int64_to_strhex(&outpacket[17], c.s.event); + outpacket[33] = 0; + cvmx_debug_putpacket_noformat(outpacket); } break; } @@ -782,21 +921,27 @@ static cvmx_debug_command_t cvmx_debug_process_packet(char *packet) WP_ACCESS = 3 }; - int num, size; - long long addr; - enum type type; - char bp_type; + uint64_t num, size; + uint64_t addr; + uint64_t type; + char bp_type = *buf++; const int BE = 1, TE = 4; - int n; volatile cvmx_debug_core_context_t *context = cvmx_debug_core_context(); - n = sscanf(buf, "%c%x,%llx,%x,%x", &bp_type, &num, &addr, &size, &type); + if (!cvmx_debug_hexToLong(&buf, &num) + || *buf++ != ',' + || !cvmx_debug_hexToLong(&buf, &addr)) + { + cvmx_debug_printf("Z packet corrupt: %s\n", &packet[1]); + goto error_packet; + } + switch (bp_type) { case 'i': // Instruction hardware breakpoint - if (n != 3 || num > 4) + if (num > 4) { - cvmx_debug_printf("Z packet corrupt: %s\n", buf); + cvmx_debug_printf("Z packet corrupt: %s\n", &packet[1]); goto error_packet; } @@ -810,9 +955,15 @@ static cvmx_debug_command_t cvmx_debug_process_packet(char *packet) { uint64_t dbc = 0xff0 | BE | TE; uint64_t dbm; - if (n != 5 || num > 4) + if (num > 4 + || *buf++ != ',' + || !cvmx_debug_hexToLong(&buf, &size) + || *buf++ != ',' + || !cvmx_debug_hexToLong(&buf, &type) + || type > WP_ACCESS + || type < WP_LOAD) { - cvmx_debug_printf("Z packet corrupt: %s\n", buf); + cvmx_debug_printf("Z packet corrupt: %s\n", &packet[1]); goto error_packet; } @@ -831,7 +982,7 @@ static cvmx_debug_command_t cvmx_debug_process_packet(char *packet) break; } default: - cvmx_debug_printf("z packet corrupt: %s\n", buf); + cvmx_debug_printf("Z packet corrupt: %s\n", &packet[1]); goto error_packet; } } @@ -840,11 +991,11 @@ static cvmx_debug_command_t cvmx_debug_process_packet(char *packet) case 'z': /* Remove hardware breakpoint: z[di]NN..N remove NN..Nth breakpoint. */ { - int num; - char bp_type; + uint64_t num; + char bp_type = *buf++; volatile cvmx_debug_core_context_t *context = cvmx_debug_core_context(); - if (sscanf(buf, "%c%x", &bp_type, &num) != 2 || num > 4) + if (!cvmx_debug_hexToLong(&buf, &num) || num > 4) { cvmx_debug_printf("z packet corrupt: %s\n", buf); goto error_packet; @@ -919,7 +1070,7 @@ static int cvmx_debug_stop_core(cvmx_debug_state_t state, unsigned core, cvmx_de cvmx_debug_printf("Core #%d not in active cores, continuing.\n", core); return 0; } - if ((state.core_finished & (1<<core)) && proxy) + if ((state.core_finished & (1u<<core)) && proxy) return 0; return 1; } @@ -936,7 +1087,7 @@ static int cvmx_debug_single_step_exc(cvmx_debug_register_t *debug_reg) static void cvmx_debug_set_focus_core(cvmx_debug_state_t *state, int core) { if (state->ever_been_in_debug) - cvmx_debug_putpacket("!Core %2x taking focus.", core); + cvmx_debug_putcorepacket("taking focus.", core); cvmx_debug_comms[cvmx_debug_globals->comm_type]->change_core (state->focus_core, core); state->focus_core = core; } @@ -944,7 +1095,7 @@ static void cvmx_debug_set_focus_core(cvmx_debug_state_t *state, int core) static void cvmx_debug_may_elect_as_focus_core(cvmx_debug_state_t *state, int core, cvmx_debug_register_t *debug_reg) { /* If another core has already elected itself as the focus core, we're late. */ - if (state->handler_cores & (1 << state->focus_core)) + if (state->handler_cores & (1u << state->focus_core)) return; /* If we hit a breakpoint, elect ourselves. */ @@ -954,7 +1105,7 @@ static void cvmx_debug_may_elect_as_focus_core(cvmx_debug_state_t *state, int co /* It is possible the focus core has completed processing and exited the program. When this happens the focus core will not be in known_cores. If this is the case we need to elect a new focus. */ - if ((state->known_cores & (1 << state->focus_core)) == 0) + if ((state->known_cores & (1u << state->focus_core)) == 0) cvmx_debug_set_focus_core(state, core); } @@ -962,7 +1113,7 @@ static void cvmx_debug_send_stop_reason(cvmx_debug_register_t *debug_reg, volati { /* Handle Debug Data Breakpoint Store/Load Exception. */ if (debug_reg->s.ddbs || debug_reg->s.ddbl) - cvmx_debug_putpacket("T8:%x", (int) context->hw_dbp.status); + cvmx_debug_putpacket_hexint("T8:", (int) context->hw_dbp.status); else cvmx_debug_putpacket_noformat("T9"); } @@ -980,10 +1131,12 @@ static void cvmx_debug_clear_status(volatile cvmx_debug_core_context_t *context) static void cvmx_debug_sync_up_cores(void) { - cvmx_debug_state_t state; + /* NOTE this reads directly from the state array for speed reasons + and we don't change the array. */ do { - state = cvmx_debug_get_state(); - } while (state.step_all && state.handler_cores != 0); + asm("": : : "memory"); + } while (cvmx_debug_globals->state[offsetof(cvmx_debug_state_t, step_all)/sizeof(uint32_t)] + && cvmx_debug_globals->state[offsetof(cvmx_debug_state_t, handler_cores)/sizeof(uint32_t)] != 0); } /* Delay the focus core a little if it is likely another core needs to steal @@ -993,7 +1146,7 @@ static void cvmx_debug_delay_focus_core(cvmx_debug_state_t state, unsigned core, volatile int i; if (debug_reg->s.dss || debug_reg->s.dbp || core != state.focus_core) return; - for (i = 0; i < 24000; i++) + for (i = 0; i < 2400; i++) { asm volatile (".set push \n\t" ".set noreorder \n\t" @@ -1086,7 +1239,7 @@ static int cvmx_debug_perform_proxy(cvmx_debug_register_t *debug_reg, volatile c cvmx_spinlock_lock(&cvmx_debug_globals->lock); state = cvmx_debug_get_state(); - state.handler_cores |= (1 << core); + state.handler_cores |= (1u << core); cvmx_debug_may_elect_as_focus_core(&state, core, debug_reg); /* Push all updates before exiting the critical section */ @@ -1098,10 +1251,17 @@ static int cvmx_debug_perform_proxy(cvmx_debug_register_t *debug_reg, volatile c cvmx_debug_send_stop_reason(debug_reg, context); do { + unsigned oldfocus = state.focus_core; state = cvmx_debug_get_state(); /* Note the focus core can change in this loop. */ if (__cvmx_debug_in_focus(state, core)) { + /* If the focus has changed and the old focus has exited, then send a signal + that we should stop if step_all is off. */ + if (oldfocus != state.focus_core && ((1u << oldfocus) & state.core_finished) + && !state.step_all) + cvmx_debug_send_stop_reason(debug_reg, context); + command = cvmx_debug_process_next_packet(); state = cvmx_debug_get_state(); /* When resuming let the other cores resume as well with @@ -1135,7 +1295,7 @@ static int cvmx_debug_perform_proxy(cvmx_debug_register_t *debug_reg, volatile c { cvmx_spinlock_lock(&cvmx_debug_globals->lock); state = cvmx_debug_get_state(); - state.handler_cores ^= (1 << core); + state.handler_cores ^= (1u << core); cvmx_debug_update_state(state); cvmx_spinlock_unlock(&cvmx_debug_globals->lock); } @@ -1153,12 +1313,12 @@ static int cvmx_debug_perform_proxy(cvmx_debug_register_t *debug_reg, volatile c return 0; } -static void cvmx_debug_save_core_context(volatile cvmx_debug_core_context_t *context) +static void cvmx_debug_save_core_context(volatile cvmx_debug_core_context_t *context, uint64_t hi, uint64_t lo) { unsigned i; - memcpy((char *) context->regs, __cvmx_debug_save_regs_area, sizeof(context->regs)); - asm("mflo %0" : "=r"(context->lo)); - asm("mfhi %0" : "=r"(context->hi)); + cvmx_debug_memcpy_align ((char *) context->regs, __cvmx_debug_save_regs_area, sizeof(context->regs)); + context->lo = lo; + context->hi = hi; CVMX_MF_COP0(context->cop0.index, COP0_INDEX); CVMX_MF_COP0(context->cop0.entrylo[0], COP0_ENTRYLO0); CVMX_MF_COP0(context->cop0.entrylo[1], COP0_ENTRYLO1); @@ -1209,10 +1369,9 @@ static void cvmx_debug_save_core_context(volatile cvmx_debug_core_context_t *con static void cvmx_debug_restore_core_context(volatile cvmx_debug_core_context_t *context) { + uint64_t hi, lo; int i; - memcpy(__cvmx_debug_save_regs_area, (char *) context->regs, sizeof(context->regs)); - asm("mtlo %0" :: "r"(context->lo)); - asm("mthi %0" :: "r"(context->hi)); + cvmx_debug_memcpy_align (__cvmx_debug_save_regs_area, (char *) context->regs, sizeof(context->regs)); /* We don't change the TLB so no need to restore it. */ cvmx_write_csr(CVMX_DEBUG_HW_DATA_BREAKPOINT_STATUS, context->hw_dbp.status); for (i = 0; i < 4; i++) @@ -1245,6 +1404,10 @@ static void cvmx_debug_restore_core_context(volatile cvmx_debug_core_context_t * CVMX_MT_COP0(context->cop0.perfctrl[1], COP0_PERFCONTROL1); CVMX_MT_COP0(context->cop0.depc, COP0_DEPC); CVMX_MT_COP0(context->cop0.desave, COP0_DESAVE); + lo = context->lo; + hi = context->hi; + asm("mtlo %0" :: "r"(lo)); + asm("mthi %0" :: "r"(hi)); } static inline void cvmx_debug_print_cause(volatile cvmx_debug_core_context_t *context) @@ -1273,7 +1436,7 @@ static inline void cvmx_debug_print_cause(volatile cvmx_debug_core_context_t *co cvmx_dprintf("Debug Single Step (DSS) exception\n"); } -void __cvmx_debug_handler_stage3 (void) +void __cvmx_debug_handler_stage3 (uint64_t lo, uint64_t hi) { volatile cvmx_debug_core_context_t *context; int comms_changed = 0; @@ -1293,7 +1456,7 @@ void __cvmx_debug_handler_stage3 (void) } context = cvmx_debug_core_context(); - cvmx_debug_save_core_context(context); + cvmx_debug_save_core_context(context, hi, lo); { cvmx_debug_state_t state; @@ -1370,7 +1533,7 @@ void __cvmx_debug_handler_stage3 (void) void cvmx_debug_trigger_exception(void) { /* Set CVMX_CIU_DINT to enter debug exception handler. */ - cvmx_write_csr (CVMX_CIU_DINT, 1 << cvmx_get_core_num ()); + cvmx_write_csr (CVMX_CIU_DINT, 1u << cvmx_get_core_num ()); /* Perform an immediate read after every write to an RSL register to force the write to complete. It doesn't matter what RSL read we do, so we choose CVMX_MIO_BOOT_BIST_STAT because it is fast and harmless */ @@ -1387,6 +1550,7 @@ void cvmx_debug_finish(void) unsigned coreid = cvmx_get_core_num(); cvmx_debug_state_t state; + if (!cvmx_debug_globals) return; cvmx_debug_printf ("Debug _exit reached!, core %d, cvmx_debug_globals = %p\n", coreid, cvmx_debug_globals); #ifndef CVMX_BUILD_FOR_LINUX_KERNEL @@ -1396,13 +1560,13 @@ void cvmx_debug_finish(void) cvmx_spinlock_lock(&cvmx_debug_globals->lock); state = cvmx_debug_get_state(); - state.known_cores ^= (1 << coreid); - state.core_finished |= (1<<coreid); + state.known_cores ^= (1u << coreid); + state.core_finished |= (1u <<coreid); cvmx_debug_update_state(state); /* Tell the user the core has finished. */ if (state.ever_been_in_debug) - cvmx_debug_putpacket("!Core %d finish.", coreid); + cvmx_debug_putcorepacket("finished.", coreid); /* Notify the debugger if all cores have completed the program */ if ((cvmx_debug_core_mask () & state.core_finished) == cvmx_debug_core_mask ()) @@ -1417,9 +1581,9 @@ void cvmx_debug_finish(void) Since we already check that known_cores is non zero, this should always find a core */ unsigned newcore; - for (newcore = 0; newcore < CVMX_DEBUG_MAX_CORES; newcore++) + for (newcore = 0; newcore < CVMX_MAX_CORES; newcore++) { - if (state.known_cores & (1<<newcore)) + if (state.known_cores & (1u<<newcore)) { cvmx_debug_printf("Routing uart interrupts to Core #%u.\n", newcore); cvmx_debug_set_focus_core(&state, newcore); |