cvmx-debug.c revision 215976
1215976Sjmallett/***********************license start*************** 2215976Sjmallett * Copyright (c) 2003-2010 Cavium Networks (support@cavium.com). All rights 3215976Sjmallett * reserved. 4215976Sjmallett * 5215976Sjmallett * 6215976Sjmallett * Redistribution and use in source and binary forms, with or without 7215976Sjmallett * modification, are permitted provided that the following conditions are 8215976Sjmallett * met: 9215976Sjmallett * 10215976Sjmallett * * Redistributions of source code must retain the above copyright 11215976Sjmallett * notice, this list of conditions and the following disclaimer. 12215976Sjmallett * 13215976Sjmallett * * Redistributions in binary form must reproduce the above 14215976Sjmallett * copyright notice, this list of conditions and the following 15215976Sjmallett * disclaimer in the documentation and/or other materials provided 16215976Sjmallett * with the distribution. 17215976Sjmallett 18215976Sjmallett * * Neither the name of Cavium Networks nor the names of 19215976Sjmallett * its contributors may be used to endorse or promote products 20215976Sjmallett * derived from this software without specific prior written 21215976Sjmallett * permission. 22215976Sjmallett 23215976Sjmallett * This Software, including technical data, may be subject to U.S. export control 24215976Sjmallett * laws, including the U.S. Export Administration Act and its associated 25215976Sjmallett * regulations, and may be subject to export or import regulations in other 26215976Sjmallett * countries. 27215976Sjmallett 28215976Sjmallett * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" 29215976Sjmallett * AND WITH ALL FAULTS AND CAVIUM NETWORKS MAKES NO PROMISES, REPRESENTATIONS OR 30215976Sjmallett * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO 31215976Sjmallett * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR 32215976Sjmallett * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM 33215976Sjmallett * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE, 34215976Sjmallett * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF 35215976Sjmallett * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR 36215976Sjmallett * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT OF USE OR 37215976Sjmallett * PERFORMANCE OF THE SOFTWARE LIES WITH YOU. 38215976Sjmallett ***********************license end**************************************/ 39215976Sjmallett 40215976Sjmallett 41215976Sjmallett/* 42215976Sjmallett * @file 43215976Sjmallett * 44215976Sjmallett * Interface to debug exception handler 45215976Sjmallett * 46215976Sjmallett * <hr>$Revision: 50060 $<hr> 47215976Sjmallett */ 48215976Sjmallett 49215976Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 50215976Sjmallett#include <linux/module.h> 51215976Sjmallett#include <asm/octeon/octeon.h> 52215976Sjmallett#include <asm/octeon/cvmx.h> 53215976Sjmallett#include <asm/octeon/cvmx-debug.h> 54215976Sjmallett#include <asm/octeon/cvmx-core.h> 55215976Sjmallett#include <asm/octeon/cvmx-bootmem.h> 56215976Sjmallett#include <asm/octeon/octeon-boot-info.h> 57215976Sjmallett#else 58215976Sjmallett#include <stdint.h> 59215976Sjmallett#include "executive-config.h" 60215976Sjmallett#include "cvmx.h" 61215976Sjmallett#include "cvmx-debug.h" 62215976Sjmallett#include "cvmx-bootmem.h" 63215976Sjmallett#include "cvmx-core.h" 64215976Sjmallett#include "cvmx-coremask.h" 65215976Sjmallett 66215976Sjmallett#ifndef __OCTEON_NEWLIB__ 67215976Sjmallett#include "../../bootloader/u-boot/include/octeon_mem_map.h" 68215976Sjmallett#else 69215976Sjmallett#include "octeon-boot-info.h" 70215976Sjmallett#endif 71215976Sjmallett 72215976Sjmallett#endif 73215976Sjmallett 74215976Sjmallett#ifdef CVMX_DEBUG_LOGGING 75215976Sjmallett# undef CVMX_DEBUG_LOGGING 76215976Sjmallett# define CVMX_DEBUG_LOGGING 1 77215976Sjmallett#else 78215976Sjmallett# define CVMX_DEBUG_LOGGING 0 79215976Sjmallett#endif 80215976Sjmallett 81215976Sjmallett#ifndef CVMX_DEBUG_ATTACH 82215976Sjmallett# define CVMX_DEBUG_ATTACH 1 83215976Sjmallett#endif 84215976Sjmallett 85215976Sjmallett#define CVMX_DEBUG_HW_INSTRUCTION_BREAKPOINT_STATUS (0xFFFFFFFFFF301000ull) 86215976Sjmallett#define CVMX_DEBUG_HW_INSTRUCTION_BREAKPOINT_ADDRESS(num) (0xFFFFFFFFFF301100ull + 0x100 * (num)) 87215976Sjmallett#define CVMX_DEBUG_HW_INSTRUCTION_BREAKPOINT_ADDRESS_MASK(num) (0xFFFFFFFFFF301108ull + 0x100 * (num)) 88215976Sjmallett#define CVMX_DEBUG_HW_INSTRUCTION_BREAKPOINT_ASID(num) (0xFFFFFFFFFF301110ull + 0x100 * (num)) 89215976Sjmallett#define CVMX_DEBUG_HW_INSTRUCTION_BREAKPOINT_CONTROL(num) (0xFFFFFFFFFF301118ull + 0x100 * (num)) 90215976Sjmallett 91215976Sjmallett#define CVMX_DEBUG_HW_DATA_BREAKPOINT_STATUS (0xFFFFFFFFFF302000ull) 92215976Sjmallett#define CVMX_DEBUG_HW_DATA_BREAKPOINT_ADDRESS(num) (0xFFFFFFFFFF302100ull + 0x100 * (num)) 93215976Sjmallett#define CVMX_DEBUG_HW_DATA_BREAKPOINT_ADDRESS_MASK(num) (0xFFFFFFFFFF302108ull + 0x100 * (num)) 94215976Sjmallett#define CVMX_DEBUG_HW_DATA_BREAKPOINT_ASID(num) (0xFFFFFFFFFF302110ull + 0x100 * (num)) 95215976Sjmallett#define CVMX_DEBUG_HW_DATA_BREAKPOINT_CONTROL(num) (0xFFFFFFFFFF302118ull + 0x100 * (num)) 96215976Sjmallett 97215976Sjmallett#define ERET_INSN 0x42000018U /* Hexcode for eret */ 98215976Sjmallett#define ISR_DELAY_COUNTER 120000000 /* Could be tuned down */ 99215976Sjmallett 100215976Sjmallettextern cvmx_debug_comm_t cvmx_debug_uart_comm; 101215976Sjmallettextern cvmx_debug_comm_t cvmx_debug_remote_comm; 102215976Sjmallettstatic const cvmx_debug_comm_t *cvmx_debug_comms[COMM_SIZE] = {&cvmx_debug_uart_comm, &cvmx_debug_remote_comm}; 103215976Sjmallett 104215976Sjmallett 105215976Sjmallett 106215976Sjmallettstatic cvmx_debug_globals_t *cvmx_debug_globals; 107215976Sjmallett 108215976Sjmallett/** 109215976Sjmallett * @file 110215976Sjmallett * 111215976Sjmallett */ 112215976Sjmallett 113215976Sjmallett#ifndef CVMX_BUILD_FOR_LINUX_KERNEL 114215976Sjmallettuint64_t __cvmx_debug_save_regs_area[32]; 115215976Sjmallett 116215976Sjmallettvolatile uint64_t __cvmx_debug_mode_exception_ignore; 117215976Sjmallettvolatile uint64_t __cvmx_debug_mode_exception_occured; 118215976Sjmallett 119215976Sjmallettstatic char cvmx_debug_stack[8*1024] __attribute ((aligned (16))); 120215976Sjmallettchar *__cvmx_debug_stack_top = &cvmx_debug_stack[8*1024]; 121215976Sjmallett 122215976Sjmallett#ifndef __OCTEON_NEWLIB__ 123215976Sjmallettextern int cvmx_interrupt_in_isr; 124215976Sjmallett#else 125215976Sjmallett#define cvmx_interrupt_in_isr 0 126215976Sjmallett#endif 127215976Sjmallett 128215976Sjmallett#else 129215976Sjmallettuint64_t __cvmx_debug_save_regs_area_all[OCTEON_NUM_CORES][32]; 130215976Sjmallett#define __cvmx_debug_save_regs_area __cvmx_debug_save_regs_area_all[cvmx_get_core_num()] 131215976Sjmallett 132215976Sjmallettvolatile uint64_t __cvmx_debug_mode_exception_ignore_all[OCTEON_NUM_CORES]; 133215976Sjmallett#define __cvmx_debug_mode_exception_ignore __cvmx_debug_mode_exception_ignore_all[cvmx_get_core_num()] 134215976Sjmallettvolatile uint64_t __cvmx_debug_mode_exception_occured_all[OCTEON_NUM_CORES]; 135215976Sjmallett#define __cvmx_debug_mode_exception_occured __cvmx_debug_mode_exception_occured_all[cvmx_get_core_num()] 136215976Sjmallett 137215976Sjmallettstatic char cvmx_debug_stack_all[OCTEON_NUM_CORES][8*1024] __attribute ((aligned (16))); 138215976Sjmallettchar *__cvmx_debug_stack_top_all[OCTEON_NUM_CORES]; 139215976Sjmallett 140215976Sjmallett#define cvmx_interrupt_in_isr 0 141215976Sjmallett 142215976Sjmallett#endif 143215976Sjmallett 144215976Sjmallett 145215976Sjmallettstatic inline uint32_t cvmx_debug_core_mask(void) 146215976Sjmallett{ 147215976Sjmallett#ifndef CVMX_BUILD_FOR_LINUX_KERNEL 148215976Sjmallett#ifdef __OCTEON_NEWLIB__ 149215976Sjmallett extern int __octeon_core_mask; 150215976Sjmallett return __octeon_core_mask; 151215976Sjmallett#endif 152215976Sjmallettreturn cvmx_sysinfo_get()->core_mask; 153215976Sjmallett#else 154215976Sjmallettreturn octeon_get_boot_coremask (); 155215976Sjmallett#endif 156215976Sjmallett} 157215976Sjmallett 158215976Sjmallettstatic inline void cvmx_debug_update_state(cvmx_debug_state_t state) 159215976Sjmallett{ 160215976Sjmallett memcpy(cvmx_debug_globals->state, &state, sizeof(cvmx_debug_state_t)); 161215976Sjmallett} 162215976Sjmallett 163215976Sjmallettstatic inline cvmx_debug_state_t cvmx_debug_get_state(void) 164215976Sjmallett{ 165215976Sjmallett cvmx_debug_state_t state; 166215976Sjmallett memcpy(&state, cvmx_debug_globals->state, sizeof(cvmx_debug_state_t)); 167215976Sjmallett return state; 168215976Sjmallett} 169215976Sjmallett 170215976Sjmallettstatic void cvmx_debug_printf(char *format, ...) __attribute__((format(__printf__, 1, 2))); 171215976Sjmallettstatic void cvmx_debug_printf(char *format, ...) 172215976Sjmallett{ 173215976Sjmallett va_list ap; 174215976Sjmallett 175215976Sjmallett if (!CVMX_DEBUG_LOGGING) 176215976Sjmallett return; 177215976Sjmallett 178215976Sjmallett va_start(ap, format); 179215976Sjmallett cvmx_dvprintf(format, ap); 180215976Sjmallett va_end(ap); 181215976Sjmallett} 182215976Sjmallett 183215976Sjmallettstatic inline int __cvmx_debug_in_focus(cvmx_debug_state_t state, unsigned core) 184215976Sjmallett{ 185215976Sjmallett return state.focus_core == core; 186215976Sjmallett} 187215976Sjmallett 188215976Sjmallettstatic void cvmx_debug_install_handler(unsigned core) 189215976Sjmallett{ 190215976Sjmallett extern void __cvmx_debug_handler_stage2(void); 191215976Sjmallett int32_t *trampoline = CASTPTR(int32_t, CVMX_ADD_SEG32(CVMX_MIPS32_SPACE_KSEG0, BOOTLOADER_DEBUG_TRAMPOLINE_CORE)); 192215976Sjmallett trampoline += core; 193215976Sjmallett 194215976Sjmallett *trampoline = (int32_t)(long)&__cvmx_debug_handler_stage2; 195215976Sjmallett 196215976Sjmallett cvmx_debug_printf("Debug handled installed on core %d at %p\n", core, trampoline); 197215976Sjmallett} 198215976Sjmallett 199215976Sjmallettstatic int cvmx_debug_enabled(void) 200215976Sjmallett{ 201215976Sjmallett return cvmx_debug_booted() || CVMX_DEBUG_ATTACH; 202215976Sjmallett} 203215976Sjmallett 204215976Sjmallettstatic void cvmx_debug_init_globals(void) 205215976Sjmallett{ 206215976Sjmallett int toclear = 0; 207215976Sjmallett uint64_t phys; 208215976Sjmallett void *a; 209215976Sjmallett 210215976Sjmallett if (cvmx_debug_globals) 211215976Sjmallett return; 212215976Sjmallett 213215976Sjmallett if (cvmx_get_core_num() != 0) 214215976Sjmallett { 215215976Sjmallett volatile size_t i; 216215976Sjmallett /* Delay here just enough for the writing of the version. */ 217215976Sjmallett for(i = 0; i < sizeof(cvmx_debug_globals_t)/2 + 8; i++) 218215976Sjmallett ; 219215976Sjmallett } 220215976Sjmallett 221215976Sjmallett a = cvmx_bootmem_alloc_named(sizeof(cvmx_debug_globals_t), 8, CVMX_DEBUG_GLOBALS_BLOCK_NAME); 222215976Sjmallett if (a) 223215976Sjmallett { 224215976Sjmallett phys = cvmx_ptr_to_phys(a); 225215976Sjmallett toclear = 1; 226215976Sjmallett } 227215976Sjmallett else 228215976Sjmallett { 229215976Sjmallett const cvmx_bootmem_named_block_desc_t *debug_globals_nblk; 230215976Sjmallett debug_globals_nblk = cvmx_bootmem_find_named_block (CVMX_DEBUG_GLOBALS_BLOCK_NAME); 231215976Sjmallett phys = debug_globals_nblk->base_addr; 232215976Sjmallett } 233215976Sjmallett cvmx_debug_globals = CASTPTR(cvmx_debug_globals_t, CVMX_ADD_SEG32(CVMX_MIPS32_SPACE_KSEG0, phys)); 234215976Sjmallett cvmx_debug_printf("Debug named block at %p\n", cvmx_debug_globals); 235215976Sjmallett if (toclear) 236215976Sjmallett cvmx_debug_printf("Debug named block cleared\n"); 237215976Sjmallett 238215976Sjmallett if (toclear) 239215976Sjmallett { 240215976Sjmallett memset (cvmx_debug_globals, 0, sizeof(cvmx_debug_globals_t)); 241215976Sjmallett cvmx_debug_globals->version = CVMX_DEBUG_GLOBALS_VERSION; 242215976Sjmallett cvmx_debug_globals->tlb_entries = cvmx_core_get_tlb_entries(); 243215976Sjmallett } 244215976Sjmallett else 245215976Sjmallett { 246215976Sjmallett volatile size_t i; 247215976Sjmallett /* Delay here just enough for the writing of the version. */ 248215976Sjmallett for(i = 0; i < sizeof(cvmx_debug_globals_t) + 8; i++) 249215976Sjmallett ; 250215976Sjmallett } 251215976Sjmallett} 252215976Sjmallett 253215976Sjmallett 254215976Sjmallettstatic void cvmx_debug_globals_check_version(void) 255215976Sjmallett{ 256215976Sjmallett if (cvmx_debug_globals->version != CVMX_DEBUG_GLOBALS_VERSION) 257215976Sjmallett { 258215976Sjmallett cvmx_dprintf("Wrong version on the globals struct spinining; expected %d, got: %d.\n", (int)CVMX_DEBUG_GLOBALS_VERSION, (int)(cvmx_debug_globals->version)); 259215976Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 260215976Sjmallett panic("Wrong version.\n"); 261215976Sjmallett#endif 262215976Sjmallett while (1) 263215976Sjmallett ; 264215976Sjmallett } 265215976Sjmallett} 266215976Sjmallett 267215976Sjmallettstatic inline volatile cvmx_debug_core_context_t *cvmx_debug_core_context(void); 268215976Sjmallettstatic inline void cvmx_debug_save_core_context(volatile cvmx_debug_core_context_t *context); 269215976Sjmallett 270215976Sjmallettvoid cvmx_debug_init(void) 271215976Sjmallett{ 272215976Sjmallett cvmx_debug_state_t state; 273215976Sjmallett int core; 274215976Sjmallett const cvmx_debug_comm_t *comm; 275215976Sjmallett cvmx_spinlock_t *lock; 276215976Sjmallett unsigned int coremask = cvmx_debug_core_mask(); 277215976Sjmallett 278215976Sjmallett if (!cvmx_debug_enabled()) 279215976Sjmallett return; 280215976Sjmallett 281215976Sjmallett cvmx_debug_init_globals(); 282215976Sjmallett 283215976Sjmallett#ifndef CVMX_BUILD_FOR_LINUX_KERNEL 284215976Sjmallett // Put a barrier until all cores have got to this point. 285215976Sjmallett cvmx_coremask_barrier_sync(coremask); 286215976Sjmallett#endif 287215976Sjmallett cvmx_debug_globals_check_version(); 288215976Sjmallett 289215976Sjmallett 290215976Sjmallett comm = cvmx_debug_comms[cvmx_debug_globals->comm_type]; 291215976Sjmallett lock = &cvmx_debug_globals->lock; 292215976Sjmallett 293215976Sjmallett core = cvmx_get_core_num(); 294215976Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 295215976Sjmallett /* Install the debugger handler on the cores. */ 296215976Sjmallett { 297215976Sjmallett int core1 = 0; 298215976Sjmallett for (core1 = 0; core1 < OCTEON_NUM_CORES; core1++) 299215976Sjmallett { 300215976Sjmallett if ((1<<core1) & coremask) 301215976Sjmallett cvmx_debug_install_handler(core1); 302215976Sjmallett } 303215976Sjmallett } 304215976Sjmallett#else 305215976Sjmallett cvmx_debug_install_handler(core); 306215976Sjmallett#endif 307215976Sjmallett 308215976Sjmallett if (comm->init) 309215976Sjmallett comm->init(); 310215976Sjmallett 311215976Sjmallett { 312215976Sjmallett cvmx_spinlock_lock(lock); 313215976Sjmallett state = cvmx_debug_get_state(); 314215976Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 315215976Sjmallett state.known_cores |= coremask; 316215976Sjmallett state.core_finished &= ~coremask; 317215976Sjmallett#else 318215976Sjmallett state.known_cores |= (1 << core); 319215976Sjmallett state.core_finished &= ~(1 << core); 320215976Sjmallett#endif 321215976Sjmallett cvmx_debug_update_state(state); 322215976Sjmallett cvmx_spinlock_unlock(lock); 323215976Sjmallett } 324215976Sjmallett 325215976Sjmallett#ifndef CVMX_BUILD_FOR_LINUX_KERNEL 326215976Sjmallett // Put a barrier until all cores have got to this point. 327215976Sjmallett cvmx_coremask_barrier_sync(coremask); 328215976Sjmallett 329215976Sjmallett if (cvmx_coremask_first_core(coremask)) 330215976Sjmallett#endif 331215976Sjmallett { 332215976Sjmallett cvmx_debug_printf("cvmx_debug_init core: %d\n", core); 333215976Sjmallett state = cvmx_debug_get_state(); 334215976Sjmallett state.focus_core = core; 335215976Sjmallett state.active_cores = state.known_cores; 336215976Sjmallett state.focus_switch = 1; 337215976Sjmallett state.step_isr = 1; 338215976Sjmallett cvmx_debug_printf("Known cores at init: 0x%x\n", (int)state.known_cores); 339215976Sjmallett cvmx_debug_update_state(state); 340215976Sjmallett 341215976Sjmallett /* Initialize __cvmx_debug_stack_top_all. */ 342215976Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 343215976Sjmallett { 344215976Sjmallett int i; 345215976Sjmallett for (i = 0; i < OCTEON_NUM_CORES; i++) 346215976Sjmallett __cvmx_debug_stack_top_all[i] = &cvmx_debug_stack_all[i][8*1024]; 347215976Sjmallett } 348215976Sjmallett#endif 349215976Sjmallett cvmx_debug_globals->init_complete = 1; 350215976Sjmallett CVMX_SYNCW; 351215976Sjmallett } 352215976Sjmallett while (!cvmx_debug_globals->init_complete) 353215976Sjmallett { 354215976Sjmallett /* Spin waiting for init to complete */ 355215976Sjmallett } 356215976Sjmallett 357215976Sjmallett if (cvmx_debug_booted()) 358215976Sjmallett cvmx_debug_trigger_exception(); 359215976Sjmallett 360215976Sjmallett /* Install the break handler after might tripper the debugger exception. */ 361215976Sjmallett#ifndef CVMX_BUILD_FOR_LINUX_KERNEL 362215976Sjmallett if (cvmx_coremask_first_core(coremask)) 363215976Sjmallett#endif 364215976Sjmallett { 365215976Sjmallett if (comm->install_break_handler) 366215976Sjmallett comm->install_break_handler(); 367215976Sjmallett } 368215976Sjmallett} 369215976Sjmallett 370215976Sjmallettstatic int cvmx_debug_putpacket_noformat(char *packet); 371215976Sjmallett 372215976Sjmallettstatic __attribute__ ((format (printf, 1, 2))) int cvmx_debug_putpacket(char *format, ...) 373215976Sjmallett{ 374215976Sjmallett va_list ap; 375215976Sjmallett size_t n; 376215976Sjmallett char packet[CVMX_DEBUG_MAX_RESPONSE_SIZE]; 377215976Sjmallett 378215976Sjmallett if (cvmx_debug_comms[cvmx_debug_globals->comm_type]->putpacket == NULL) 379215976Sjmallett return 0; 380215976Sjmallett 381215976Sjmallett va_start(ap, format); 382215976Sjmallett n = vsnprintf(packet, sizeof(packet), format, ap); 383215976Sjmallett va_end(ap); 384215976Sjmallett 385215976Sjmallett if (n >= sizeof(packet)) 386215976Sjmallett { 387215976Sjmallett cvmx_debug_printf("packet truncated (needed %d bytes): %s\n", (int)n, packet); 388215976Sjmallett return 0; 389215976Sjmallett } 390215976Sjmallett return cvmx_debug_putpacket_noformat(packet); 391215976Sjmallett} 392215976Sjmallett 393215976Sjmallettstatic int cvmx_debug_putpacket_noformat(char *packet) 394215976Sjmallett{ 395215976Sjmallett if (cvmx_debug_comms[cvmx_debug_globals->comm_type]->putpacket == NULL) 396215976Sjmallett return 0; 397215976Sjmallett cvmx_debug_printf("Reply: %s\n", packet); 398215976Sjmallett return cvmx_debug_comms[cvmx_debug_globals->comm_type]->putpacket(packet); 399215976Sjmallett} 400215976Sjmallett 401215976Sjmallettstatic int cvmx_debug_active_core(cvmx_debug_state_t state, int core) 402215976Sjmallett{ 403215976Sjmallett return state.active_cores & (1 << core); 404215976Sjmallett} 405215976Sjmallett 406215976Sjmallettstatic volatile cvmx_debug_core_context_t *cvmx_debug_core_context(void) 407215976Sjmallett{ 408215976Sjmallett return &cvmx_debug_globals->contextes[cvmx_get_core_num()]; 409215976Sjmallett} 410215976Sjmallett 411215976Sjmallettstatic volatile uint64_t *cvmx_debug_regnum_to_context_ref(int regnum, volatile cvmx_debug_core_context_t *context) 412215976Sjmallett{ 413215976Sjmallett /* Must be kept in sync with mips_octeon_reg_names in gdb/mips-tdep.c. */ 414215976Sjmallett if (regnum < 32) 415215976Sjmallett return &context->regs[regnum]; 416215976Sjmallett switch (regnum) 417215976Sjmallett { 418215976Sjmallett case 32: return &context->cop0.status; 419215976Sjmallett case 33: return &context->lo; 420215976Sjmallett case 34: return &context->hi; 421215976Sjmallett case 35: return &context->cop0.badvaddr; 422215976Sjmallett case 36: return &context->cop0.cause; 423215976Sjmallett case 37: return &context->cop0.depc; 424215976Sjmallett default: return NULL; 425215976Sjmallett } 426215976Sjmallett} 427215976Sjmallett 428215976Sjmallettstatic int cvmx_debug_probe_load(unsigned char *ptr, unsigned char *result) 429215976Sjmallett{ 430215976Sjmallett volatile unsigned char *p = ptr; 431215976Sjmallett int ok; 432215976Sjmallett unsigned char tem; 433215976Sjmallett 434215976Sjmallett { 435215976Sjmallett __cvmx_debug_mode_exception_ignore = 1; 436215976Sjmallett __cvmx_debug_mode_exception_occured = 0; 437215976Sjmallett /* We don't handle debug-mode exceptions in delay slots. Avoid them. */ 438215976Sjmallett asm volatile (".set push \n\t" 439215976Sjmallett ".set noreorder \n\t" 440215976Sjmallett "nop \n\t" 441215976Sjmallett "lbu %0, %1 \n\t" 442215976Sjmallett "nop \n\t" 443215976Sjmallett ".set pop" : "=r"(tem) : "m"(*p)); 444215976Sjmallett ok = __cvmx_debug_mode_exception_occured == 0; 445215976Sjmallett __cvmx_debug_mode_exception_ignore = 0; 446215976Sjmallett __cvmx_debug_mode_exception_occured = 0; 447215976Sjmallett *result = tem; 448215976Sjmallett } 449215976Sjmallett return ok; 450215976Sjmallett} 451215976Sjmallett 452215976Sjmallettstatic int cvmx_debug_probe_store(unsigned char *ptr) 453215976Sjmallett{ 454215976Sjmallett volatile unsigned char *p = ptr; 455215976Sjmallett int ok; 456215976Sjmallett 457215976Sjmallett __cvmx_debug_mode_exception_ignore = 1; 458215976Sjmallett __cvmx_debug_mode_exception_occured = 0; 459215976Sjmallett /* We don't handle debug-mode exceptions in delay slots. Avoid them. */ 460215976Sjmallett asm volatile (".set push \n\t" 461215976Sjmallett ".set noreorder \n\t" 462215976Sjmallett "nop \n\t" 463215976Sjmallett "sb $0, %0 \n\t" 464215976Sjmallett "nop \n\t" 465215976Sjmallett ".set pop" : "=m"(*p)); 466215976Sjmallett ok = __cvmx_debug_mode_exception_occured == 0; 467215976Sjmallett 468215976Sjmallett __cvmx_debug_mode_exception_ignore = 0; 469215976Sjmallett __cvmx_debug_mode_exception_occured = 0; 470215976Sjmallett return ok; 471215976Sjmallett} 472215976Sjmallett 473215976Sjmallett/* Put the hex value of t into str. */ 474215976Sjmallettstatic void strhex(char *str, unsigned char t) 475215976Sjmallett{ 476215976Sjmallett char a[] = "0123456789ABCDEF"; 477215976Sjmallett str[0] = a[(t>>4)]; 478215976Sjmallett str[1] = a[t&0xF]; 479215976Sjmallett str[2] = 0; 480215976Sjmallett} 481215976Sjmallett 482215976Sjmallett/** 483215976Sjmallett * Initialize the performance counter control registers. 484215976Sjmallett * 485215976Sjmallett */ 486215976Sjmallettstatic void cvmx_debug_set_perf_control_reg (int perf_event, int perf_counter) 487215976Sjmallett{ 488215976Sjmallett volatile cvmx_debug_core_context_t *context = cvmx_debug_core_context(); 489215976Sjmallett cvmx_core_perf_control_t control; 490215976Sjmallett 491215976Sjmallett control.u32 = 0; 492215976Sjmallett control.s.u = 1; 493215976Sjmallett control.s.s = 1; 494215976Sjmallett control.s.k = 1; 495215976Sjmallett control.s.ex = 1; 496215976Sjmallett control.s.w = 1; 497215976Sjmallett control.s.m = 1 - perf_counter; 498215976Sjmallett control.s.event = perf_event; 499215976Sjmallett 500215976Sjmallett context->cop0.perfctrl[perf_counter] = control.u32; 501215976Sjmallett} 502215976Sjmallett 503215976Sjmallettstatic cvmx_debug_command_t cvmx_debug_process_packet(char *packet) 504215976Sjmallett{ 505215976Sjmallett const char *buf = packet; 506215976Sjmallett cvmx_debug_command_t result = COMMAND_NOP; 507215976Sjmallett cvmx_debug_state_t state = cvmx_debug_get_state(); 508215976Sjmallett 509215976Sjmallett /* A one letter command code represents what to do. */ 510215976Sjmallett switch (*buf++) 511215976Sjmallett { 512215976Sjmallett case '?': /* What protocol do I speak? */ 513215976Sjmallett cvmx_debug_putpacket_noformat("S0A"); 514215976Sjmallett break; 515215976Sjmallett 516215976Sjmallett case '\003': /* Control-C */ 517215976Sjmallett cvmx_debug_putpacket_noformat("T9"); 518215976Sjmallett break; 519215976Sjmallett 520215976Sjmallett case 'F': /* Change the focus core */ 521215976Sjmallett { 522215976Sjmallett int core; 523215976Sjmallett sscanf(buf, "%x", &core); 524215976Sjmallett 525215976Sjmallett /* Only cores in the exception handler may become the focus. 526215976Sjmallett If a core not in the exception handler got focus the 527215976Sjmallett debugger would hang since nobody would talk to it. */ 528215976Sjmallett if (state.handler_cores & (1 << core)) 529215976Sjmallett { 530215976Sjmallett /* Focus change reply must be sent before the focus 531215976Sjmallett changes. Otherwise the new focus core will eat our ACK 532215976Sjmallett from the debugger. */ 533215976Sjmallett cvmx_debug_putpacket("F%02x", core); 534215976Sjmallett cvmx_debug_comms[cvmx_debug_globals->comm_type]->change_core(state.focus_core, core); 535215976Sjmallett state.focus_core = core; 536215976Sjmallett cvmx_debug_update_state(state); 537215976Sjmallett break; 538215976Sjmallett } 539215976Sjmallett else 540215976Sjmallett cvmx_debug_putpacket_noformat("!Core is not in the exception handler. Focus not changed."); 541215976Sjmallett /* Nothing changed, so we send back the old value */ 542215976Sjmallett } 543215976Sjmallett /* fall through */ 544215976Sjmallett case 'f': /* Get the focus core */ 545215976Sjmallett cvmx_debug_putpacket("F%02x", (unsigned)state.focus_core); 546215976Sjmallett break; 547215976Sjmallett 548215976Sjmallett case 'J': /* Set the flag for skip-over-isr in Single-Stepping mode */ 549215976Sjmallett { 550215976Sjmallett if (*buf == '1') 551215976Sjmallett state.step_isr = 1; /* Step in ISR */ 552215976Sjmallett else 553215976Sjmallett state.step_isr = 0; /* Step over ISR */ 554215976Sjmallett cvmx_debug_update_state(state); 555215976Sjmallett } 556215976Sjmallett /* Fall through. The reply to the set step-isr command is the 557215976Sjmallett same as the get step-isr command */ 558215976Sjmallett 559215976Sjmallett case 'j': /* Reply with step_isr status */ 560215976Sjmallett cvmx_debug_putpacket("J%x", (unsigned)state.step_isr); 561215976Sjmallett break; 562215976Sjmallett 563215976Sjmallett 564215976Sjmallett case 'I': /* Set the active cores */ 565215976Sjmallett { 566215976Sjmallett long long active_cores; 567215976Sjmallett sscanf(buf, "%llx", &active_cores); 568215976Sjmallett /* Limit the active mask to the known to exist cores */ 569215976Sjmallett state.active_cores = active_cores & state.known_cores; 570215976Sjmallett 571215976Sjmallett /* Lazy user hack to have 0 be all cores */ 572215976Sjmallett if (state.active_cores == 0) 573215976Sjmallett state.active_cores = state.known_cores; 574215976Sjmallett 575215976Sjmallett /* The focus core must be in the active_cores mask */ 576215976Sjmallett if ((state.active_cores & (1 << state.focus_core)) == 0) 577215976Sjmallett { 578215976Sjmallett cvmx_debug_putpacket_noformat("!Focus core was added to the masked."); 579215976Sjmallett state.active_cores |= 1 << state.focus_core; 580215976Sjmallett } 581215976Sjmallett 582215976Sjmallett cvmx_debug_update_state(state); 583215976Sjmallett } 584215976Sjmallett /* Fall through. The reply to the set active cores command is the 585215976Sjmallett same as the get active cores command */ 586215976Sjmallett 587215976Sjmallett case 'i': /* Get the active cores */ 588215976Sjmallett cvmx_debug_putpacket("I%llx", (long long) state.active_cores); 589215976Sjmallett break; 590215976Sjmallett 591215976Sjmallett case 'A': /* Setting the step mode all or one */ 592215976Sjmallett { 593215976Sjmallett if (*buf == '1') 594215976Sjmallett state.step_all = 1; /* A step or continue will start all cores */ 595215976Sjmallett else 596215976Sjmallett state.step_all = 0; /* A step or continue only affects the focus core */ 597215976Sjmallett cvmx_debug_update_state(state); 598215976Sjmallett } 599215976Sjmallett /* Fall through. The reply to the set step-all command is the 600215976Sjmallett same as the get step-all command */ 601215976Sjmallett 602215976Sjmallett case 'a': /* Getting the current step mode */ 603215976Sjmallett cvmx_debug_putpacket("A%x", (unsigned)state.step_all); 604215976Sjmallett break; 605215976Sjmallett 606215976Sjmallett case 'g': /* read a register from global place. */ 607215976Sjmallett { 608215976Sjmallett volatile cvmx_debug_core_context_t *context = cvmx_debug_core_context(); 609215976Sjmallett int regno; 610215976Sjmallett volatile uint64_t *reg; 611215976Sjmallett 612215976Sjmallett /* Get the register number to read */ 613215976Sjmallett sscanf(buf, "%x", ®no); 614215976Sjmallett 615215976Sjmallett reg = cvmx_debug_regnum_to_context_ref(regno, context); 616215976Sjmallett if (!reg) 617215976Sjmallett cvmx_debug_printf("Register #%d is not valid\n", regno); 618215976Sjmallett cvmx_debug_putpacket("%llx", (unsigned long long) *reg); 619215976Sjmallett } 620215976Sjmallett break; 621215976Sjmallett 622215976Sjmallett case 'G': /* set the value of a register. */ 623215976Sjmallett { 624215976Sjmallett volatile cvmx_debug_core_context_t *context = cvmx_debug_core_context(); 625215976Sjmallett int regno; 626215976Sjmallett volatile uint64_t *reg; 627215976Sjmallett long long value; 628215976Sjmallett 629215976Sjmallett /* Get the register number to read */ 630215976Sjmallett if (sscanf(buf, "%x,%llx", ®no, &value) != 2) 631215976Sjmallett { 632215976Sjmallett cvmx_debug_printf("G packet corrupt: %s\n", buf); 633215976Sjmallett goto error_packet; 634215976Sjmallett } 635215976Sjmallett 636215976Sjmallett reg = cvmx_debug_regnum_to_context_ref(regno, context); 637215976Sjmallett if (!reg) 638215976Sjmallett { 639215976Sjmallett cvmx_debug_printf("Register #%d is not valid\n", regno); 640215976Sjmallett goto error_packet; 641215976Sjmallett } 642215976Sjmallett *reg = value; 643215976Sjmallett } 644215976Sjmallett break; 645215976Sjmallett 646215976Sjmallett case 'm': /* Memory read. mAA..AA,LLLL Read LLLL bytes at address AA..AA */ 647215976Sjmallett { 648215976Sjmallett long long addr, i, length; 649215976Sjmallett unsigned char *ptr; 650215976Sjmallett char *reply; 651215976Sjmallett 652215976Sjmallett if (sscanf(buf, "%llx,%llx", &addr, &length) != 2) 653215976Sjmallett { 654215976Sjmallett cvmx_debug_printf("m packet corrupt: %s\n", buf); 655215976Sjmallett goto error_packet; 656215976Sjmallett } 657215976Sjmallett if (length >= 1024) 658215976Sjmallett { 659215976Sjmallett cvmx_debug_printf("m packet length out of range: %lld\n", length); 660215976Sjmallett goto error_packet; 661215976Sjmallett } 662215976Sjmallett 663215976Sjmallett reply = __builtin_alloca(length * 2 + 1); 664215976Sjmallett ptr = (unsigned char *)(long)addr; 665215976Sjmallett for (i = 0; i < length; i++) 666215976Sjmallett { 667215976Sjmallett /* Probe memory. If not accessible fail. */ 668215976Sjmallett unsigned char t; 669215976Sjmallett if (!cvmx_debug_probe_load(&ptr[i], &t)) 670215976Sjmallett goto error_packet; 671215976Sjmallett strhex(&reply[i * 2], t); 672215976Sjmallett } 673215976Sjmallett cvmx_debug_putpacket_noformat(reply); 674215976Sjmallett } 675215976Sjmallett break; 676215976Sjmallett 677215976Sjmallett case 'M': /* Memory write. MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */ 678215976Sjmallett { 679215976Sjmallett long long addr, i, length; 680215976Sjmallett unsigned char *ptr; 681215976Sjmallett char value[1024]; 682215976Sjmallett 683215976Sjmallett if (sscanf(buf, "%llx,%llx:%1024s", &addr, &length, value) != 3) 684215976Sjmallett { 685215976Sjmallett cvmx_debug_printf("M packet corrupt: %s\n", buf); 686215976Sjmallett goto error_packet; 687215976Sjmallett } 688215976Sjmallett 689215976Sjmallett ptr = (unsigned char *)(long)addr; 690215976Sjmallett for (i = 0; i < length; i++) 691215976Sjmallett { 692215976Sjmallett int c; 693215976Sjmallett int n; 694215976Sjmallett char tempstr[3] = {0, 0, 0}; 695215976Sjmallett memcpy (tempstr, &value[i * 2], 2); 696215976Sjmallett 697215976Sjmallett n = sscanf(tempstr, "%2x", &c); 698215976Sjmallett if (n != 1) 699215976Sjmallett { 700215976Sjmallett cvmx_debug_printf("M packet corrupt: %s\n", &value[i * 2]); 701215976Sjmallett goto error_packet; 702215976Sjmallett } 703215976Sjmallett /* Probe memory. If not accessible fail. */ 704215976Sjmallett if (!cvmx_debug_probe_store(&ptr[i])) 705215976Sjmallett { 706215976Sjmallett cvmx_debug_printf("M cannot write: %p\n", &ptr[i]); 707215976Sjmallett goto error_packet; 708215976Sjmallett } 709215976Sjmallett ptr[i] = c; 710215976Sjmallett } 711215976Sjmallett cvmx_debug_putpacket_noformat("+"); 712215976Sjmallett } 713215976Sjmallett break; 714215976Sjmallett 715215976Sjmallett case 'e': /* Set/get performance counter events. e[1234]XX..X: [01] 716215976Sjmallett is the performance counter to set X is the performance 717215976Sjmallett event. [34] is to get the same thing. */ 718215976Sjmallett { 719215976Sjmallett int perf_event = 0; 720215976Sjmallett int counter, encoded_counter; 721215976Sjmallett volatile cvmx_debug_core_context_t *context = cvmx_debug_core_context(); 722215976Sjmallett sscanf(buf, "%1d%x", &encoded_counter, &perf_event); 723215976Sjmallett 724215976Sjmallett switch (encoded_counter) 725215976Sjmallett { 726215976Sjmallett case 1: /* Set performance counter0 event. */ 727215976Sjmallett case 2: /* Set performance counter1 event. */ 728215976Sjmallett 729215976Sjmallett counter = encoded_counter - 1; 730215976Sjmallett context->cop0.perfval[counter] = 0; 731215976Sjmallett cvmx_debug_set_perf_control_reg(perf_event, counter); 732215976Sjmallett break; 733215976Sjmallett 734215976Sjmallett case 3: /* Get performance counter0 event. */ 735215976Sjmallett case 4: /* Get performance counter1 event. */ 736215976Sjmallett { 737215976Sjmallett cvmx_core_perf_control_t c; 738215976Sjmallett counter = encoded_counter - 3; 739215976Sjmallett /* Pass performance counter0 event and counter to 740215976Sjmallett the debugger. */ 741215976Sjmallett c.u32 = context->cop0.perfctrl[counter]; 742215976Sjmallett cvmx_debug_putpacket("%llx,%llx", (long long) context->cop0.perfval[counter], (long long) c.s.event); 743215976Sjmallett } 744215976Sjmallett break; 745215976Sjmallett } 746215976Sjmallett } 747215976Sjmallett break; 748215976Sjmallett 749215976Sjmallett#if 0 750215976Sjmallett case 't': /* Return the trace buffer read data register contents. */ 751215976Sjmallett { 752215976Sjmallett uint64_t tra_data; 753215976Sjmallett uint64_t tra_ctl; 754215976Sjmallett char tmp[64]; 755215976Sjmallett 756215976Sjmallett /* If trace buffer is disabled no trace data information is available. */ 757215976Sjmallett if ((tra_ctl & 0x1) == 0) 758215976Sjmallett { 759215976Sjmallett cvmx_debug_putpacket_noformat("!Trace buffer not enabled\n"); 760215976Sjmallett cvmx_debug_putpacket_noformat("t"); 761215976Sjmallett } 762215976Sjmallett else 763215976Sjmallett { 764215976Sjmallett cvmx_debug_putpacket_noformat("!Trace buffer is enabled\n"); 765215976Sjmallett tra_data = cvmx_read_csr(OCTEON_TRA_READ_DATA); 766215976Sjmallett mem2hex (&tra_data, tmp, 8); 767215976Sjmallett strcpy (debug_output_buffer, "t"); 768215976Sjmallett strcat (debug_output_buffer, tmp); 769215976Sjmallett cvmx_debug_putpacket_noformat(debug_output_buffer); 770215976Sjmallett } 771215976Sjmallett } 772215976Sjmallett break; 773215976Sjmallett#endif 774215976Sjmallett 775215976Sjmallett case 'Z': /* Insert hardware breakpoint: Z[di]NN..N,AA.A, [di] data or 776215976Sjmallett instruction, NN..Nth at address AA..A */ 777215976Sjmallett { 778215976Sjmallett enum type 779215976Sjmallett { 780215976Sjmallett WP_LOAD = 1, 781215976Sjmallett WP_STORE = 2, 782215976Sjmallett WP_ACCESS = 3 783215976Sjmallett }; 784215976Sjmallett 785215976Sjmallett int num, size; 786215976Sjmallett long long addr; 787215976Sjmallett enum type type; 788215976Sjmallett char bp_type; 789215976Sjmallett const int BE = 1, TE = 4; 790215976Sjmallett int n; 791215976Sjmallett volatile cvmx_debug_core_context_t *context = cvmx_debug_core_context(); 792215976Sjmallett 793215976Sjmallett n = sscanf(buf, "%c%x,%llx,%x,%x", &bp_type, &num, &addr, &size, &type); 794215976Sjmallett switch (bp_type) 795215976Sjmallett { 796215976Sjmallett case 'i': // Instruction hardware breakpoint 797215976Sjmallett if (n != 3 || num > 4) 798215976Sjmallett { 799215976Sjmallett cvmx_debug_printf("Z packet corrupt: %s\n", buf); 800215976Sjmallett goto error_packet; 801215976Sjmallett } 802215976Sjmallett 803215976Sjmallett context->hw_ibp.address[num] = addr; 804215976Sjmallett context->hw_ibp.address_mask[num] = 0; 805215976Sjmallett context->hw_ibp.asid[num] = 0; 806215976Sjmallett context->hw_ibp.control[num] = BE | TE; 807215976Sjmallett break; 808215976Sjmallett 809215976Sjmallett case 'd': // Data hardware breakpoint 810215976Sjmallett { 811215976Sjmallett uint64_t dbc = 0xff0 | BE | TE; 812215976Sjmallett uint64_t dbm; 813215976Sjmallett if (n != 5 || num > 4) 814215976Sjmallett { 815215976Sjmallett cvmx_debug_printf("Z packet corrupt: %s\n", buf); 816215976Sjmallett goto error_packet; 817215976Sjmallett } 818215976Sjmallett 819215976Sjmallett /* Set DBC[BE,TE,BLM]. */ 820215976Sjmallett context->hw_dbp.address[num] = addr; 821215976Sjmallett context->hw_dbp.asid[num] = 0; 822215976Sjmallett 823215976Sjmallett dbc |= type == WP_STORE ? 0x1000 : type == WP_LOAD ? 0x2000 : 0; 824215976Sjmallett /* Mask the bits depending on the size for 825215976Sjmallett debugger to stop while accessing parts of the 826215976Sjmallett memory location. */ 827215976Sjmallett dbm = (size == 8) ? 0x7 : ((size == 4) ? 3 828215976Sjmallett : (size == 2) ? 1 : 0); 829215976Sjmallett context->hw_dbp.address_mask[num] = dbm; 830215976Sjmallett context->hw_dbp.control[num] = dbc; 831215976Sjmallett break; 832215976Sjmallett } 833215976Sjmallett default: 834215976Sjmallett cvmx_debug_printf("z packet corrupt: %s\n", buf); 835215976Sjmallett goto error_packet; 836215976Sjmallett } 837215976Sjmallett } 838215976Sjmallett break; 839215976Sjmallett 840215976Sjmallett case 'z': /* Remove hardware breakpoint: z[di]NN..N remove NN..Nth 841215976Sjmallettbreakpoint. */ 842215976Sjmallett { 843215976Sjmallett int num; 844215976Sjmallett char bp_type; 845215976Sjmallett volatile cvmx_debug_core_context_t *context = cvmx_debug_core_context(); 846215976Sjmallett 847215976Sjmallett if (sscanf(buf, "%c%x", &bp_type, &num) != 2 || num > 4) 848215976Sjmallett { 849215976Sjmallett cvmx_debug_printf("z packet corrupt: %s\n", buf); 850215976Sjmallett goto error_packet; 851215976Sjmallett } 852215976Sjmallett 853215976Sjmallett switch (bp_type) 854215976Sjmallett { 855215976Sjmallett case 'i': // Instruction hardware breakpoint 856215976Sjmallett context->hw_ibp.address[num] = 0; 857215976Sjmallett context->hw_ibp.address_mask[num] = 0; 858215976Sjmallett context->hw_ibp.asid[num] = 0; 859215976Sjmallett context->hw_ibp.control[num] = 0; 860215976Sjmallett break; 861215976Sjmallett case 'd': // Data hardware breakpoint 862215976Sjmallett context->hw_dbp.address[num] = 0; 863215976Sjmallett context->hw_dbp.address_mask[num] = 0; 864215976Sjmallett context->hw_dbp.asid[num] = 0; 865215976Sjmallett context->hw_dbp.control[num] = 0; 866215976Sjmallett break; 867215976Sjmallett default: 868215976Sjmallett cvmx_debug_printf("z packet corrupt: %s\n", buf); 869215976Sjmallett goto error_packet; 870215976Sjmallett } 871215976Sjmallett } 872215976Sjmallett break; 873215976Sjmallett 874215976Sjmallett case 's': /* Single step. sAA..AA Step one instruction from AA..AA (optional) */ 875215976Sjmallett result = COMMAND_STEP; 876215976Sjmallett break; 877215976Sjmallett 878215976Sjmallett case 'c': /* Continue. cAA..AA Continue at address AA..AA (optional) */ 879215976Sjmallett result = COMMAND_CONTINUE; 880215976Sjmallett break; 881215976Sjmallett 882215976Sjmallett case '+': /* Don't know. I think it is a communications sync */ 883215976Sjmallett /* Ignoring this command */ 884215976Sjmallett break; 885215976Sjmallett 886215976Sjmallett default: 887215976Sjmallett cvmx_debug_printf("Unknown debug command: %s\n", buf - 1); 888215976Sjmalletterror_packet: 889215976Sjmallett cvmx_debug_putpacket_noformat("-"); 890215976Sjmallett break; 891215976Sjmallett } 892215976Sjmallett 893215976Sjmallett return result; 894215976Sjmallett} 895215976Sjmallett 896215976Sjmallettstatic cvmx_debug_command_t cvmx_debug_process_next_packet(void) 897215976Sjmallett{ 898215976Sjmallett char packet[CVMX_DEBUG_MAX_REQUEST_SIZE]; 899215976Sjmallett if (cvmx_debug_comms[cvmx_debug_globals->comm_type]->getpacket(packet, CVMX_DEBUG_MAX_REQUEST_SIZE)) 900215976Sjmallett { 901215976Sjmallett cvmx_debug_printf("Request: %s\n", packet); 902215976Sjmallett return cvmx_debug_process_packet(packet); 903215976Sjmallett } 904215976Sjmallett return COMMAND_NOP; 905215976Sjmallett} 906215976Sjmallett 907215976Sjmallett/* If a core isn't in the active core mask we need to start him up again. We 908215976Sjmallett can only do this if the core didn't hit a breakpoint or single step. If the 909215976Sjmallett core hit CVMX_CIU_DINT interrupt (generally happens when while executing 910215976Sjmallett _exit() at the end of the program). Remove the core from known cores so 911215976Sjmallett that when the cores in active core mask are done executing the program, the 912215976Sjmallett focus will not be transfered to this core. */ 913215976Sjmallett 914215976Sjmallettstatic int cvmx_debug_stop_core(cvmx_debug_state_t state, unsigned core, cvmx_debug_register_t *debug_reg, int proxy) 915215976Sjmallett{ 916215976Sjmallett if (!cvmx_debug_active_core(state, core) && !debug_reg->s.dbp && !debug_reg->s.dss && (debug_reg->s.dint != 1)) 917215976Sjmallett { 918215976Sjmallett debug_reg->s.sst = 0; 919215976Sjmallett cvmx_debug_printf("Core #%d not in active cores, continuing.\n", core); 920215976Sjmallett return 0; 921215976Sjmallett } 922215976Sjmallett if ((state.core_finished & (1<<core)) && proxy) 923215976Sjmallett return 0; 924215976Sjmallett return 1; 925215976Sjmallett} 926215976Sjmallett 927215976Sjmallett/* check to see if current exc is single-stepped and that no other exc 928215976Sjmallett was also simultaneously noticed. */ 929215976Sjmallettstatic int cvmx_debug_single_step_exc(cvmx_debug_register_t *debug_reg) 930215976Sjmallett{ 931215976Sjmallett if (debug_reg->s.dss && !debug_reg->s.dib && !debug_reg->s.dbp && !debug_reg->s.ddbs && !debug_reg->s.ddbl) 932215976Sjmallett return 1; 933215976Sjmallett return 0; 934215976Sjmallett} 935215976Sjmallett 936215976Sjmallettstatic void cvmx_debug_set_focus_core(cvmx_debug_state_t *state, int core) 937215976Sjmallett{ 938215976Sjmallett if (state->ever_been_in_debug) 939215976Sjmallett cvmx_debug_putpacket("!Core %2x taking focus.", core); 940215976Sjmallett cvmx_debug_comms[cvmx_debug_globals->comm_type]->change_core (state->focus_core, core); 941215976Sjmallett state->focus_core = core; 942215976Sjmallett} 943215976Sjmallett 944215976Sjmallettstatic void cvmx_debug_may_elect_as_focus_core(cvmx_debug_state_t *state, int core, cvmx_debug_register_t *debug_reg) 945215976Sjmallett{ 946215976Sjmallett /* If another core has already elected itself as the focus core, we're late. */ 947215976Sjmallett if (state->handler_cores & (1 << state->focus_core)) 948215976Sjmallett return; 949215976Sjmallett 950215976Sjmallett /* If we hit a breakpoint, elect ourselves. */ 951215976Sjmallett if (debug_reg->s.dib || debug_reg->s.dbp || debug_reg->s.ddbs || debug_reg->s.ddbl) 952215976Sjmallett cvmx_debug_set_focus_core(state, core); 953215976Sjmallett 954215976Sjmallett /* It is possible the focus core has completed processing and exited the 955215976Sjmallett program. When this happens the focus core will not be in 956215976Sjmallett known_cores. If this is the case we need to elect a new focus. */ 957215976Sjmallett if ((state->known_cores & (1 << state->focus_core)) == 0) 958215976Sjmallett cvmx_debug_set_focus_core(state, core); 959215976Sjmallett} 960215976Sjmallett 961215976Sjmallettstatic void cvmx_debug_send_stop_reason(cvmx_debug_register_t *debug_reg, volatile cvmx_debug_core_context_t *context) 962215976Sjmallett{ 963215976Sjmallett /* Handle Debug Data Breakpoint Store/Load Exception. */ 964215976Sjmallett if (debug_reg->s.ddbs || debug_reg->s.ddbl) 965215976Sjmallett cvmx_debug_putpacket("T8:%x", (int) context->hw_dbp.status); 966215976Sjmallett else 967215976Sjmallett cvmx_debug_putpacket_noformat("T9"); 968215976Sjmallett} 969215976Sjmallett 970215976Sjmallett 971215976Sjmallettstatic void cvmx_debug_clear_status(volatile cvmx_debug_core_context_t *context) 972215976Sjmallett{ 973215976Sjmallett /* SW needs to clear the BreakStatus bits after a watchpoint is hit or on 974215976Sjmallett reset. */ 975215976Sjmallett context->hw_dbp.status &= ~0x3fff; 976215976Sjmallett 977215976Sjmallett /* Clear MCD0, which is write-1-to-clear. */ 978215976Sjmallett context->cop0.multicoredebug |= 1; 979215976Sjmallett} 980215976Sjmallett 981215976Sjmallettstatic void cvmx_debug_sync_up_cores(void) 982215976Sjmallett{ 983215976Sjmallett cvmx_debug_state_t state; 984215976Sjmallett do { 985215976Sjmallett state = cvmx_debug_get_state(); 986215976Sjmallett } while (state.step_all && state.handler_cores != 0); 987215976Sjmallett} 988215976Sjmallett 989215976Sjmallett/* Delay the focus core a little if it is likely another core needs to steal 990215976Sjmallett focus. Once we enter the main loop focus can't be stolen */ 991215976Sjmallettstatic void cvmx_debug_delay_focus_core(cvmx_debug_state_t state, unsigned core, cvmx_debug_register_t *debug_reg) 992215976Sjmallett{ 993215976Sjmallett volatile int i; 994215976Sjmallett if (debug_reg->s.dss || debug_reg->s.dbp || core != state.focus_core) 995215976Sjmallett return; 996215976Sjmallett for (i = 0; i < 24000; i++) 997215976Sjmallett { 998215976Sjmallett asm volatile (".set push \n\t" 999215976Sjmallett ".set noreorder \n\t" 1000215976Sjmallett "nop \n\t" 1001215976Sjmallett "nop \n\t" 1002215976Sjmallett "nop \n\t" 1003215976Sjmallett "nop \n\t" 1004215976Sjmallett ".set pop"); 1005215976Sjmallett /* Spin giving the breakpoint core time to steal focus */ 1006215976Sjmallett } 1007215976Sjmallett 1008215976Sjmallett} 1009215976Sjmallett 1010215976Sjmallett/* If this core was single-stepping in a group, 1011215976Sjmallett && it was not the last focus-core, 1012215976Sjmallett && last focus-core happens to be inside an ISR, blocking focus-switch 1013215976Sjmallett then burn some cycles, to avoid unnecessary focus toggles. */ 1014215976Sjmallettstatic void cvmx_debug_delay_isr_core(unsigned core, uint32_t depc, int single_stepped_exc_only, 1015215976Sjmallett cvmx_debug_state_t state) 1016215976Sjmallett{ 1017215976Sjmallett volatile uint64_t i; 1018215976Sjmallett if(!single_stepped_exc_only || state.step_isr || core == state.focus_core || state.focus_switch) 1019215976Sjmallett return; 1020215976Sjmallett 1021215976Sjmallett cvmx_debug_printf ("Core #%u spinning for focus at 0x%x\n", core, (unsigned int)depc); 1022215976Sjmallett 1023215976Sjmallett for(i = ISR_DELAY_COUNTER; i > 0 ; i--) 1024215976Sjmallett { 1025215976Sjmallett state = cvmx_debug_get_state(); 1026215976Sjmallett /* Spin giving the focus core time to service ISR */ 1027215976Sjmallett /* But cut short the loop, if we can. Shrink down i, only once. */ 1028215976Sjmallett if (i > 600000 && state.focus_switch) 1029215976Sjmallett i = 500000; 1030215976Sjmallett } 1031215976Sjmallett 1032215976Sjmallett} 1033215976Sjmallett 1034215976Sjmallettstatic int cvmx_debug_perform_proxy(cvmx_debug_register_t *debug_reg, volatile cvmx_debug_core_context_t *context) 1035215976Sjmallett{ 1036215976Sjmallett unsigned core = cvmx_get_core_num(); 1037215976Sjmallett cvmx_debug_state_t state = cvmx_debug_get_state(); 1038215976Sjmallett cvmx_debug_command_t command = COMMAND_NOP; 1039215976Sjmallett int single_stepped_exc_only = cvmx_debug_single_step_exc (debug_reg); 1040215976Sjmallett 1041215976Sjmallett /* All cores should respect the focus core if it has to 1042215976Sjmallett stop focus switching while servicing an interrupt. 1043215976Sjmallett If the system is single-stepping, then the following 1044215976Sjmallett code path is valid. If the current core tripped on a 1045215976Sjmallett break-point or some other error while going through 1046215976Sjmallett an ISR, then we shouldn't be returning unconditionally. 1047215976Sjmallett In that case (non-single-step case) we must enter 1048215976Sjmallett the debugger exception stub fully. */ 1049215976Sjmallett if (!state.step_isr && (cvmx_interrupt_in_isr || (context->cop0.status & 0x2ULL)) && single_stepped_exc_only) 1050215976Sjmallett { 1051215976Sjmallett cvmx_spinlock_lock(&cvmx_debug_globals->lock); 1052215976Sjmallett state = cvmx_debug_get_state(); 1053215976Sjmallett /* If this is the focus core, switch off focus switching 1054215976Sjmallett till ISR_DELAY_COUNTER. This will let focus core 1055215976Sjmallett keep the focus until the ISR is completed. */ 1056215976Sjmallett if(state.focus_switch && core == state.focus_core) 1057215976Sjmallett { 1058215976Sjmallett cvmx_debug_printf ("Core #%u stopped focus stealing at 0x%llx\n", core, (unsigned long long)context->cop0.depc); 1059215976Sjmallett state.focus_switch = 0; 1060215976Sjmallett } 1061215976Sjmallett /* Alow other cores to steal focus. 1062215976Sjmallett Focus core has completed ISR. */ 1063215976Sjmallett if (*(uint32_t*)((__SIZE_TYPE__)context->cop0.depc) == ERET_INSN && core == state.focus_core) 1064215976Sjmallett { 1065215976Sjmallett cvmx_debug_printf ("Core #%u resumed focus stealing at 0x%llx\n", core, (unsigned long long)context->cop0.depc); 1066215976Sjmallett state.focus_switch = 1; 1067215976Sjmallett } 1068215976Sjmallett cvmx_debug_update_state(state); 1069215976Sjmallett cvmx_spinlock_unlock(&cvmx_debug_globals->lock); 1070215976Sjmallett cvmx_debug_printf ("Core #%u resumed skipping isr.\n", core); 1071215976Sjmallett return 0; 1072215976Sjmallett } 1073215976Sjmallett 1074215976Sjmallett /* Delay the focus core a little if it is likely another core needs to 1075215976Sjmallett steal focus. Once we enter the main loop focus can't be stolen */ 1076215976Sjmallett cvmx_debug_delay_focus_core(state, core, debug_reg); 1077215976Sjmallett 1078215976Sjmallett cvmx_debug_delay_isr_core (core, context->cop0.depc, single_stepped_exc_only, state); 1079215976Sjmallett 1080215976Sjmallett /* The following section of code does two critical things. First, it 1081215976Sjmallett populates the handler_cores bitmask of all cores in the exception 1082215976Sjmallett handler. Only one core at a time can update this field. Second it 1083215976Sjmallett changes the focus core if needed. */ 1084215976Sjmallett { 1085215976Sjmallett cvmx_debug_printf("Core #%d stopped\n", core); 1086215976Sjmallett cvmx_spinlock_lock(&cvmx_debug_globals->lock); 1087215976Sjmallett state = cvmx_debug_get_state(); 1088215976Sjmallett 1089215976Sjmallett state.handler_cores |= (1 << core); 1090215976Sjmallett cvmx_debug_may_elect_as_focus_core(&state, core, debug_reg); 1091215976Sjmallett 1092215976Sjmallett/* Push all updates before exiting the critical section */ 1093215976Sjmallett state.focus_switch = 1; 1094215976Sjmallett cvmx_debug_update_state(state); 1095215976Sjmallett cvmx_spinlock_unlock(&cvmx_debug_globals->lock); 1096215976Sjmallett } 1097215976Sjmallett if (__cvmx_debug_in_focus(state, core)) 1098215976Sjmallett cvmx_debug_send_stop_reason(debug_reg, context); 1099215976Sjmallett 1100215976Sjmallett do { 1101215976Sjmallett state = cvmx_debug_get_state(); 1102215976Sjmallett /* Note the focus core can change in this loop. */ 1103215976Sjmallett if (__cvmx_debug_in_focus(state, core)) 1104215976Sjmallett { 1105215976Sjmallett command = cvmx_debug_process_next_packet(); 1106215976Sjmallett state = cvmx_debug_get_state(); 1107215976Sjmallett /* When resuming let the other cores resume as well with 1108215976Sjmallett step-all. */ 1109215976Sjmallett if (command != COMMAND_NOP && state.step_all) 1110215976Sjmallett { 1111215976Sjmallett state.command = command; 1112215976Sjmallett cvmx_debug_update_state(state); 1113215976Sjmallett } 1114215976Sjmallett } 1115215976Sjmallett /* When steping all cores, update the non focus core's command too. */ 1116215976Sjmallett else if (state.step_all) 1117215976Sjmallett command = state.command; 1118215976Sjmallett 1119215976Sjmallett /* If we did not get a command and the communication changed return, 1120215976Sjmallett we are changing the communications. */ 1121215976Sjmallett if (command == COMMAND_NOP && cvmx_debug_globals->comm_changed) 1122215976Sjmallett { 1123215976Sjmallett /* FIXME, this should a sync not based on cvmx_coremask_barrier_sync. */ 1124215976Sjmallett#ifndef CVMX_BUILD_FOR_LINUX_KERNEL 1125215976Sjmallett /* Sync up. */ 1126215976Sjmallett cvmx_coremask_barrier_sync(state.handler_cores); 1127215976Sjmallett#endif 1128215976Sjmallett return 1; 1129215976Sjmallett } 1130215976Sjmallett } while (command == COMMAND_NOP); 1131215976Sjmallett 1132215976Sjmallett debug_reg->s.sst = command == COMMAND_STEP; 1133215976Sjmallett cvmx_debug_printf("Core #%d running\n", core); 1134215976Sjmallett 1135215976Sjmallett { 1136215976Sjmallett cvmx_spinlock_lock(&cvmx_debug_globals->lock); 1137215976Sjmallett state = cvmx_debug_get_state(); 1138215976Sjmallett state.handler_cores ^= (1 << core); 1139215976Sjmallett cvmx_debug_update_state(state); 1140215976Sjmallett cvmx_spinlock_unlock(&cvmx_debug_globals->lock); 1141215976Sjmallett } 1142215976Sjmallett 1143215976Sjmallett cvmx_debug_sync_up_cores(); 1144215976Sjmallett /* Now that all cores are out, reset the command. */ 1145215976Sjmallett if (__cvmx_debug_in_focus(state, core)) 1146215976Sjmallett { 1147215976Sjmallett cvmx_spinlock_lock(&cvmx_debug_globals->lock); 1148215976Sjmallett state = cvmx_debug_get_state(); 1149215976Sjmallett state.command = COMMAND_NOP; 1150215976Sjmallett cvmx_debug_update_state(state); 1151215976Sjmallett cvmx_spinlock_unlock(&cvmx_debug_globals->lock); 1152215976Sjmallett } 1153215976Sjmallett return 0; 1154215976Sjmallett} 1155215976Sjmallett 1156215976Sjmallettstatic void cvmx_debug_save_core_context(volatile cvmx_debug_core_context_t *context) 1157215976Sjmallett{ 1158215976Sjmallett unsigned i; 1159215976Sjmallett memcpy((char *) context->regs, __cvmx_debug_save_regs_area, sizeof(context->regs)); 1160215976Sjmallett asm("mflo %0" : "=r"(context->lo)); 1161215976Sjmallett asm("mfhi %0" : "=r"(context->hi)); 1162215976Sjmallett CVMX_MF_COP0(context->cop0.index, COP0_INDEX); 1163215976Sjmallett CVMX_MF_COP0(context->cop0.entrylo[0], COP0_ENTRYLO0); 1164215976Sjmallett CVMX_MF_COP0(context->cop0.entrylo[1], COP0_ENTRYLO1); 1165215976Sjmallett CVMX_MF_COP0(context->cop0.entryhi, COP0_ENTRYHI); 1166215976Sjmallett CVMX_MF_COP0(context->cop0.pagemask, COP0_PAGEMASK); 1167215976Sjmallett CVMX_MF_COP0(context->cop0.status, COP0_STATUS); 1168215976Sjmallett CVMX_MF_COP0(context->cop0.cause, COP0_CAUSE); 1169215976Sjmallett CVMX_MF_COP0(context->cop0.debug, COP0_DEBUG); 1170215976Sjmallett CVMX_MF_COP0(context->cop0.multicoredebug, COP0_MULTICOREDEBUG); 1171215976Sjmallett CVMX_MF_COP0(context->cop0.perfval[0], COP0_PERFVALUE0); 1172215976Sjmallett CVMX_MF_COP0(context->cop0.perfval[1], COP0_PERFVALUE1); 1173215976Sjmallett CVMX_MF_COP0(context->cop0.perfctrl[0], COP0_PERFCONTROL0); 1174215976Sjmallett CVMX_MF_COP0(context->cop0.perfctrl[1], COP0_PERFCONTROL1); 1175215976Sjmallett /* Save DEPC and DESAVE since debug-mode exceptions (see 1176215976Sjmallett debug_probe_{load,store}) can clobber these. */ 1177215976Sjmallett CVMX_MF_COP0(context->cop0.depc, COP0_DEPC); 1178215976Sjmallett CVMX_MF_COP0(context->cop0.desave, COP0_DESAVE); 1179215976Sjmallett 1180215976Sjmallett context->hw_ibp.status = cvmx_read_csr(CVMX_DEBUG_HW_INSTRUCTION_BREAKPOINT_STATUS); 1181215976Sjmallett for (i = 0; i < 4; i++) 1182215976Sjmallett { 1183215976Sjmallett context->hw_ibp.address[i] = cvmx_read_csr(CVMX_DEBUG_HW_INSTRUCTION_BREAKPOINT_ADDRESS(i)); 1184215976Sjmallett context->hw_ibp.address_mask[i] = cvmx_read_csr(CVMX_DEBUG_HW_INSTRUCTION_BREAKPOINT_ADDRESS_MASK(i)); 1185215976Sjmallett context->hw_ibp.asid[i] = cvmx_read_csr(CVMX_DEBUG_HW_INSTRUCTION_BREAKPOINT_ASID(i)); 1186215976Sjmallett context->hw_ibp.control[i] = cvmx_read_csr(CVMX_DEBUG_HW_INSTRUCTION_BREAKPOINT_CONTROL(i)); 1187215976Sjmallett } 1188215976Sjmallett 1189215976Sjmallett context->hw_dbp.status = cvmx_read_csr(CVMX_DEBUG_HW_DATA_BREAKPOINT_STATUS); 1190215976Sjmallett for (i = 0; i < 4; i++) 1191215976Sjmallett { 1192215976Sjmallett context->hw_dbp.address[i] = cvmx_read_csr(CVMX_DEBUG_HW_DATA_BREAKPOINT_ADDRESS(i)); 1193215976Sjmallett context->hw_dbp.address_mask[i] = cvmx_read_csr(CVMX_DEBUG_HW_DATA_BREAKPOINT_ADDRESS_MASK(i)); 1194215976Sjmallett context->hw_dbp.asid[i] = cvmx_read_csr(CVMX_DEBUG_HW_DATA_BREAKPOINT_ASID(i)); 1195215976Sjmallett context->hw_dbp.control[i] = cvmx_read_csr(CVMX_DEBUG_HW_DATA_BREAKPOINT_CONTROL(i)); 1196215976Sjmallett } 1197215976Sjmallett 1198215976Sjmallett for (i = 0; i < cvmx_debug_globals->tlb_entries; i++) 1199215976Sjmallett { 1200215976Sjmallett CVMX_MT_COP0(i, COP0_INDEX); 1201215976Sjmallett asm volatile ("tlbr"); 1202215976Sjmallett CVMX_MF_COP0(context->tlbs[i].entrylo[0], COP0_ENTRYLO0); 1203215976Sjmallett CVMX_MF_COP0(context->tlbs[i].entrylo[1], COP0_ENTRYLO1); 1204215976Sjmallett CVMX_MF_COP0(context->tlbs[i].entryhi, COP0_ENTRYHI); 1205215976Sjmallett CVMX_MF_COP0(context->tlbs[i].pagemask, COP0_PAGEMASK); 1206215976Sjmallett } 1207215976Sjmallett CVMX_SYNCW; 1208215976Sjmallett} 1209215976Sjmallett 1210215976Sjmallettstatic void cvmx_debug_restore_core_context(volatile cvmx_debug_core_context_t *context) 1211215976Sjmallett{ 1212215976Sjmallett int i; 1213215976Sjmallett memcpy(__cvmx_debug_save_regs_area, (char *) context->regs, sizeof(context->regs)); 1214215976Sjmallett asm("mtlo %0" :: "r"(context->lo)); 1215215976Sjmallett asm("mthi %0" :: "r"(context->hi)); 1216215976Sjmallett /* We don't change the TLB so no need to restore it. */ 1217215976Sjmallett cvmx_write_csr(CVMX_DEBUG_HW_DATA_BREAKPOINT_STATUS, context->hw_dbp.status); 1218215976Sjmallett for (i = 0; i < 4; i++) 1219215976Sjmallett { 1220215976Sjmallett cvmx_write_csr(CVMX_DEBUG_HW_DATA_BREAKPOINT_ADDRESS(i), context->hw_dbp.address[i]); 1221215976Sjmallett cvmx_write_csr(CVMX_DEBUG_HW_DATA_BREAKPOINT_ADDRESS_MASK(i), context->hw_dbp.address_mask[i]); 1222215976Sjmallett cvmx_write_csr(CVMX_DEBUG_HW_DATA_BREAKPOINT_ASID(i), context->hw_dbp.asid[i]); 1223215976Sjmallett cvmx_write_csr(CVMX_DEBUG_HW_DATA_BREAKPOINT_CONTROL(i), context->hw_dbp.control[i]); 1224215976Sjmallett } 1225215976Sjmallett cvmx_write_csr(CVMX_DEBUG_HW_INSTRUCTION_BREAKPOINT_STATUS, context->hw_ibp.status); 1226215976Sjmallett for (i = 0; i < 4; i++) 1227215976Sjmallett { 1228215976Sjmallett cvmx_write_csr(CVMX_DEBUG_HW_INSTRUCTION_BREAKPOINT_ADDRESS(i), context->hw_ibp.address[i]); 1229215976Sjmallett cvmx_write_csr(CVMX_DEBUG_HW_INSTRUCTION_BREAKPOINT_ADDRESS_MASK(i), context->hw_ibp.address_mask[i]); 1230215976Sjmallett cvmx_write_csr(CVMX_DEBUG_HW_INSTRUCTION_BREAKPOINT_ASID(i), context->hw_ibp.asid[i]); 1231215976Sjmallett cvmx_write_csr(CVMX_DEBUG_HW_INSTRUCTION_BREAKPOINT_CONTROL(i), context->hw_ibp.control[i]); 1232215976Sjmallett } 1233215976Sjmallett CVMX_MT_COP0(context->cop0.index, COP0_INDEX); 1234215976Sjmallett CVMX_MT_COP0(context->cop0.entrylo[0], COP0_ENTRYLO0); 1235215976Sjmallett CVMX_MT_COP0(context->cop0.entrylo[1], COP0_ENTRYLO1); 1236215976Sjmallett CVMX_MT_COP0(context->cop0.entryhi, COP0_ENTRYHI); 1237215976Sjmallett CVMX_MT_COP0(context->cop0.pagemask, COP0_PAGEMASK); 1238215976Sjmallett CVMX_MT_COP0(context->cop0.status, COP0_STATUS); 1239215976Sjmallett CVMX_MT_COP0(context->cop0.cause, COP0_CAUSE); 1240215976Sjmallett CVMX_MT_COP0(context->cop0.debug, COP0_DEBUG); 1241215976Sjmallett CVMX_MT_COP0(context->cop0.multicoredebug, COP0_MULTICOREDEBUG); 1242215976Sjmallett CVMX_MT_COP0(context->cop0.perfval[0], COP0_PERFVALUE0); 1243215976Sjmallett CVMX_MT_COP0(context->cop0.perfval[1], COP0_PERFVALUE1); 1244215976Sjmallett CVMX_MT_COP0(context->cop0.perfctrl[0], COP0_PERFCONTROL0); 1245215976Sjmallett CVMX_MT_COP0(context->cop0.perfctrl[1], COP0_PERFCONTROL1); 1246215976Sjmallett CVMX_MT_COP0(context->cop0.depc, COP0_DEPC); 1247215976Sjmallett CVMX_MT_COP0(context->cop0.desave, COP0_DESAVE); 1248215976Sjmallett} 1249215976Sjmallett 1250215976Sjmallettstatic inline void cvmx_debug_print_cause(volatile cvmx_debug_core_context_t *context) 1251215976Sjmallett{ 1252215976Sjmallett if (!CVMX_DEBUG_LOGGING) 1253215976Sjmallett return; 1254215976Sjmallett if (context->cop0.multicoredebug & 1) 1255215976Sjmallett cvmx_dprintf("MCD0 was pulsed\n"); 1256215976Sjmallett if (context->cop0.multicoredebug & (1 << 16)) 1257215976Sjmallett cvmx_dprintf("Exception %lld in Debug Mode\n", (long long)((context->cop0.debug >> 10) & 0x1f)); 1258215976Sjmallett if (context->cop0.debug & (1 << 19)) 1259215976Sjmallett cvmx_dprintf("DDBSImpr\n"); 1260215976Sjmallett if (context->cop0.debug & (1 << 18)) 1261215976Sjmallett cvmx_dprintf("DDBLImpr\n"); 1262215976Sjmallett if (context->cop0.debug & (1 << 5)) 1263215976Sjmallett cvmx_dprintf("DINT\n"); 1264215976Sjmallett if (context->cop0.debug & (1 << 4)) 1265215976Sjmallett cvmx_dprintf("Debug Instruction Breakpoint (DIB) exception\n"); 1266215976Sjmallett if (context->cop0.debug & (1 << 3)) 1267215976Sjmallett cvmx_dprintf("Debug Date Break Store (DDBS) exception\n"); 1268215976Sjmallett if (context->cop0.debug & (1 << 2)) 1269215976Sjmallett cvmx_dprintf("Debug Date Break Load (DDBL) exception\n"); 1270215976Sjmallett if (context->cop0.debug & (1 << 1)) 1271215976Sjmallett cvmx_dprintf("Debug Breakpoint (DBp) exception\n"); 1272215976Sjmallett if (context->cop0.debug & (1 << 0)) 1273215976Sjmallett cvmx_dprintf("Debug Single Step (DSS) exception\n"); 1274215976Sjmallett} 1275215976Sjmallett 1276215976Sjmallettvoid __cvmx_debug_handler_stage3 (void) 1277215976Sjmallett{ 1278215976Sjmallett volatile cvmx_debug_core_context_t *context; 1279215976Sjmallett int comms_changed = 0; 1280215976Sjmallett 1281215976Sjmallett cvmx_debug_printf("Entering debug exception handler\n"); 1282215976Sjmallett cvmx_debug_printf("Debug named block at %p\n", cvmx_debug_globals); 1283215976Sjmallett if (__cvmx_debug_mode_exception_occured) 1284215976Sjmallett { 1285215976Sjmallett uint64_t depc; 1286215976Sjmallett CVMX_MF_COP0(depc, COP0_DEPC); 1287215976Sjmallett cvmx_dprintf("Unexpected debug-mode exception occured at 0x%llx, 0x%llx spinning\n", (long long) depc, (long long)(__cvmx_debug_mode_exception_occured)); 1288215976Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 1289215976Sjmallett panic("Unexpected debug-mode exception occured at 0x%llx, 0x%llx\n", (long long) depc, (long long)(__cvmx_debug_mode_exception_occured)); 1290215976Sjmallett#endif 1291215976Sjmallett while (1) 1292215976Sjmallett ; 1293215976Sjmallett } 1294215976Sjmallett 1295215976Sjmallett context = cvmx_debug_core_context(); 1296215976Sjmallett cvmx_debug_save_core_context(context); 1297215976Sjmallett 1298215976Sjmallett { 1299215976Sjmallett cvmx_debug_state_t state; 1300215976Sjmallett cvmx_spinlock_lock(&cvmx_debug_globals->lock); 1301215976Sjmallett state = cvmx_debug_get_state(); 1302215976Sjmallett state.ever_been_in_debug = 1; 1303215976Sjmallett cvmx_debug_update_state (state); 1304215976Sjmallett cvmx_spinlock_unlock(&cvmx_debug_globals->lock); 1305215976Sjmallett } 1306215976Sjmallett cvmx_debug_print_cause(context); 1307215976Sjmallett 1308215976Sjmallett do 1309215976Sjmallett { 1310215976Sjmallett int needs_proxy; 1311215976Sjmallett comms_changed = 0; 1312215976Sjmallett /* If the communication changes, change it. */ 1313215976Sjmallett cvmx_spinlock_lock(&cvmx_debug_globals->lock); 1314215976Sjmallett if (cvmx_debug_globals->comm_changed) 1315215976Sjmallett { 1316215976Sjmallett cvmx_debug_printf("Communication changed: %d\n", (int)cvmx_debug_globals->comm_changed); 1317215976Sjmallett if (cvmx_debug_globals->comm_changed > COMM_SIZE) 1318215976Sjmallett { 1319215976Sjmallett cvmx_dprintf("Unknown communication spinning: %lld > %d.\n", (long long)cvmx_debug_globals->comm_changed, (int)(COMM_SIZE)); 1320215976Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 1321215976Sjmallett panic("Unknown communication.\n"); 1322215976Sjmallett#endif 1323215976Sjmallett while (1) 1324215976Sjmallett ; 1325215976Sjmallett } 1326215976Sjmallett cvmx_debug_globals->comm_type = cvmx_debug_globals->comm_changed - 1; 1327215976Sjmallett cvmx_debug_globals->comm_changed = 0; 1328215976Sjmallett } 1329215976Sjmallett cvmx_spinlock_unlock(&cvmx_debug_globals->lock); 1330215976Sjmallett needs_proxy = cvmx_debug_comms[cvmx_debug_globals->comm_type]->needs_proxy; 1331215976Sjmallett 1332215976Sjmallett { 1333215976Sjmallett cvmx_debug_register_t debug_reg; 1334215976Sjmallett cvmx_debug_state_t state; 1335215976Sjmallett unsigned core = cvmx_get_core_num(); 1336215976Sjmallett 1337215976Sjmallett state = cvmx_debug_get_state(); 1338215976Sjmallett debug_reg.u64 = context->cop0.debug; 1339215976Sjmallett /* All cores stop on any exception. See if we want nothing from this and 1340215976Sjmallett it should resume. This needs to be done for non proxy based debugging 1341215976Sjmallett so that some non active-cores can control the other cores. */ 1342215976Sjmallett if (!cvmx_debug_stop_core(state, core, &debug_reg, needs_proxy)) 1343215976Sjmallett { 1344215976Sjmallett context->cop0.debug = debug_reg.u64; 1345215976Sjmallett break; 1346215976Sjmallett } 1347215976Sjmallett } 1348215976Sjmallett 1349215976Sjmallett if (needs_proxy) 1350215976Sjmallett { 1351215976Sjmallett cvmx_debug_register_t debug_reg; 1352215976Sjmallett debug_reg.u64 = context->cop0.debug; 1353215976Sjmallett cvmx_debug_printf("Starting to proxy\n"); 1354215976Sjmallett comms_changed = cvmx_debug_perform_proxy(&debug_reg, context); 1355215976Sjmallett context->cop0.debug = debug_reg.u64; 1356215976Sjmallett } 1357215976Sjmallett else 1358215976Sjmallett { 1359215976Sjmallett cvmx_debug_printf("Starting to wait for remote host\n"); 1360215976Sjmallett cvmx_debug_comms[cvmx_debug_globals->comm_type]->wait_for_resume(context, cvmx_debug_get_state()); 1361215976Sjmallett } 1362215976Sjmallett } while (comms_changed); 1363215976Sjmallett 1364215976Sjmallett cvmx_debug_clear_status(context); 1365215976Sjmallett 1366215976Sjmallett cvmx_debug_restore_core_context(context); 1367215976Sjmallett cvmx_debug_printf("Exiting debug exception handler\n"); 1368215976Sjmallett} 1369215976Sjmallett 1370215976Sjmallettvoid cvmx_debug_trigger_exception(void) 1371215976Sjmallett{ 1372215976Sjmallett /* Set CVMX_CIU_DINT to enter debug exception handler. */ 1373215976Sjmallett cvmx_write_csr (CVMX_CIU_DINT, 1 << cvmx_get_core_num ()); 1374215976Sjmallett /* Perform an immediate read after every write to an RSL register to force 1375215976Sjmallett the write to complete. It doesn't matter what RSL read we do, so we 1376215976Sjmallett choose CVMX_MIO_BOOT_BIST_STAT because it is fast and harmless */ 1377215976Sjmallett cvmx_read_csr (CVMX_MIO_BOOT_BIST_STAT); 1378215976Sjmallett} 1379215976Sjmallett 1380215976Sjmallett/** 1381215976Sjmallett * Inform debugger about the end of the program. This is 1382215976Sjmallett * called from crt0 after all the C cleanup code finishes. 1383215976Sjmallett * Our current stack is the C one, not the debug exception 1384215976Sjmallett * stack. */ 1385215976Sjmallettvoid cvmx_debug_finish(void) 1386215976Sjmallett{ 1387215976Sjmallett unsigned coreid = cvmx_get_core_num(); 1388215976Sjmallett cvmx_debug_state_t state; 1389215976Sjmallett 1390215976Sjmallett cvmx_debug_printf ("Debug _exit reached!, core %d, cvmx_debug_globals = %p\n", coreid, cvmx_debug_globals); 1391215976Sjmallett 1392215976Sjmallett#ifndef CVMX_BUILD_FOR_LINUX_KERNEL 1393215976Sjmallett fflush (stdout); 1394215976Sjmallett fflush (stderr); 1395215976Sjmallett#endif 1396215976Sjmallett 1397215976Sjmallett cvmx_spinlock_lock(&cvmx_debug_globals->lock); 1398215976Sjmallett state = cvmx_debug_get_state(); 1399215976Sjmallett state.known_cores ^= (1 << coreid); 1400215976Sjmallett state.core_finished |= (1<<coreid); 1401215976Sjmallett cvmx_debug_update_state(state); 1402215976Sjmallett 1403215976Sjmallett /* Tell the user the core has finished. */ 1404215976Sjmallett if (state.ever_been_in_debug) 1405215976Sjmallett cvmx_debug_putpacket("!Core %d finish.", coreid); 1406215976Sjmallett 1407215976Sjmallett /* Notify the debugger if all cores have completed the program */ 1408215976Sjmallett if ((cvmx_debug_core_mask () & state.core_finished) == cvmx_debug_core_mask ()) 1409215976Sjmallett { 1410215976Sjmallett cvmx_debug_printf("All cores done!\n"); 1411215976Sjmallett if (state.ever_been_in_debug) 1412215976Sjmallett cvmx_debug_putpacket_noformat("D0"); 1413215976Sjmallett } 1414215976Sjmallett if (state.focus_core == coreid && state.known_cores != 0) 1415215976Sjmallett { 1416215976Sjmallett /* Loop through cores looking for someone to handle interrupts. 1417215976Sjmallett Since we already check that known_cores is non zero, this 1418215976Sjmallett should always find a core */ 1419215976Sjmallett unsigned newcore; 1420215976Sjmallett for (newcore = 0; newcore < CVMX_DEBUG_MAX_CORES; newcore++) 1421215976Sjmallett { 1422215976Sjmallett if (state.known_cores & (1<<newcore)) 1423215976Sjmallett { 1424215976Sjmallett cvmx_debug_printf("Routing uart interrupts to Core #%u.\n", newcore); 1425215976Sjmallett cvmx_debug_set_focus_core(&state, newcore); 1426215976Sjmallett cvmx_debug_update_state(state); 1427215976Sjmallett break; 1428215976Sjmallett } 1429215976Sjmallett } 1430215976Sjmallett } 1431215976Sjmallett cvmx_spinlock_unlock(&cvmx_debug_globals->lock); 1432215976Sjmallett 1433215976Sjmallett /* If we ever been in the debug, report to it that we have exited the core. */ 1434215976Sjmallett if (state.ever_been_in_debug) 1435215976Sjmallett cvmx_debug_trigger_exception(); 1436215976Sjmallett} 1437