1215976Sjmallett/***********************license start*************** 2232812Sjmallett * Copyright (c) 2003-2010 Cavium Inc. (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 18232812Sjmallett * * Neither the name of Cavium Inc. 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" 29232812Sjmallett * AND WITH ALL FAULTS AND CAVIUM INC. 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 45232812Sjmallett * NOTE: CARE SHOULD BE TAKE WHEN USING STD C LIBRARY FUNCTIONS IN 46232812Sjmallett * THIS FILE IF SOMEONE PUTS A BREAKPOINT ON THOSE FUNCTIONS 47232812Sjmallett * DEBUGGING WILL FAIL. 48215976Sjmallett * 49215976Sjmallett * <hr>$Revision: 50060 $<hr> 50215976Sjmallett */ 51215976Sjmallett 52215976Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 53215976Sjmallett#include <linux/module.h> 54215976Sjmallett#include <asm/octeon/octeon.h> 55215976Sjmallett#include <asm/octeon/cvmx.h> 56215976Sjmallett#include <asm/octeon/cvmx-debug.h> 57215976Sjmallett#include <asm/octeon/cvmx-core.h> 58215976Sjmallett#include <asm/octeon/cvmx-bootmem.h> 59215976Sjmallett#include <asm/octeon/octeon-boot-info.h> 60215976Sjmallett#else 61215976Sjmallett#include <stdint.h> 62215976Sjmallett#include "cvmx.h" 63215976Sjmallett#include "cvmx-debug.h" 64215976Sjmallett#include "cvmx-bootmem.h" 65215976Sjmallett#include "cvmx-core.h" 66215976Sjmallett#include "cvmx-coremask.h" 67215976Sjmallett#include "octeon-boot-info.h" 68215976Sjmallett#endif 69215976Sjmallett 70215976Sjmallett#ifdef CVMX_DEBUG_LOGGING 71215976Sjmallett# undef CVMX_DEBUG_LOGGING 72215976Sjmallett# define CVMX_DEBUG_LOGGING 1 73215976Sjmallett#else 74215976Sjmallett# define CVMX_DEBUG_LOGGING 0 75215976Sjmallett#endif 76215976Sjmallett 77215976Sjmallett#ifndef CVMX_DEBUG_ATTACH 78215976Sjmallett# define CVMX_DEBUG_ATTACH 1 79215976Sjmallett#endif 80215976Sjmallett 81215976Sjmallett#define CVMX_DEBUG_HW_INSTRUCTION_BREAKPOINT_STATUS (0xFFFFFFFFFF301000ull) 82215976Sjmallett#define CVMX_DEBUG_HW_INSTRUCTION_BREAKPOINT_ADDRESS(num) (0xFFFFFFFFFF301100ull + 0x100 * (num)) 83215976Sjmallett#define CVMX_DEBUG_HW_INSTRUCTION_BREAKPOINT_ADDRESS_MASK(num) (0xFFFFFFFFFF301108ull + 0x100 * (num)) 84215976Sjmallett#define CVMX_DEBUG_HW_INSTRUCTION_BREAKPOINT_ASID(num) (0xFFFFFFFFFF301110ull + 0x100 * (num)) 85215976Sjmallett#define CVMX_DEBUG_HW_INSTRUCTION_BREAKPOINT_CONTROL(num) (0xFFFFFFFFFF301118ull + 0x100 * (num)) 86215976Sjmallett 87215976Sjmallett#define CVMX_DEBUG_HW_DATA_BREAKPOINT_STATUS (0xFFFFFFFFFF302000ull) 88215976Sjmallett#define CVMX_DEBUG_HW_DATA_BREAKPOINT_ADDRESS(num) (0xFFFFFFFFFF302100ull + 0x100 * (num)) 89215976Sjmallett#define CVMX_DEBUG_HW_DATA_BREAKPOINT_ADDRESS_MASK(num) (0xFFFFFFFFFF302108ull + 0x100 * (num)) 90215976Sjmallett#define CVMX_DEBUG_HW_DATA_BREAKPOINT_ASID(num) (0xFFFFFFFFFF302110ull + 0x100 * (num)) 91215976Sjmallett#define CVMX_DEBUG_HW_DATA_BREAKPOINT_CONTROL(num) (0xFFFFFFFFFF302118ull + 0x100 * (num)) 92215976Sjmallett 93215976Sjmallett#define ERET_INSN 0x42000018U /* Hexcode for eret */ 94215976Sjmallett#define ISR_DELAY_COUNTER 120000000 /* Could be tuned down */ 95215976Sjmallett 96215976Sjmallettextern cvmx_debug_comm_t cvmx_debug_uart_comm; 97215976Sjmallettextern cvmx_debug_comm_t cvmx_debug_remote_comm; 98215976Sjmallettstatic const cvmx_debug_comm_t *cvmx_debug_comms[COMM_SIZE] = {&cvmx_debug_uart_comm, &cvmx_debug_remote_comm}; 99215976Sjmallett 100215976Sjmallett 101215976Sjmallett 102215976Sjmallettstatic cvmx_debug_globals_t *cvmx_debug_globals; 103215976Sjmallett 104215976Sjmallett/** 105215976Sjmallett * @file 106215976Sjmallett * 107215976Sjmallett */ 108215976Sjmallett 109215976Sjmallett#ifndef CVMX_BUILD_FOR_LINUX_KERNEL 110215976Sjmallettuint64_t __cvmx_debug_save_regs_area[32]; 111215976Sjmallett 112215976Sjmallettvolatile uint64_t __cvmx_debug_mode_exception_ignore; 113215976Sjmallettvolatile uint64_t __cvmx_debug_mode_exception_occured; 114215976Sjmallett 115215976Sjmallettstatic char cvmx_debug_stack[8*1024] __attribute ((aligned (16))); 116215976Sjmallettchar *__cvmx_debug_stack_top = &cvmx_debug_stack[8*1024]; 117215976Sjmallett 118232812Sjmallett#ifndef CVMX_BUILD_FOR_TOOLCHAIN 119215976Sjmallettextern int cvmx_interrupt_in_isr; 120215976Sjmallett#else 121215976Sjmallett#define cvmx_interrupt_in_isr 0 122215976Sjmallett#endif 123215976Sjmallett 124215976Sjmallett#else 125232812Sjmallettuint64_t __cvmx_debug_save_regs_area_all[CVMX_MAX_CORES][32]; 126215976Sjmallett#define __cvmx_debug_save_regs_area __cvmx_debug_save_regs_area_all[cvmx_get_core_num()] 127215976Sjmallett 128232812Sjmallettvolatile uint64_t __cvmx_debug_mode_exception_ignore_all[CVMX_MAX_CORES]; 129215976Sjmallett#define __cvmx_debug_mode_exception_ignore __cvmx_debug_mode_exception_ignore_all[cvmx_get_core_num()] 130232812Sjmallettvolatile uint64_t __cvmx_debug_mode_exception_occured_all[CVMX_MAX_CORES]; 131215976Sjmallett#define __cvmx_debug_mode_exception_occured __cvmx_debug_mode_exception_occured_all[cvmx_get_core_num()] 132215976Sjmallett 133232812Sjmallettstatic char cvmx_debug_stack_all[CVMX_MAX_CORES][8*1024] __attribute ((aligned (16))); 134232812Sjmallettchar *__cvmx_debug_stack_top_all[CVMX_MAX_CORES]; 135215976Sjmallett 136215976Sjmallett#define cvmx_interrupt_in_isr 0 137215976Sjmallett 138215976Sjmallett#endif 139215976Sjmallett 140215976Sjmallett 141232812Sjmallettstatic size_t cvmx_debug_strlen (const char *str) 142232812Sjmallett{ 143232812Sjmallett size_t size = 0; 144232812Sjmallett while (*str) 145232812Sjmallett { 146232812Sjmallett size++; 147232812Sjmallett str++; 148232812Sjmallett } 149232812Sjmallett return size; 150232812Sjmallett} 151232812Sjmallettstatic void cvmx_debug_strcpy (char *dest, const char *src) 152232812Sjmallett{ 153232812Sjmallett while (*src) 154232812Sjmallett { 155232812Sjmallett *dest = *src; 156232812Sjmallett src++; 157232812Sjmallett dest++; 158232812Sjmallett } 159232812Sjmallett *dest = 0; 160232812Sjmallett} 161232812Sjmallett 162232812Sjmallettstatic void cvmx_debug_memcpy_align (void *dest, const void *src, int size) __attribute__ ((__noinline__)); 163232812Sjmallettstatic void cvmx_debug_memcpy_align (void *dest, const void *src, int size) 164232812Sjmallett{ 165232812Sjmallett long long *dest1 = (long long*)dest; 166232812Sjmallett const long long *src1 = (const long long*)src; 167232812Sjmallett int i; 168232812Sjmallett if (size == 40) 169232812Sjmallett { 170232812Sjmallett long long a0, a1, a2, a3, a4; 171232812Sjmallett a0 = src1[0]; 172232812Sjmallett a1 = src1[1]; 173232812Sjmallett a2 = src1[2]; 174232812Sjmallett a3 = src1[3]; 175232812Sjmallett a4 = src1[4]; 176232812Sjmallett dest1[0] = a0; 177232812Sjmallett dest1[1] = a1; 178232812Sjmallett dest1[2] = a2; 179232812Sjmallett dest1[3] = a3; 180232812Sjmallett dest1[4] = a4; 181232812Sjmallett return; 182232812Sjmallett } 183232812Sjmallett for(i = 0;i < size;i+=8) 184232812Sjmallett { 185232812Sjmallett *dest1 = *src1; 186232812Sjmallett dest1++; 187232812Sjmallett src1++; 188232812Sjmallett } 189232812Sjmallett} 190232812Sjmallett 191232812Sjmallett 192215976Sjmallettstatic inline uint32_t cvmx_debug_core_mask(void) 193215976Sjmallett{ 194215976Sjmallett#ifndef CVMX_BUILD_FOR_LINUX_KERNEL 195232812Sjmallett#ifdef CVMX_BUILD_FOR_TOOLCHAIN 196215976Sjmallett extern int __octeon_core_mask; 197215976Sjmallett return __octeon_core_mask; 198215976Sjmallett#endif 199215976Sjmallettreturn cvmx_sysinfo_get()->core_mask; 200215976Sjmallett#else 201215976Sjmallettreturn octeon_get_boot_coremask (); 202215976Sjmallett#endif 203215976Sjmallett} 204215976Sjmallett 205215976Sjmallettstatic inline void cvmx_debug_update_state(cvmx_debug_state_t state) 206215976Sjmallett{ 207232812Sjmallett cvmx_debug_memcpy_align(cvmx_debug_globals->state, &state, sizeof(cvmx_debug_state_t)); 208215976Sjmallett} 209215976Sjmallett 210215976Sjmallettstatic inline cvmx_debug_state_t cvmx_debug_get_state(void) 211215976Sjmallett{ 212215976Sjmallett cvmx_debug_state_t state; 213232812Sjmallett cvmx_debug_memcpy_align(&state, cvmx_debug_globals->state, sizeof(cvmx_debug_state_t)); 214215976Sjmallett return state; 215215976Sjmallett} 216215976Sjmallett 217215976Sjmallettstatic void cvmx_debug_printf(char *format, ...) __attribute__((format(__printf__, 1, 2))); 218215976Sjmallettstatic void cvmx_debug_printf(char *format, ...) 219215976Sjmallett{ 220215976Sjmallett va_list ap; 221215976Sjmallett 222215976Sjmallett if (!CVMX_DEBUG_LOGGING) 223215976Sjmallett return; 224215976Sjmallett 225215976Sjmallett va_start(ap, format); 226215976Sjmallett cvmx_dvprintf(format, ap); 227215976Sjmallett va_end(ap); 228215976Sjmallett} 229215976Sjmallett 230215976Sjmallettstatic inline int __cvmx_debug_in_focus(cvmx_debug_state_t state, unsigned core) 231215976Sjmallett{ 232215976Sjmallett return state.focus_core == core; 233215976Sjmallett} 234215976Sjmallett 235215976Sjmallettstatic void cvmx_debug_install_handler(unsigned core) 236215976Sjmallett{ 237215976Sjmallett extern void __cvmx_debug_handler_stage2(void); 238215976Sjmallett int32_t *trampoline = CASTPTR(int32_t, CVMX_ADD_SEG32(CVMX_MIPS32_SPACE_KSEG0, BOOTLOADER_DEBUG_TRAMPOLINE_CORE)); 239215976Sjmallett trampoline += core; 240215976Sjmallett 241215976Sjmallett *trampoline = (int32_t)(long)&__cvmx_debug_handler_stage2; 242215976Sjmallett 243215976Sjmallett cvmx_debug_printf("Debug handled installed on core %d at %p\n", core, trampoline); 244215976Sjmallett} 245215976Sjmallett 246215976Sjmallettstatic int cvmx_debug_enabled(void) 247215976Sjmallett{ 248215976Sjmallett return cvmx_debug_booted() || CVMX_DEBUG_ATTACH; 249215976Sjmallett} 250215976Sjmallett 251232812Sjmallettstatic void cvmx_debug_init_global_ptr (void *ptr) 252232812Sjmallett{ 253232812Sjmallett uint64_t phys = cvmx_ptr_to_phys (ptr); 254232812Sjmallett cvmx_debug_globals_t *p; 255232812Sjmallett /* Since at this point, TLBs are not mapped 1 to 1, we should just use KSEG0 accesses. */ 256232812Sjmallett p = CASTPTR(cvmx_debug_globals_t, CVMX_ADD_SEG32(CVMX_MIPS32_SPACE_KSEG0, phys)); 257232812Sjmallett memset (p, 0, sizeof(cvmx_debug_globals_t)); 258232812Sjmallett p->version = CVMX_DEBUG_GLOBALS_VERSION; 259232812Sjmallett p->tlb_entries = cvmx_core_get_tlb_entries(); 260232812Sjmallett} 261232812Sjmallett 262215976Sjmallettstatic void cvmx_debug_init_globals(void) 263215976Sjmallett{ 264215976Sjmallett uint64_t phys; 265232812Sjmallett void *ptr; 266215976Sjmallett 267215976Sjmallett if (cvmx_debug_globals) 268215976Sjmallett return; 269232812Sjmallett ptr = cvmx_bootmem_alloc_named_range_once(sizeof(cvmx_debug_globals_t), 0, /* KSEG0 max, 512MB=*/0/*1024*1024*512*/, 8, 270232812Sjmallett CVMX_DEBUG_GLOBALS_BLOCK_NAME, cvmx_debug_init_global_ptr); 271232812Sjmallett phys = cvmx_ptr_to_phys (ptr); 272215976Sjmallett 273232812Sjmallett /* Since TLBs are not always mapped 1 to 1, we should just use access via KSEG0. */ 274215976Sjmallett cvmx_debug_globals = CASTPTR(cvmx_debug_globals_t, CVMX_ADD_SEG32(CVMX_MIPS32_SPACE_KSEG0, phys)); 275215976Sjmallett cvmx_debug_printf("Debug named block at %p\n", cvmx_debug_globals); 276215976Sjmallett} 277215976Sjmallett 278215976Sjmallett 279215976Sjmallettstatic void cvmx_debug_globals_check_version(void) 280215976Sjmallett{ 281215976Sjmallett if (cvmx_debug_globals->version != CVMX_DEBUG_GLOBALS_VERSION) 282215976Sjmallett { 283215976Sjmallett cvmx_dprintf("Wrong version on the globals struct spinining; expected %d, got: %d.\n", (int)CVMX_DEBUG_GLOBALS_VERSION, (int)(cvmx_debug_globals->version)); 284215976Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 285215976Sjmallett panic("Wrong version.\n"); 286215976Sjmallett#endif 287215976Sjmallett while (1) 288215976Sjmallett ; 289215976Sjmallett } 290215976Sjmallett} 291215976Sjmallett 292215976Sjmallettstatic inline volatile cvmx_debug_core_context_t *cvmx_debug_core_context(void); 293232812Sjmallettstatic inline void cvmx_debug_save_core_context(volatile cvmx_debug_core_context_t *context, uint64_t hi, uint64_t lo); 294215976Sjmallett 295215976Sjmallettvoid cvmx_debug_init(void) 296215976Sjmallett{ 297215976Sjmallett cvmx_debug_state_t state; 298215976Sjmallett int core; 299215976Sjmallett const cvmx_debug_comm_t *comm; 300215976Sjmallett cvmx_spinlock_t *lock; 301215976Sjmallett unsigned int coremask = cvmx_debug_core_mask(); 302215976Sjmallett 303215976Sjmallett if (!cvmx_debug_enabled()) 304215976Sjmallett return; 305215976Sjmallett 306215976Sjmallett cvmx_debug_init_globals(); 307215976Sjmallett 308215976Sjmallett#ifndef CVMX_BUILD_FOR_LINUX_KERNEL 309215976Sjmallett // Put a barrier until all cores have got to this point. 310215976Sjmallett cvmx_coremask_barrier_sync(coremask); 311215976Sjmallett#endif 312215976Sjmallett cvmx_debug_globals_check_version(); 313215976Sjmallett 314215976Sjmallett 315215976Sjmallett comm = cvmx_debug_comms[cvmx_debug_globals->comm_type]; 316215976Sjmallett lock = &cvmx_debug_globals->lock; 317215976Sjmallett 318215976Sjmallett core = cvmx_get_core_num(); 319215976Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 320215976Sjmallett /* Install the debugger handler on the cores. */ 321215976Sjmallett { 322215976Sjmallett int core1 = 0; 323232812Sjmallett for (core1 = 0; core1 < CVMX_MAX_CORES; core1++) 324215976Sjmallett { 325232812Sjmallett if ((1u<<core1) & coremask) 326215976Sjmallett cvmx_debug_install_handler(core1); 327215976Sjmallett } 328215976Sjmallett } 329215976Sjmallett#else 330215976Sjmallett cvmx_debug_install_handler(core); 331215976Sjmallett#endif 332215976Sjmallett 333215976Sjmallett if (comm->init) 334215976Sjmallett comm->init(); 335215976Sjmallett 336215976Sjmallett { 337215976Sjmallett cvmx_spinlock_lock(lock); 338215976Sjmallett state = cvmx_debug_get_state(); 339215976Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 340215976Sjmallett state.known_cores |= coremask; 341215976Sjmallett state.core_finished &= ~coremask; 342215976Sjmallett#else 343232812Sjmallett state.known_cores |= (1u << core); 344232812Sjmallett state.core_finished &= ~(1u << core); 345215976Sjmallett#endif 346215976Sjmallett cvmx_debug_update_state(state); 347215976Sjmallett cvmx_spinlock_unlock(lock); 348215976Sjmallett } 349215976Sjmallett 350215976Sjmallett#ifndef CVMX_BUILD_FOR_LINUX_KERNEL 351215976Sjmallett // Put a barrier until all cores have got to this point. 352215976Sjmallett cvmx_coremask_barrier_sync(coremask); 353215976Sjmallett 354215976Sjmallett if (cvmx_coremask_first_core(coremask)) 355215976Sjmallett#endif 356215976Sjmallett { 357215976Sjmallett cvmx_debug_printf("cvmx_debug_init core: %d\n", core); 358215976Sjmallett state = cvmx_debug_get_state(); 359215976Sjmallett state.focus_core = core; 360215976Sjmallett state.active_cores = state.known_cores; 361215976Sjmallett state.focus_switch = 1; 362215976Sjmallett state.step_isr = 1; 363215976Sjmallett cvmx_debug_printf("Known cores at init: 0x%x\n", (int)state.known_cores); 364215976Sjmallett cvmx_debug_update_state(state); 365215976Sjmallett 366215976Sjmallett /* Initialize __cvmx_debug_stack_top_all. */ 367215976Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 368215976Sjmallett { 369215976Sjmallett int i; 370232812Sjmallett for (i = 0; i < CVMX_MAX_CORES; i++) 371215976Sjmallett __cvmx_debug_stack_top_all[i] = &cvmx_debug_stack_all[i][8*1024]; 372215976Sjmallett } 373215976Sjmallett#endif 374215976Sjmallett cvmx_debug_globals->init_complete = 1; 375215976Sjmallett CVMX_SYNCW; 376215976Sjmallett } 377215976Sjmallett while (!cvmx_debug_globals->init_complete) 378215976Sjmallett { 379215976Sjmallett /* Spin waiting for init to complete */ 380215976Sjmallett } 381215976Sjmallett 382215976Sjmallett if (cvmx_debug_booted()) 383215976Sjmallett cvmx_debug_trigger_exception(); 384215976Sjmallett 385215976Sjmallett /* Install the break handler after might tripper the debugger exception. */ 386215976Sjmallett#ifndef CVMX_BUILD_FOR_LINUX_KERNEL 387215976Sjmallett if (cvmx_coremask_first_core(coremask)) 388215976Sjmallett#endif 389215976Sjmallett { 390215976Sjmallett if (comm->install_break_handler) 391215976Sjmallett comm->install_break_handler(); 392215976Sjmallett } 393215976Sjmallett} 394215976Sjmallett 395232812Sjmallettstatic const char cvmx_debug_hexchar[] = "0123456789ABCDEF"; 396232812Sjmallett/* Put the hex value of t into str. */ 397232812Sjmallettstatic void cvmx_debug_int8_to_strhex(char *str, unsigned char t) 398232812Sjmallett{ 399232812Sjmallett str[0] = cvmx_debug_hexchar[(t>>4)&0xf]; 400232812Sjmallett str[1] = cvmx_debug_hexchar[t&0xF]; 401232812Sjmallett str[2] = 0; 402232812Sjmallett} 403215976Sjmallett 404232812Sjmallettstatic void cvmx_debug_int64_to_strhex(char *str, uint64_t t) 405215976Sjmallett{ 406232812Sjmallett str[0] = cvmx_debug_hexchar[(t>>60)&0xF]; 407232812Sjmallett str[1] = cvmx_debug_hexchar[(t>>56)&0xF]; 408232812Sjmallett str[2] = cvmx_debug_hexchar[(t>>52)&0xF]; 409232812Sjmallett str[3] = cvmx_debug_hexchar[(t>>48)&0xF]; 410232812Sjmallett str[4] = cvmx_debug_hexchar[(t>>44)&0xF]; 411232812Sjmallett str[5] = cvmx_debug_hexchar[(t>>40)&0xF]; 412232812Sjmallett str[6] = cvmx_debug_hexchar[(t>>36)&0xF]; 413232812Sjmallett str[7] = cvmx_debug_hexchar[(t>>32)&0xF]; 414232812Sjmallett str[8] = cvmx_debug_hexchar[(t>>28)&0xF]; 415232812Sjmallett str[9] = cvmx_debug_hexchar[(t>>24)&0xF]; 416232812Sjmallett str[10] = cvmx_debug_hexchar[(t>>20)&0xF]; 417232812Sjmallett str[11] = cvmx_debug_hexchar[(t>>16)&0xF]; 418232812Sjmallett str[12] = cvmx_debug_hexchar[(t>>12)&0xF]; 419232812Sjmallett str[13] = cvmx_debug_hexchar[(t>>8)&0xF]; 420232812Sjmallett str[14] = cvmx_debug_hexchar[(t>>4)&0xF]; 421232812Sjmallett str[15] = cvmx_debug_hexchar[(t>>0)&0xF]; 422232812Sjmallett str[16] = 0; 423215976Sjmallett} 424215976Sjmallett 425215976Sjmallettstatic int cvmx_debug_putpacket_noformat(char *packet) 426215976Sjmallett{ 427215976Sjmallett if (cvmx_debug_comms[cvmx_debug_globals->comm_type]->putpacket == NULL) 428215976Sjmallett return 0; 429215976Sjmallett cvmx_debug_printf("Reply: %s\n", packet); 430215976Sjmallett return cvmx_debug_comms[cvmx_debug_globals->comm_type]->putpacket(packet); 431215976Sjmallett} 432215976Sjmallett 433232812Sjmallettstatic int cvmx_debug_putcorepacket(char *buf, int core) 434215976Sjmallett{ 435232812Sjmallett char *tmp = "!Core XX "; 436232812Sjmallett int tmpsize = cvmx_debug_strlen(tmp); 437232812Sjmallett int bufsize = cvmx_debug_strlen(buf); 438232812Sjmallett char *packet = __builtin_alloca(tmpsize + bufsize + 1); 439232812Sjmallett cvmx_debug_strcpy(packet, tmp); 440232812Sjmallett cvmx_debug_strcpy(&packet[tmpsize], buf); 441232812Sjmallett if (core < 10) 442232812Sjmallett { 443232812Sjmallett packet[6] = ' '; 444232812Sjmallett packet[7] = core + '0'; 445232812Sjmallett } 446232812Sjmallett else if (core < 20) 447232812Sjmallett { 448232812Sjmallett packet[6] = '1'; 449232812Sjmallett packet[7] = core - 10 + '0'; 450232812Sjmallett } 451232812Sjmallett else if (core < 30) 452232812Sjmallett { 453232812Sjmallett packet[6] = '2'; 454232812Sjmallett packet[7] = core - 20 + '0'; 455232812Sjmallett } 456232812Sjmallett else 457232812Sjmallett { 458232812Sjmallett packet[6] = '3'; 459232812Sjmallett packet[7] = core - 30 + '0'; 460232812Sjmallett } 461232812Sjmallett return cvmx_debug_putpacket_noformat(packet); 462215976Sjmallett} 463215976Sjmallett 464232812Sjmallett/* Put a buf followed by an integer formated as a hex. */ 465232812Sjmallettstatic int cvmx_debug_putpacket_hexint(char *buf, uint64_t value) 466232812Sjmallett{ 467232812Sjmallett size_t size = cvmx_debug_strlen(buf); 468232812Sjmallett char *packet = __builtin_alloca(size + 16 + 1); 469232812Sjmallett cvmx_debug_strcpy(packet, buf); 470232812Sjmallett cvmx_debug_int64_to_strhex(&packet[size], value); 471232812Sjmallett return cvmx_debug_putpacket_noformat(packet); 472232812Sjmallett} 473232812Sjmallett 474232812Sjmallettstatic int cvmx_debug_active_core(cvmx_debug_state_t state, unsigned core) 475232812Sjmallett{ 476232812Sjmallett return state.active_cores & (1u << core); 477232812Sjmallett} 478232812Sjmallett 479215976Sjmallettstatic volatile cvmx_debug_core_context_t *cvmx_debug_core_context(void) 480215976Sjmallett{ 481215976Sjmallett return &cvmx_debug_globals->contextes[cvmx_get_core_num()]; 482215976Sjmallett} 483215976Sjmallett 484215976Sjmallettstatic volatile uint64_t *cvmx_debug_regnum_to_context_ref(int regnum, volatile cvmx_debug_core_context_t *context) 485215976Sjmallett{ 486215976Sjmallett /* Must be kept in sync with mips_octeon_reg_names in gdb/mips-tdep.c. */ 487215976Sjmallett if (regnum < 32) 488215976Sjmallett return &context->regs[regnum]; 489215976Sjmallett switch (regnum) 490215976Sjmallett { 491215976Sjmallett case 32: return &context->cop0.status; 492215976Sjmallett case 33: return &context->lo; 493215976Sjmallett case 34: return &context->hi; 494215976Sjmallett case 35: return &context->cop0.badvaddr; 495215976Sjmallett case 36: return &context->cop0.cause; 496215976Sjmallett case 37: return &context->cop0.depc; 497215976Sjmallett default: return NULL; 498215976Sjmallett } 499215976Sjmallett} 500215976Sjmallett 501215976Sjmallettstatic int cvmx_debug_probe_load(unsigned char *ptr, unsigned char *result) 502215976Sjmallett{ 503215976Sjmallett volatile unsigned char *p = ptr; 504215976Sjmallett int ok; 505215976Sjmallett unsigned char tem; 506215976Sjmallett 507215976Sjmallett { 508215976Sjmallett __cvmx_debug_mode_exception_ignore = 1; 509215976Sjmallett __cvmx_debug_mode_exception_occured = 0; 510215976Sjmallett /* We don't handle debug-mode exceptions in delay slots. Avoid them. */ 511215976Sjmallett asm volatile (".set push \n\t" 512215976Sjmallett ".set noreorder \n\t" 513215976Sjmallett "nop \n\t" 514215976Sjmallett "lbu %0, %1 \n\t" 515215976Sjmallett "nop \n\t" 516215976Sjmallett ".set pop" : "=r"(tem) : "m"(*p)); 517215976Sjmallett ok = __cvmx_debug_mode_exception_occured == 0; 518215976Sjmallett __cvmx_debug_mode_exception_ignore = 0; 519215976Sjmallett __cvmx_debug_mode_exception_occured = 0; 520215976Sjmallett *result = tem; 521215976Sjmallett } 522215976Sjmallett return ok; 523215976Sjmallett} 524215976Sjmallett 525215976Sjmallettstatic int cvmx_debug_probe_store(unsigned char *ptr) 526215976Sjmallett{ 527215976Sjmallett volatile unsigned char *p = ptr; 528215976Sjmallett int ok; 529215976Sjmallett 530215976Sjmallett __cvmx_debug_mode_exception_ignore = 1; 531215976Sjmallett __cvmx_debug_mode_exception_occured = 0; 532215976Sjmallett /* We don't handle debug-mode exceptions in delay slots. Avoid them. */ 533215976Sjmallett asm volatile (".set push \n\t" 534215976Sjmallett ".set noreorder \n\t" 535215976Sjmallett "nop \n\t" 536215976Sjmallett "sb $0, %0 \n\t" 537215976Sjmallett "nop \n\t" 538215976Sjmallett ".set pop" : "=m"(*p)); 539215976Sjmallett ok = __cvmx_debug_mode_exception_occured == 0; 540215976Sjmallett 541215976Sjmallett __cvmx_debug_mode_exception_ignore = 0; 542215976Sjmallett __cvmx_debug_mode_exception_occured = 0; 543215976Sjmallett return ok; 544215976Sjmallett} 545215976Sjmallett 546232812Sjmallett 547232812Sjmallett/** 548232812Sjmallett * Routines to handle hex data 549232812Sjmallett * 550232812Sjmallett * @param ch 551232812Sjmallett * @return 552232812Sjmallett */ 553232812Sjmallettstatic inline int cvmx_debug_hex(char ch) 554215976Sjmallett{ 555232812Sjmallett if ((ch >= 'a') && (ch <= 'f')) 556232812Sjmallett return(ch - 'a' + 10); 557232812Sjmallett if ((ch >= '0') && (ch <= '9')) 558232812Sjmallett return(ch - '0'); 559232812Sjmallett if ((ch >= 'A') && (ch <= 'F')) 560232812Sjmallett return(ch - 'A' + 10); 561232812Sjmallett return(-1); 562215976Sjmallett} 563215976Sjmallett 564215976Sjmallett/** 565232812Sjmallett * While we find nice hex chars, build an int. 566232812Sjmallett * Return number of chars processed. 567232812Sjmallett * 568232812Sjmallett * @param ptr 569232812Sjmallett * @param intValue 570232812Sjmallett * @return 571232812Sjmallett */ 572232812Sjmallettstatic int cvmx_debug_hexToLong(const char **ptr, uint64_t *intValue) 573232812Sjmallett{ 574232812Sjmallett int numChars = 0; 575232812Sjmallett long hexValue; 576232812Sjmallett 577232812Sjmallett *intValue = 0; 578232812Sjmallett while (**ptr) 579232812Sjmallett { 580232812Sjmallett hexValue = cvmx_debug_hex(**ptr); 581232812Sjmallett if (hexValue < 0) 582232812Sjmallett break; 583232812Sjmallett 584232812Sjmallett *intValue = (*intValue << 4) | hexValue; 585232812Sjmallett numChars ++; 586232812Sjmallett 587232812Sjmallett (*ptr)++; 588232812Sjmallett } 589232812Sjmallett 590232812Sjmallett return(numChars); 591232812Sjmallett} 592232812Sjmallett 593232812Sjmallett/** 594215976Sjmallett * Initialize the performance counter control registers. 595215976Sjmallett * 596215976Sjmallett */ 597232812Sjmallettstatic void cvmx_debug_set_perf_control_reg (volatile cvmx_debug_core_context_t *context, int perf_event, int perf_counter) 598215976Sjmallett{ 599215976Sjmallett cvmx_core_perf_control_t control; 600215976Sjmallett 601215976Sjmallett control.u32 = 0; 602215976Sjmallett control.s.u = 1; 603215976Sjmallett control.s.s = 1; 604215976Sjmallett control.s.k = 1; 605215976Sjmallett control.s.ex = 1; 606215976Sjmallett control.s.w = 1; 607215976Sjmallett control.s.m = 1 - perf_counter; 608215976Sjmallett control.s.event = perf_event; 609215976Sjmallett 610215976Sjmallett context->cop0.perfctrl[perf_counter] = control.u32; 611215976Sjmallett} 612215976Sjmallett 613232812Sjmallettstatic cvmx_debug_command_t cvmx_debug_process_packet(const char *packet) 614215976Sjmallett{ 615215976Sjmallett const char *buf = packet; 616215976Sjmallett cvmx_debug_command_t result = COMMAND_NOP; 617215976Sjmallett cvmx_debug_state_t state = cvmx_debug_get_state(); 618215976Sjmallett 619215976Sjmallett /* A one letter command code represents what to do. */ 620215976Sjmallett switch (*buf++) 621215976Sjmallett { 622215976Sjmallett case '?': /* What protocol do I speak? */ 623215976Sjmallett cvmx_debug_putpacket_noformat("S0A"); 624215976Sjmallett break; 625215976Sjmallett 626215976Sjmallett case '\003': /* Control-C */ 627215976Sjmallett cvmx_debug_putpacket_noformat("T9"); 628215976Sjmallett break; 629215976Sjmallett 630215976Sjmallett case 'F': /* Change the focus core */ 631215976Sjmallett { 632232812Sjmallett uint64_t core; 633232812Sjmallett if (!cvmx_debug_hexToLong(&buf, &core)) 634232812Sjmallett { 635232812Sjmallett cvmx_debug_putpacket_noformat("!Uknown core. Focus not changed."); 636232812Sjmallett } 637215976Sjmallett /* Only cores in the exception handler may become the focus. 638232812Sjmallett If a core not in the exception handler got focus the 639232812Sjmallett debugger would hang since nobody would talk to it. */ 640232812Sjmallett else if (state.handler_cores & (1u << core)) 641215976Sjmallett { 642215976Sjmallett /* Focus change reply must be sent before the focus 643232812Sjmallett changes. Otherwise the new focus core will eat our ACK 644232812Sjmallett from the debugger. */ 645232812Sjmallett cvmx_debug_putpacket_hexint("F", core); 646215976Sjmallett cvmx_debug_comms[cvmx_debug_globals->comm_type]->change_core(state.focus_core, core); 647215976Sjmallett state.focus_core = core; 648215976Sjmallett cvmx_debug_update_state(state); 649215976Sjmallett break; 650215976Sjmallett } 651215976Sjmallett else 652215976Sjmallett cvmx_debug_putpacket_noformat("!Core is not in the exception handler. Focus not changed."); 653215976Sjmallett /* Nothing changed, so we send back the old value */ 654215976Sjmallett } 655215976Sjmallett /* fall through */ 656215976Sjmallett case 'f': /* Get the focus core */ 657232812Sjmallett cvmx_debug_putpacket_hexint("F", state.focus_core); 658215976Sjmallett break; 659215976Sjmallett 660215976Sjmallett case 'J': /* Set the flag for skip-over-isr in Single-Stepping mode */ 661215976Sjmallett { 662215976Sjmallett if (*buf == '1') 663215976Sjmallett state.step_isr = 1; /* Step in ISR */ 664215976Sjmallett else 665215976Sjmallett state.step_isr = 0; /* Step over ISR */ 666215976Sjmallett cvmx_debug_update_state(state); 667215976Sjmallett } 668215976Sjmallett /* Fall through. The reply to the set step-isr command is the 669215976Sjmallett same as the get step-isr command */ 670215976Sjmallett 671215976Sjmallett case 'j': /* Reply with step_isr status */ 672232812Sjmallett cvmx_debug_putpacket_hexint("J", (unsigned)state.step_isr); 673215976Sjmallett break; 674215976Sjmallett 675215976Sjmallett 676215976Sjmallett case 'I': /* Set the active cores */ 677215976Sjmallett { 678232812Sjmallett uint64_t active_cores; 679232812Sjmallett if (!cvmx_debug_hexToLong(&buf, &active_cores)) 680232812Sjmallett active_cores = 0; 681215976Sjmallett /* Limit the active mask to the known to exist cores */ 682215976Sjmallett state.active_cores = active_cores & state.known_cores; 683215976Sjmallett 684215976Sjmallett /* Lazy user hack to have 0 be all cores */ 685215976Sjmallett if (state.active_cores == 0) 686215976Sjmallett state.active_cores = state.known_cores; 687215976Sjmallett 688215976Sjmallett /* The focus core must be in the active_cores mask */ 689232812Sjmallett if ((state.active_cores & (1u << state.focus_core)) == 0) 690215976Sjmallett { 691215976Sjmallett cvmx_debug_putpacket_noformat("!Focus core was added to the masked."); 692232812Sjmallett state.active_cores |= 1u << state.focus_core; 693215976Sjmallett } 694215976Sjmallett 695215976Sjmallett cvmx_debug_update_state(state); 696215976Sjmallett } 697215976Sjmallett /* Fall through. The reply to the set active cores command is the 698215976Sjmallett same as the get active cores command */ 699215976Sjmallett 700215976Sjmallett case 'i': /* Get the active cores */ 701232812Sjmallett cvmx_debug_putpacket_hexint("I", state.active_cores); 702215976Sjmallett break; 703215976Sjmallett 704215976Sjmallett case 'A': /* Setting the step mode all or one */ 705215976Sjmallett { 706215976Sjmallett if (*buf == '1') 707215976Sjmallett state.step_all = 1; /* A step or continue will start all cores */ 708215976Sjmallett else 709215976Sjmallett state.step_all = 0; /* A step or continue only affects the focus core */ 710215976Sjmallett cvmx_debug_update_state(state); 711215976Sjmallett } 712215976Sjmallett /* Fall through. The reply to the set step-all command is the 713215976Sjmallett same as the get step-all command */ 714215976Sjmallett 715215976Sjmallett case 'a': /* Getting the current step mode */ 716232812Sjmallett cvmx_debug_putpacket_hexint("A", state.step_all); 717215976Sjmallett break; 718215976Sjmallett 719215976Sjmallett case 'g': /* read a register from global place. */ 720215976Sjmallett { 721215976Sjmallett volatile cvmx_debug_core_context_t *context = cvmx_debug_core_context(); 722232812Sjmallett uint64_t regno; 723215976Sjmallett volatile uint64_t *reg; 724215976Sjmallett 725215976Sjmallett /* Get the register number to read */ 726232812Sjmallett if (!cvmx_debug_hexToLong(&buf, ®no)) 727232812Sjmallett { 728232812Sjmallett cvmx_debug_printf("Register number cannot be read.\n"); 729232812Sjmallett cvmx_debug_putpacket_hexint("", 0xDEADBEEF); 730232812Sjmallett break; 731232812Sjmallett } 732215976Sjmallett 733215976Sjmallett reg = cvmx_debug_regnum_to_context_ref(regno, context); 734215976Sjmallett if (!reg) 735232812Sjmallett { 736232812Sjmallett cvmx_debug_printf("Register #%d is not valid\n", (int)regno); 737232812Sjmallett cvmx_debug_putpacket_hexint("", 0xDEADBEEF); 738232812Sjmallett break; 739232812Sjmallett } 740232812Sjmallett cvmx_debug_putpacket_hexint("", *reg); 741215976Sjmallett } 742215976Sjmallett break; 743215976Sjmallett 744215976Sjmallett case 'G': /* set the value of a register. */ 745215976Sjmallett { 746215976Sjmallett volatile cvmx_debug_core_context_t *context = cvmx_debug_core_context(); 747232812Sjmallett uint64_t regno; 748215976Sjmallett volatile uint64_t *reg; 749232812Sjmallett uint64_t value; 750215976Sjmallett 751232812Sjmallett /* Get the register number to write. It should be followed by 752232812Sjmallett a comma */ 753232812Sjmallett if (!cvmx_debug_hexToLong(&buf, ®no) 754232812Sjmallett || (*buf++ != ',') 755232812Sjmallett || !cvmx_debug_hexToLong(&buf, &value)) 756215976Sjmallett { 757215976Sjmallett cvmx_debug_printf("G packet corrupt: %s\n", buf); 758215976Sjmallett goto error_packet; 759215976Sjmallett } 760215976Sjmallett 761215976Sjmallett reg = cvmx_debug_regnum_to_context_ref(regno, context); 762215976Sjmallett if (!reg) 763215976Sjmallett { 764232812Sjmallett cvmx_debug_printf("Register #%d is not valid\n", (int)regno); 765215976Sjmallett goto error_packet; 766215976Sjmallett } 767215976Sjmallett *reg = value; 768215976Sjmallett } 769215976Sjmallett break; 770215976Sjmallett 771215976Sjmallett case 'm': /* Memory read. mAA..AA,LLLL Read LLLL bytes at address AA..AA */ 772215976Sjmallett { 773232812Sjmallett uint64_t addr, i, length; 774215976Sjmallett unsigned char *ptr; 775215976Sjmallett char *reply; 776215976Sjmallett 777232812Sjmallett /* Get the memory address, a comma, and the length */ 778232812Sjmallett if (!cvmx_debug_hexToLong(&buf, &addr) 779232812Sjmallett || (*buf++ != ',') 780232812Sjmallett || !cvmx_debug_hexToLong(&buf, &length)) 781215976Sjmallett { 782215976Sjmallett cvmx_debug_printf("m packet corrupt: %s\n", buf); 783215976Sjmallett goto error_packet; 784215976Sjmallett } 785215976Sjmallett if (length >= 1024) 786215976Sjmallett { 787232812Sjmallett cvmx_debug_printf("m packet length out of range: %lld\n", (long long)length); 788215976Sjmallett goto error_packet; 789215976Sjmallett } 790215976Sjmallett 791215976Sjmallett reply = __builtin_alloca(length * 2 + 1); 792215976Sjmallett ptr = (unsigned char *)(long)addr; 793215976Sjmallett for (i = 0; i < length; i++) 794215976Sjmallett { 795215976Sjmallett /* Probe memory. If not accessible fail. */ 796215976Sjmallett unsigned char t; 797215976Sjmallett if (!cvmx_debug_probe_load(&ptr[i], &t)) 798215976Sjmallett goto error_packet; 799232812Sjmallett cvmx_debug_int8_to_strhex(&reply[i * 2], t); 800215976Sjmallett } 801215976Sjmallett cvmx_debug_putpacket_noformat(reply); 802215976Sjmallett } 803215976Sjmallett break; 804215976Sjmallett 805215976Sjmallett case 'M': /* Memory write. MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */ 806215976Sjmallett { 807232812Sjmallett uint64_t addr, i, length; 808215976Sjmallett unsigned char *ptr; 809215976Sjmallett 810232812Sjmallett if (!cvmx_debug_hexToLong(&buf, &addr) 811232812Sjmallett || *buf++ != ',' 812232812Sjmallett || !cvmx_debug_hexToLong(&buf, &length) 813232812Sjmallett || *buf++ != ':') 814215976Sjmallett { 815215976Sjmallett cvmx_debug_printf("M packet corrupt: %s\n", buf); 816215976Sjmallett goto error_packet; 817215976Sjmallett } 818232812Sjmallett 819215976Sjmallett ptr = (unsigned char *)(long)addr; 820215976Sjmallett for (i = 0; i < length; i++) 821215976Sjmallett { 822232812Sjmallett int n, n1; 823232812Sjmallett unsigned char c; 824232812Sjmallett 825232812Sjmallett n = cvmx_debug_hex(buf[i * 2]); 826232812Sjmallett n1 = cvmx_debug_hex(buf[i * 2 + 1]); 827232812Sjmallett c = (n << 4) | n1; 828215976Sjmallett 829232812Sjmallett if (n == -1 || n1 == -1) 830215976Sjmallett { 831232812Sjmallett cvmx_debug_printf("M packet corrupt: %s\n", &buf[i * 2]); 832215976Sjmallett goto error_packet; 833215976Sjmallett } 834215976Sjmallett /* Probe memory. If not accessible fail. */ 835215976Sjmallett if (!cvmx_debug_probe_store(&ptr[i])) 836215976Sjmallett { 837215976Sjmallett cvmx_debug_printf("M cannot write: %p\n", &ptr[i]); 838215976Sjmallett goto error_packet; 839215976Sjmallett } 840215976Sjmallett ptr[i] = c; 841215976Sjmallett } 842215976Sjmallett cvmx_debug_putpacket_noformat("+"); 843215976Sjmallett } 844215976Sjmallett break; 845215976Sjmallett 846215976Sjmallett case 'e': /* Set/get performance counter events. e[1234]XX..X: [01] 847215976Sjmallett is the performance counter to set X is the performance 848215976Sjmallett event. [34] is to get the same thing. */ 849215976Sjmallett { 850232812Sjmallett uint64_t perf_event = 0; 851232812Sjmallett char encoded_counter = *buf++; 852232812Sjmallett uint64_t counter; 853215976Sjmallett volatile cvmx_debug_core_context_t *context = cvmx_debug_core_context(); 854215976Sjmallett 855232812Sjmallett /* Ignore errors from the packet. */ 856232812Sjmallett cvmx_debug_hexToLong(&buf, &perf_event); 857232812Sjmallett 858215976Sjmallett switch (encoded_counter) 859215976Sjmallett { 860232812Sjmallett case '1': /* Set performance counter0 event. */ 861232812Sjmallett case '2': /* Set performance counter1 event. */ 862215976Sjmallett 863232812Sjmallett counter = encoded_counter - '1'; 864215976Sjmallett context->cop0.perfval[counter] = 0; 865232812Sjmallett cvmx_debug_set_perf_control_reg(context, perf_event, counter); 866215976Sjmallett break; 867215976Sjmallett 868232812Sjmallett case '3': /* Get performance counter0 event. */ 869232812Sjmallett case '4': /* Get performance counter1 event. */ 870215976Sjmallett { 871215976Sjmallett cvmx_core_perf_control_t c; 872232812Sjmallett char outpacket[16*2 +2]; 873232812Sjmallett counter = encoded_counter - '3'; 874215976Sjmallett /* Pass performance counter0 event and counter to 875215976Sjmallett the debugger. */ 876215976Sjmallett c.u32 = context->cop0.perfctrl[counter]; 877232812Sjmallett cvmx_debug_int64_to_strhex(outpacket, context->cop0.perfval[counter]); 878232812Sjmallett outpacket[16] = ','; 879232812Sjmallett cvmx_debug_int64_to_strhex(&outpacket[17], c.s.event); 880232812Sjmallett outpacket[33] = 0; 881232812Sjmallett cvmx_debug_putpacket_noformat(outpacket); 882215976Sjmallett } 883215976Sjmallett break; 884215976Sjmallett } 885215976Sjmallett } 886215976Sjmallett break; 887215976Sjmallett 888215976Sjmallett#if 0 889215976Sjmallett case 't': /* Return the trace buffer read data register contents. */ 890215976Sjmallett { 891215976Sjmallett uint64_t tra_data; 892215976Sjmallett uint64_t tra_ctl; 893215976Sjmallett char tmp[64]; 894215976Sjmallett 895215976Sjmallett /* If trace buffer is disabled no trace data information is available. */ 896215976Sjmallett if ((tra_ctl & 0x1) == 0) 897215976Sjmallett { 898215976Sjmallett cvmx_debug_putpacket_noformat("!Trace buffer not enabled\n"); 899215976Sjmallett cvmx_debug_putpacket_noformat("t"); 900215976Sjmallett } 901215976Sjmallett else 902215976Sjmallett { 903215976Sjmallett cvmx_debug_putpacket_noformat("!Trace buffer is enabled\n"); 904215976Sjmallett tra_data = cvmx_read_csr(OCTEON_TRA_READ_DATA); 905215976Sjmallett mem2hex (&tra_data, tmp, 8); 906215976Sjmallett strcpy (debug_output_buffer, "t"); 907215976Sjmallett strcat (debug_output_buffer, tmp); 908215976Sjmallett cvmx_debug_putpacket_noformat(debug_output_buffer); 909215976Sjmallett } 910215976Sjmallett } 911215976Sjmallett break; 912215976Sjmallett#endif 913215976Sjmallett 914215976Sjmallett case 'Z': /* Insert hardware breakpoint: Z[di]NN..N,AA.A, [di] data or 915215976Sjmallett instruction, NN..Nth at address AA..A */ 916215976Sjmallett { 917215976Sjmallett enum type 918215976Sjmallett { 919215976Sjmallett WP_LOAD = 1, 920215976Sjmallett WP_STORE = 2, 921215976Sjmallett WP_ACCESS = 3 922215976Sjmallett }; 923215976Sjmallett 924232812Sjmallett uint64_t num, size; 925232812Sjmallett uint64_t addr; 926232812Sjmallett uint64_t type; 927232812Sjmallett char bp_type = *buf++; 928215976Sjmallett const int BE = 1, TE = 4; 929215976Sjmallett volatile cvmx_debug_core_context_t *context = cvmx_debug_core_context(); 930215976Sjmallett 931232812Sjmallett if (!cvmx_debug_hexToLong(&buf, &num) 932232812Sjmallett || *buf++ != ',' 933232812Sjmallett || !cvmx_debug_hexToLong(&buf, &addr)) 934232812Sjmallett { 935232812Sjmallett cvmx_debug_printf("Z packet corrupt: %s\n", &packet[1]); 936232812Sjmallett goto error_packet; 937232812Sjmallett } 938232812Sjmallett 939215976Sjmallett switch (bp_type) 940215976Sjmallett { 941215976Sjmallett case 'i': // Instruction hardware breakpoint 942232812Sjmallett if (num > 4) 943215976Sjmallett { 944232812Sjmallett cvmx_debug_printf("Z packet corrupt: %s\n", &packet[1]); 945215976Sjmallett goto error_packet; 946215976Sjmallett } 947215976Sjmallett 948215976Sjmallett context->hw_ibp.address[num] = addr; 949215976Sjmallett context->hw_ibp.address_mask[num] = 0; 950215976Sjmallett context->hw_ibp.asid[num] = 0; 951215976Sjmallett context->hw_ibp.control[num] = BE | TE; 952215976Sjmallett break; 953215976Sjmallett 954215976Sjmallett case 'd': // Data hardware breakpoint 955215976Sjmallett { 956215976Sjmallett uint64_t dbc = 0xff0 | BE | TE; 957215976Sjmallett uint64_t dbm; 958232812Sjmallett if (num > 4 959232812Sjmallett || *buf++ != ',' 960232812Sjmallett || !cvmx_debug_hexToLong(&buf, &size) 961232812Sjmallett || *buf++ != ',' 962232812Sjmallett || !cvmx_debug_hexToLong(&buf, &type) 963232812Sjmallett || type > WP_ACCESS 964232812Sjmallett || type < WP_LOAD) 965215976Sjmallett { 966232812Sjmallett cvmx_debug_printf("Z packet corrupt: %s\n", &packet[1]); 967215976Sjmallett goto error_packet; 968215976Sjmallett } 969215976Sjmallett 970215976Sjmallett /* Set DBC[BE,TE,BLM]. */ 971215976Sjmallett context->hw_dbp.address[num] = addr; 972215976Sjmallett context->hw_dbp.asid[num] = 0; 973215976Sjmallett 974215976Sjmallett dbc |= type == WP_STORE ? 0x1000 : type == WP_LOAD ? 0x2000 : 0; 975215976Sjmallett /* Mask the bits depending on the size for 976215976Sjmallett debugger to stop while accessing parts of the 977215976Sjmallett memory location. */ 978215976Sjmallett dbm = (size == 8) ? 0x7 : ((size == 4) ? 3 979215976Sjmallett : (size == 2) ? 1 : 0); 980215976Sjmallett context->hw_dbp.address_mask[num] = dbm; 981215976Sjmallett context->hw_dbp.control[num] = dbc; 982215976Sjmallett break; 983215976Sjmallett } 984215976Sjmallett default: 985232812Sjmallett cvmx_debug_printf("Z packet corrupt: %s\n", &packet[1]); 986215976Sjmallett goto error_packet; 987215976Sjmallett } 988215976Sjmallett } 989215976Sjmallett break; 990215976Sjmallett 991215976Sjmallett case 'z': /* Remove hardware breakpoint: z[di]NN..N remove NN..Nth 992215976Sjmallettbreakpoint. */ 993215976Sjmallett { 994232812Sjmallett uint64_t num; 995232812Sjmallett char bp_type = *buf++; 996215976Sjmallett volatile cvmx_debug_core_context_t *context = cvmx_debug_core_context(); 997215976Sjmallett 998232812Sjmallett if (!cvmx_debug_hexToLong(&buf, &num) || num > 4) 999215976Sjmallett { 1000215976Sjmallett cvmx_debug_printf("z packet corrupt: %s\n", buf); 1001215976Sjmallett goto error_packet; 1002215976Sjmallett } 1003215976Sjmallett 1004215976Sjmallett switch (bp_type) 1005215976Sjmallett { 1006215976Sjmallett case 'i': // Instruction hardware breakpoint 1007215976Sjmallett context->hw_ibp.address[num] = 0; 1008215976Sjmallett context->hw_ibp.address_mask[num] = 0; 1009215976Sjmallett context->hw_ibp.asid[num] = 0; 1010215976Sjmallett context->hw_ibp.control[num] = 0; 1011215976Sjmallett break; 1012215976Sjmallett case 'd': // Data hardware breakpoint 1013215976Sjmallett context->hw_dbp.address[num] = 0; 1014215976Sjmallett context->hw_dbp.address_mask[num] = 0; 1015215976Sjmallett context->hw_dbp.asid[num] = 0; 1016215976Sjmallett context->hw_dbp.control[num] = 0; 1017215976Sjmallett break; 1018215976Sjmallett default: 1019215976Sjmallett cvmx_debug_printf("z packet corrupt: %s\n", buf); 1020215976Sjmallett goto error_packet; 1021215976Sjmallett } 1022215976Sjmallett } 1023215976Sjmallett break; 1024215976Sjmallett 1025215976Sjmallett case 's': /* Single step. sAA..AA Step one instruction from AA..AA (optional) */ 1026215976Sjmallett result = COMMAND_STEP; 1027215976Sjmallett break; 1028215976Sjmallett 1029215976Sjmallett case 'c': /* Continue. cAA..AA Continue at address AA..AA (optional) */ 1030215976Sjmallett result = COMMAND_CONTINUE; 1031215976Sjmallett break; 1032215976Sjmallett 1033215976Sjmallett case '+': /* Don't know. I think it is a communications sync */ 1034215976Sjmallett /* Ignoring this command */ 1035215976Sjmallett break; 1036215976Sjmallett 1037215976Sjmallett default: 1038215976Sjmallett cvmx_debug_printf("Unknown debug command: %s\n", buf - 1); 1039215976Sjmalletterror_packet: 1040215976Sjmallett cvmx_debug_putpacket_noformat("-"); 1041215976Sjmallett break; 1042215976Sjmallett } 1043215976Sjmallett 1044215976Sjmallett return result; 1045215976Sjmallett} 1046215976Sjmallett 1047215976Sjmallettstatic cvmx_debug_command_t cvmx_debug_process_next_packet(void) 1048215976Sjmallett{ 1049215976Sjmallett char packet[CVMX_DEBUG_MAX_REQUEST_SIZE]; 1050215976Sjmallett if (cvmx_debug_comms[cvmx_debug_globals->comm_type]->getpacket(packet, CVMX_DEBUG_MAX_REQUEST_SIZE)) 1051215976Sjmallett { 1052215976Sjmallett cvmx_debug_printf("Request: %s\n", packet); 1053215976Sjmallett return cvmx_debug_process_packet(packet); 1054215976Sjmallett } 1055215976Sjmallett return COMMAND_NOP; 1056215976Sjmallett} 1057215976Sjmallett 1058215976Sjmallett/* If a core isn't in the active core mask we need to start him up again. We 1059215976Sjmallett can only do this if the core didn't hit a breakpoint or single step. If the 1060215976Sjmallett core hit CVMX_CIU_DINT interrupt (generally happens when while executing 1061215976Sjmallett _exit() at the end of the program). Remove the core from known cores so 1062215976Sjmallett that when the cores in active core mask are done executing the program, the 1063215976Sjmallett focus will not be transfered to this core. */ 1064215976Sjmallett 1065215976Sjmallettstatic int cvmx_debug_stop_core(cvmx_debug_state_t state, unsigned core, cvmx_debug_register_t *debug_reg, int proxy) 1066215976Sjmallett{ 1067215976Sjmallett if (!cvmx_debug_active_core(state, core) && !debug_reg->s.dbp && !debug_reg->s.dss && (debug_reg->s.dint != 1)) 1068215976Sjmallett { 1069215976Sjmallett debug_reg->s.sst = 0; 1070215976Sjmallett cvmx_debug_printf("Core #%d not in active cores, continuing.\n", core); 1071215976Sjmallett return 0; 1072215976Sjmallett } 1073232812Sjmallett if ((state.core_finished & (1u<<core)) && proxy) 1074215976Sjmallett return 0; 1075215976Sjmallett return 1; 1076215976Sjmallett} 1077215976Sjmallett 1078215976Sjmallett/* check to see if current exc is single-stepped and that no other exc 1079215976Sjmallett was also simultaneously noticed. */ 1080215976Sjmallettstatic int cvmx_debug_single_step_exc(cvmx_debug_register_t *debug_reg) 1081215976Sjmallett{ 1082215976Sjmallett if (debug_reg->s.dss && !debug_reg->s.dib && !debug_reg->s.dbp && !debug_reg->s.ddbs && !debug_reg->s.ddbl) 1083215976Sjmallett return 1; 1084215976Sjmallett return 0; 1085215976Sjmallett} 1086215976Sjmallett 1087215976Sjmallettstatic void cvmx_debug_set_focus_core(cvmx_debug_state_t *state, int core) 1088215976Sjmallett{ 1089215976Sjmallett if (state->ever_been_in_debug) 1090232812Sjmallett cvmx_debug_putcorepacket("taking focus.", core); 1091215976Sjmallett cvmx_debug_comms[cvmx_debug_globals->comm_type]->change_core (state->focus_core, core); 1092215976Sjmallett state->focus_core = core; 1093215976Sjmallett} 1094215976Sjmallett 1095215976Sjmallettstatic void cvmx_debug_may_elect_as_focus_core(cvmx_debug_state_t *state, int core, cvmx_debug_register_t *debug_reg) 1096215976Sjmallett{ 1097215976Sjmallett /* If another core has already elected itself as the focus core, we're late. */ 1098232812Sjmallett if (state->handler_cores & (1u << state->focus_core)) 1099215976Sjmallett return; 1100215976Sjmallett 1101215976Sjmallett /* If we hit a breakpoint, elect ourselves. */ 1102215976Sjmallett if (debug_reg->s.dib || debug_reg->s.dbp || debug_reg->s.ddbs || debug_reg->s.ddbl) 1103215976Sjmallett cvmx_debug_set_focus_core(state, core); 1104215976Sjmallett 1105215976Sjmallett /* It is possible the focus core has completed processing and exited the 1106215976Sjmallett program. When this happens the focus core will not be in 1107215976Sjmallett known_cores. If this is the case we need to elect a new focus. */ 1108232812Sjmallett if ((state->known_cores & (1u << state->focus_core)) == 0) 1109215976Sjmallett cvmx_debug_set_focus_core(state, core); 1110215976Sjmallett} 1111215976Sjmallett 1112215976Sjmallettstatic void cvmx_debug_send_stop_reason(cvmx_debug_register_t *debug_reg, volatile cvmx_debug_core_context_t *context) 1113215976Sjmallett{ 1114215976Sjmallett /* Handle Debug Data Breakpoint Store/Load Exception. */ 1115215976Sjmallett if (debug_reg->s.ddbs || debug_reg->s.ddbl) 1116232812Sjmallett cvmx_debug_putpacket_hexint("T8:", (int) context->hw_dbp.status); 1117215976Sjmallett else 1118215976Sjmallett cvmx_debug_putpacket_noformat("T9"); 1119215976Sjmallett} 1120215976Sjmallett 1121215976Sjmallett 1122215976Sjmallettstatic void cvmx_debug_clear_status(volatile cvmx_debug_core_context_t *context) 1123215976Sjmallett{ 1124215976Sjmallett /* SW needs to clear the BreakStatus bits after a watchpoint is hit or on 1125215976Sjmallett reset. */ 1126215976Sjmallett context->hw_dbp.status &= ~0x3fff; 1127215976Sjmallett 1128215976Sjmallett /* Clear MCD0, which is write-1-to-clear. */ 1129215976Sjmallett context->cop0.multicoredebug |= 1; 1130215976Sjmallett} 1131215976Sjmallett 1132215976Sjmallettstatic void cvmx_debug_sync_up_cores(void) 1133215976Sjmallett{ 1134232812Sjmallett /* NOTE this reads directly from the state array for speed reasons 1135232812Sjmallett and we don't change the array. */ 1136215976Sjmallett do { 1137232812Sjmallett asm("": : : "memory"); 1138232812Sjmallett } while (cvmx_debug_globals->state[offsetof(cvmx_debug_state_t, step_all)/sizeof(uint32_t)] 1139232812Sjmallett && cvmx_debug_globals->state[offsetof(cvmx_debug_state_t, handler_cores)/sizeof(uint32_t)] != 0); 1140215976Sjmallett} 1141215976Sjmallett 1142215976Sjmallett/* Delay the focus core a little if it is likely another core needs to steal 1143215976Sjmallett focus. Once we enter the main loop focus can't be stolen */ 1144215976Sjmallettstatic void cvmx_debug_delay_focus_core(cvmx_debug_state_t state, unsigned core, cvmx_debug_register_t *debug_reg) 1145215976Sjmallett{ 1146215976Sjmallett volatile int i; 1147215976Sjmallett if (debug_reg->s.dss || debug_reg->s.dbp || core != state.focus_core) 1148215976Sjmallett return; 1149232812Sjmallett for (i = 0; i < 2400; i++) 1150215976Sjmallett { 1151215976Sjmallett asm volatile (".set push \n\t" 1152215976Sjmallett ".set noreorder \n\t" 1153215976Sjmallett "nop \n\t" 1154215976Sjmallett "nop \n\t" 1155215976Sjmallett "nop \n\t" 1156215976Sjmallett "nop \n\t" 1157215976Sjmallett ".set pop"); 1158215976Sjmallett /* Spin giving the breakpoint core time to steal focus */ 1159215976Sjmallett } 1160215976Sjmallett 1161215976Sjmallett} 1162215976Sjmallett 1163215976Sjmallett/* If this core was single-stepping in a group, 1164215976Sjmallett && it was not the last focus-core, 1165215976Sjmallett && last focus-core happens to be inside an ISR, blocking focus-switch 1166215976Sjmallett then burn some cycles, to avoid unnecessary focus toggles. */ 1167215976Sjmallettstatic void cvmx_debug_delay_isr_core(unsigned core, uint32_t depc, int single_stepped_exc_only, 1168215976Sjmallett cvmx_debug_state_t state) 1169215976Sjmallett{ 1170215976Sjmallett volatile uint64_t i; 1171215976Sjmallett if(!single_stepped_exc_only || state.step_isr || core == state.focus_core || state.focus_switch) 1172215976Sjmallett return; 1173215976Sjmallett 1174215976Sjmallett cvmx_debug_printf ("Core #%u spinning for focus at 0x%x\n", core, (unsigned int)depc); 1175215976Sjmallett 1176215976Sjmallett for(i = ISR_DELAY_COUNTER; i > 0 ; i--) 1177215976Sjmallett { 1178215976Sjmallett state = cvmx_debug_get_state(); 1179215976Sjmallett /* Spin giving the focus core time to service ISR */ 1180215976Sjmallett /* But cut short the loop, if we can. Shrink down i, only once. */ 1181215976Sjmallett if (i > 600000 && state.focus_switch) 1182215976Sjmallett i = 500000; 1183215976Sjmallett } 1184215976Sjmallett 1185215976Sjmallett} 1186215976Sjmallett 1187215976Sjmallettstatic int cvmx_debug_perform_proxy(cvmx_debug_register_t *debug_reg, volatile cvmx_debug_core_context_t *context) 1188215976Sjmallett{ 1189215976Sjmallett unsigned core = cvmx_get_core_num(); 1190215976Sjmallett cvmx_debug_state_t state = cvmx_debug_get_state(); 1191215976Sjmallett cvmx_debug_command_t command = COMMAND_NOP; 1192215976Sjmallett int single_stepped_exc_only = cvmx_debug_single_step_exc (debug_reg); 1193215976Sjmallett 1194215976Sjmallett /* All cores should respect the focus core if it has to 1195215976Sjmallett stop focus switching while servicing an interrupt. 1196215976Sjmallett If the system is single-stepping, then the following 1197215976Sjmallett code path is valid. If the current core tripped on a 1198215976Sjmallett break-point or some other error while going through 1199215976Sjmallett an ISR, then we shouldn't be returning unconditionally. 1200215976Sjmallett In that case (non-single-step case) we must enter 1201215976Sjmallett the debugger exception stub fully. */ 1202215976Sjmallett if (!state.step_isr && (cvmx_interrupt_in_isr || (context->cop0.status & 0x2ULL)) && single_stepped_exc_only) 1203215976Sjmallett { 1204215976Sjmallett cvmx_spinlock_lock(&cvmx_debug_globals->lock); 1205215976Sjmallett state = cvmx_debug_get_state(); 1206215976Sjmallett /* If this is the focus core, switch off focus switching 1207215976Sjmallett till ISR_DELAY_COUNTER. This will let focus core 1208215976Sjmallett keep the focus until the ISR is completed. */ 1209215976Sjmallett if(state.focus_switch && core == state.focus_core) 1210215976Sjmallett { 1211215976Sjmallett cvmx_debug_printf ("Core #%u stopped focus stealing at 0x%llx\n", core, (unsigned long long)context->cop0.depc); 1212215976Sjmallett state.focus_switch = 0; 1213215976Sjmallett } 1214215976Sjmallett /* Alow other cores to steal focus. 1215215976Sjmallett Focus core has completed ISR. */ 1216215976Sjmallett if (*(uint32_t*)((__SIZE_TYPE__)context->cop0.depc) == ERET_INSN && core == state.focus_core) 1217215976Sjmallett { 1218215976Sjmallett cvmx_debug_printf ("Core #%u resumed focus stealing at 0x%llx\n", core, (unsigned long long)context->cop0.depc); 1219215976Sjmallett state.focus_switch = 1; 1220215976Sjmallett } 1221215976Sjmallett cvmx_debug_update_state(state); 1222215976Sjmallett cvmx_spinlock_unlock(&cvmx_debug_globals->lock); 1223215976Sjmallett cvmx_debug_printf ("Core #%u resumed skipping isr.\n", core); 1224215976Sjmallett return 0; 1225215976Sjmallett } 1226215976Sjmallett 1227215976Sjmallett /* Delay the focus core a little if it is likely another core needs to 1228215976Sjmallett steal focus. Once we enter the main loop focus can't be stolen */ 1229215976Sjmallett cvmx_debug_delay_focus_core(state, core, debug_reg); 1230215976Sjmallett 1231215976Sjmallett cvmx_debug_delay_isr_core (core, context->cop0.depc, single_stepped_exc_only, state); 1232215976Sjmallett 1233215976Sjmallett /* The following section of code does two critical things. First, it 1234215976Sjmallett populates the handler_cores bitmask of all cores in the exception 1235215976Sjmallett handler. Only one core at a time can update this field. Second it 1236215976Sjmallett changes the focus core if needed. */ 1237215976Sjmallett { 1238215976Sjmallett cvmx_debug_printf("Core #%d stopped\n", core); 1239215976Sjmallett cvmx_spinlock_lock(&cvmx_debug_globals->lock); 1240215976Sjmallett state = cvmx_debug_get_state(); 1241215976Sjmallett 1242232812Sjmallett state.handler_cores |= (1u << core); 1243215976Sjmallett cvmx_debug_may_elect_as_focus_core(&state, core, debug_reg); 1244215976Sjmallett 1245215976Sjmallett/* Push all updates before exiting the critical section */ 1246215976Sjmallett state.focus_switch = 1; 1247215976Sjmallett cvmx_debug_update_state(state); 1248215976Sjmallett cvmx_spinlock_unlock(&cvmx_debug_globals->lock); 1249215976Sjmallett } 1250215976Sjmallett if (__cvmx_debug_in_focus(state, core)) 1251215976Sjmallett cvmx_debug_send_stop_reason(debug_reg, context); 1252215976Sjmallett 1253215976Sjmallett do { 1254232812Sjmallett unsigned oldfocus = state.focus_core; 1255215976Sjmallett state = cvmx_debug_get_state(); 1256215976Sjmallett /* Note the focus core can change in this loop. */ 1257215976Sjmallett if (__cvmx_debug_in_focus(state, core)) 1258215976Sjmallett { 1259232812Sjmallett /* If the focus has changed and the old focus has exited, then send a signal 1260232812Sjmallett that we should stop if step_all is off. */ 1261232812Sjmallett if (oldfocus != state.focus_core && ((1u << oldfocus) & state.core_finished) 1262232812Sjmallett && !state.step_all) 1263232812Sjmallett cvmx_debug_send_stop_reason(debug_reg, context); 1264232812Sjmallett 1265215976Sjmallett command = cvmx_debug_process_next_packet(); 1266215976Sjmallett state = cvmx_debug_get_state(); 1267215976Sjmallett /* When resuming let the other cores resume as well with 1268215976Sjmallett step-all. */ 1269215976Sjmallett if (command != COMMAND_NOP && state.step_all) 1270215976Sjmallett { 1271215976Sjmallett state.command = command; 1272215976Sjmallett cvmx_debug_update_state(state); 1273215976Sjmallett } 1274215976Sjmallett } 1275215976Sjmallett /* When steping all cores, update the non focus core's command too. */ 1276215976Sjmallett else if (state.step_all) 1277215976Sjmallett command = state.command; 1278215976Sjmallett 1279215976Sjmallett /* If we did not get a command and the communication changed return, 1280215976Sjmallett we are changing the communications. */ 1281215976Sjmallett if (command == COMMAND_NOP && cvmx_debug_globals->comm_changed) 1282215976Sjmallett { 1283215976Sjmallett /* FIXME, this should a sync not based on cvmx_coremask_barrier_sync. */ 1284215976Sjmallett#ifndef CVMX_BUILD_FOR_LINUX_KERNEL 1285215976Sjmallett /* Sync up. */ 1286215976Sjmallett cvmx_coremask_barrier_sync(state.handler_cores); 1287215976Sjmallett#endif 1288215976Sjmallett return 1; 1289215976Sjmallett } 1290215976Sjmallett } while (command == COMMAND_NOP); 1291215976Sjmallett 1292215976Sjmallett debug_reg->s.sst = command == COMMAND_STEP; 1293215976Sjmallett cvmx_debug_printf("Core #%d running\n", core); 1294215976Sjmallett 1295215976Sjmallett { 1296215976Sjmallett cvmx_spinlock_lock(&cvmx_debug_globals->lock); 1297215976Sjmallett state = cvmx_debug_get_state(); 1298232812Sjmallett state.handler_cores ^= (1u << core); 1299215976Sjmallett cvmx_debug_update_state(state); 1300215976Sjmallett cvmx_spinlock_unlock(&cvmx_debug_globals->lock); 1301215976Sjmallett } 1302215976Sjmallett 1303215976Sjmallett cvmx_debug_sync_up_cores(); 1304215976Sjmallett /* Now that all cores are out, reset the command. */ 1305215976Sjmallett if (__cvmx_debug_in_focus(state, core)) 1306215976Sjmallett { 1307215976Sjmallett cvmx_spinlock_lock(&cvmx_debug_globals->lock); 1308215976Sjmallett state = cvmx_debug_get_state(); 1309215976Sjmallett state.command = COMMAND_NOP; 1310215976Sjmallett cvmx_debug_update_state(state); 1311215976Sjmallett cvmx_spinlock_unlock(&cvmx_debug_globals->lock); 1312215976Sjmallett } 1313215976Sjmallett return 0; 1314215976Sjmallett} 1315215976Sjmallett 1316232812Sjmallettstatic void cvmx_debug_save_core_context(volatile cvmx_debug_core_context_t *context, uint64_t hi, uint64_t lo) 1317215976Sjmallett{ 1318215976Sjmallett unsigned i; 1319232812Sjmallett cvmx_debug_memcpy_align ((char *) context->regs, __cvmx_debug_save_regs_area, sizeof(context->regs)); 1320232812Sjmallett context->lo = lo; 1321232812Sjmallett context->hi = hi; 1322215976Sjmallett CVMX_MF_COP0(context->cop0.index, COP0_INDEX); 1323215976Sjmallett CVMX_MF_COP0(context->cop0.entrylo[0], COP0_ENTRYLO0); 1324215976Sjmallett CVMX_MF_COP0(context->cop0.entrylo[1], COP0_ENTRYLO1); 1325215976Sjmallett CVMX_MF_COP0(context->cop0.entryhi, COP0_ENTRYHI); 1326215976Sjmallett CVMX_MF_COP0(context->cop0.pagemask, COP0_PAGEMASK); 1327215976Sjmallett CVMX_MF_COP0(context->cop0.status, COP0_STATUS); 1328215976Sjmallett CVMX_MF_COP0(context->cop0.cause, COP0_CAUSE); 1329215976Sjmallett CVMX_MF_COP0(context->cop0.debug, COP0_DEBUG); 1330215976Sjmallett CVMX_MF_COP0(context->cop0.multicoredebug, COP0_MULTICOREDEBUG); 1331215976Sjmallett CVMX_MF_COP0(context->cop0.perfval[0], COP0_PERFVALUE0); 1332215976Sjmallett CVMX_MF_COP0(context->cop0.perfval[1], COP0_PERFVALUE1); 1333215976Sjmallett CVMX_MF_COP0(context->cop0.perfctrl[0], COP0_PERFCONTROL0); 1334215976Sjmallett CVMX_MF_COP0(context->cop0.perfctrl[1], COP0_PERFCONTROL1); 1335215976Sjmallett /* Save DEPC and DESAVE since debug-mode exceptions (see 1336215976Sjmallett debug_probe_{load,store}) can clobber these. */ 1337215976Sjmallett CVMX_MF_COP0(context->cop0.depc, COP0_DEPC); 1338215976Sjmallett CVMX_MF_COP0(context->cop0.desave, COP0_DESAVE); 1339215976Sjmallett 1340215976Sjmallett context->hw_ibp.status = cvmx_read_csr(CVMX_DEBUG_HW_INSTRUCTION_BREAKPOINT_STATUS); 1341215976Sjmallett for (i = 0; i < 4; i++) 1342215976Sjmallett { 1343215976Sjmallett context->hw_ibp.address[i] = cvmx_read_csr(CVMX_DEBUG_HW_INSTRUCTION_BREAKPOINT_ADDRESS(i)); 1344215976Sjmallett context->hw_ibp.address_mask[i] = cvmx_read_csr(CVMX_DEBUG_HW_INSTRUCTION_BREAKPOINT_ADDRESS_MASK(i)); 1345215976Sjmallett context->hw_ibp.asid[i] = cvmx_read_csr(CVMX_DEBUG_HW_INSTRUCTION_BREAKPOINT_ASID(i)); 1346215976Sjmallett context->hw_ibp.control[i] = cvmx_read_csr(CVMX_DEBUG_HW_INSTRUCTION_BREAKPOINT_CONTROL(i)); 1347215976Sjmallett } 1348215976Sjmallett 1349215976Sjmallett context->hw_dbp.status = cvmx_read_csr(CVMX_DEBUG_HW_DATA_BREAKPOINT_STATUS); 1350215976Sjmallett for (i = 0; i < 4; i++) 1351215976Sjmallett { 1352215976Sjmallett context->hw_dbp.address[i] = cvmx_read_csr(CVMX_DEBUG_HW_DATA_BREAKPOINT_ADDRESS(i)); 1353215976Sjmallett context->hw_dbp.address_mask[i] = cvmx_read_csr(CVMX_DEBUG_HW_DATA_BREAKPOINT_ADDRESS_MASK(i)); 1354215976Sjmallett context->hw_dbp.asid[i] = cvmx_read_csr(CVMX_DEBUG_HW_DATA_BREAKPOINT_ASID(i)); 1355215976Sjmallett context->hw_dbp.control[i] = cvmx_read_csr(CVMX_DEBUG_HW_DATA_BREAKPOINT_CONTROL(i)); 1356215976Sjmallett } 1357215976Sjmallett 1358215976Sjmallett for (i = 0; i < cvmx_debug_globals->tlb_entries; i++) 1359215976Sjmallett { 1360215976Sjmallett CVMX_MT_COP0(i, COP0_INDEX); 1361215976Sjmallett asm volatile ("tlbr"); 1362215976Sjmallett CVMX_MF_COP0(context->tlbs[i].entrylo[0], COP0_ENTRYLO0); 1363215976Sjmallett CVMX_MF_COP0(context->tlbs[i].entrylo[1], COP0_ENTRYLO1); 1364215976Sjmallett CVMX_MF_COP0(context->tlbs[i].entryhi, COP0_ENTRYHI); 1365215976Sjmallett CVMX_MF_COP0(context->tlbs[i].pagemask, COP0_PAGEMASK); 1366215976Sjmallett } 1367215976Sjmallett CVMX_SYNCW; 1368215976Sjmallett} 1369215976Sjmallett 1370215976Sjmallettstatic void cvmx_debug_restore_core_context(volatile cvmx_debug_core_context_t *context) 1371215976Sjmallett{ 1372232812Sjmallett uint64_t hi, lo; 1373215976Sjmallett int i; 1374232812Sjmallett cvmx_debug_memcpy_align (__cvmx_debug_save_regs_area, (char *) context->regs, sizeof(context->regs)); 1375215976Sjmallett /* We don't change the TLB so no need to restore it. */ 1376215976Sjmallett cvmx_write_csr(CVMX_DEBUG_HW_DATA_BREAKPOINT_STATUS, context->hw_dbp.status); 1377215976Sjmallett for (i = 0; i < 4; i++) 1378215976Sjmallett { 1379215976Sjmallett cvmx_write_csr(CVMX_DEBUG_HW_DATA_BREAKPOINT_ADDRESS(i), context->hw_dbp.address[i]); 1380215976Sjmallett cvmx_write_csr(CVMX_DEBUG_HW_DATA_BREAKPOINT_ADDRESS_MASK(i), context->hw_dbp.address_mask[i]); 1381215976Sjmallett cvmx_write_csr(CVMX_DEBUG_HW_DATA_BREAKPOINT_ASID(i), context->hw_dbp.asid[i]); 1382215976Sjmallett cvmx_write_csr(CVMX_DEBUG_HW_DATA_BREAKPOINT_CONTROL(i), context->hw_dbp.control[i]); 1383215976Sjmallett } 1384215976Sjmallett cvmx_write_csr(CVMX_DEBUG_HW_INSTRUCTION_BREAKPOINT_STATUS, context->hw_ibp.status); 1385215976Sjmallett for (i = 0; i < 4; i++) 1386215976Sjmallett { 1387215976Sjmallett cvmx_write_csr(CVMX_DEBUG_HW_INSTRUCTION_BREAKPOINT_ADDRESS(i), context->hw_ibp.address[i]); 1388215976Sjmallett cvmx_write_csr(CVMX_DEBUG_HW_INSTRUCTION_BREAKPOINT_ADDRESS_MASK(i), context->hw_ibp.address_mask[i]); 1389215976Sjmallett cvmx_write_csr(CVMX_DEBUG_HW_INSTRUCTION_BREAKPOINT_ASID(i), context->hw_ibp.asid[i]); 1390215976Sjmallett cvmx_write_csr(CVMX_DEBUG_HW_INSTRUCTION_BREAKPOINT_CONTROL(i), context->hw_ibp.control[i]); 1391215976Sjmallett } 1392215976Sjmallett CVMX_MT_COP0(context->cop0.index, COP0_INDEX); 1393215976Sjmallett CVMX_MT_COP0(context->cop0.entrylo[0], COP0_ENTRYLO0); 1394215976Sjmallett CVMX_MT_COP0(context->cop0.entrylo[1], COP0_ENTRYLO1); 1395215976Sjmallett CVMX_MT_COP0(context->cop0.entryhi, COP0_ENTRYHI); 1396215976Sjmallett CVMX_MT_COP0(context->cop0.pagemask, COP0_PAGEMASK); 1397215976Sjmallett CVMX_MT_COP0(context->cop0.status, COP0_STATUS); 1398215976Sjmallett CVMX_MT_COP0(context->cop0.cause, COP0_CAUSE); 1399215976Sjmallett CVMX_MT_COP0(context->cop0.debug, COP0_DEBUG); 1400215976Sjmallett CVMX_MT_COP0(context->cop0.multicoredebug, COP0_MULTICOREDEBUG); 1401215976Sjmallett CVMX_MT_COP0(context->cop0.perfval[0], COP0_PERFVALUE0); 1402215976Sjmallett CVMX_MT_COP0(context->cop0.perfval[1], COP0_PERFVALUE1); 1403215976Sjmallett CVMX_MT_COP0(context->cop0.perfctrl[0], COP0_PERFCONTROL0); 1404215976Sjmallett CVMX_MT_COP0(context->cop0.perfctrl[1], COP0_PERFCONTROL1); 1405215976Sjmallett CVMX_MT_COP0(context->cop0.depc, COP0_DEPC); 1406215976Sjmallett CVMX_MT_COP0(context->cop0.desave, COP0_DESAVE); 1407232812Sjmallett lo = context->lo; 1408232812Sjmallett hi = context->hi; 1409232812Sjmallett asm("mtlo %0" :: "r"(lo)); 1410232812Sjmallett asm("mthi %0" :: "r"(hi)); 1411215976Sjmallett} 1412215976Sjmallett 1413215976Sjmallettstatic inline void cvmx_debug_print_cause(volatile cvmx_debug_core_context_t *context) 1414215976Sjmallett{ 1415215976Sjmallett if (!CVMX_DEBUG_LOGGING) 1416215976Sjmallett return; 1417215976Sjmallett if (context->cop0.multicoredebug & 1) 1418215976Sjmallett cvmx_dprintf("MCD0 was pulsed\n"); 1419215976Sjmallett if (context->cop0.multicoredebug & (1 << 16)) 1420215976Sjmallett cvmx_dprintf("Exception %lld in Debug Mode\n", (long long)((context->cop0.debug >> 10) & 0x1f)); 1421215976Sjmallett if (context->cop0.debug & (1 << 19)) 1422215976Sjmallett cvmx_dprintf("DDBSImpr\n"); 1423215976Sjmallett if (context->cop0.debug & (1 << 18)) 1424215976Sjmallett cvmx_dprintf("DDBLImpr\n"); 1425215976Sjmallett if (context->cop0.debug & (1 << 5)) 1426215976Sjmallett cvmx_dprintf("DINT\n"); 1427215976Sjmallett if (context->cop0.debug & (1 << 4)) 1428215976Sjmallett cvmx_dprintf("Debug Instruction Breakpoint (DIB) exception\n"); 1429215976Sjmallett if (context->cop0.debug & (1 << 3)) 1430215976Sjmallett cvmx_dprintf("Debug Date Break Store (DDBS) exception\n"); 1431215976Sjmallett if (context->cop0.debug & (1 << 2)) 1432215976Sjmallett cvmx_dprintf("Debug Date Break Load (DDBL) exception\n"); 1433215976Sjmallett if (context->cop0.debug & (1 << 1)) 1434215976Sjmallett cvmx_dprintf("Debug Breakpoint (DBp) exception\n"); 1435215976Sjmallett if (context->cop0.debug & (1 << 0)) 1436215976Sjmallett cvmx_dprintf("Debug Single Step (DSS) exception\n"); 1437215976Sjmallett} 1438215976Sjmallett 1439232812Sjmallettvoid __cvmx_debug_handler_stage3 (uint64_t lo, uint64_t hi) 1440215976Sjmallett{ 1441215976Sjmallett volatile cvmx_debug_core_context_t *context; 1442215976Sjmallett int comms_changed = 0; 1443215976Sjmallett 1444215976Sjmallett cvmx_debug_printf("Entering debug exception handler\n"); 1445215976Sjmallett cvmx_debug_printf("Debug named block at %p\n", cvmx_debug_globals); 1446215976Sjmallett if (__cvmx_debug_mode_exception_occured) 1447215976Sjmallett { 1448215976Sjmallett uint64_t depc; 1449215976Sjmallett CVMX_MF_COP0(depc, COP0_DEPC); 1450215976Sjmallett cvmx_dprintf("Unexpected debug-mode exception occured at 0x%llx, 0x%llx spinning\n", (long long) depc, (long long)(__cvmx_debug_mode_exception_occured)); 1451215976Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 1452215976Sjmallett panic("Unexpected debug-mode exception occured at 0x%llx, 0x%llx\n", (long long) depc, (long long)(__cvmx_debug_mode_exception_occured)); 1453215976Sjmallett#endif 1454215976Sjmallett while (1) 1455215976Sjmallett ; 1456215976Sjmallett } 1457215976Sjmallett 1458215976Sjmallett context = cvmx_debug_core_context(); 1459232812Sjmallett cvmx_debug_save_core_context(context, hi, lo); 1460215976Sjmallett 1461215976Sjmallett { 1462215976Sjmallett cvmx_debug_state_t state; 1463215976Sjmallett cvmx_spinlock_lock(&cvmx_debug_globals->lock); 1464215976Sjmallett state = cvmx_debug_get_state(); 1465215976Sjmallett state.ever_been_in_debug = 1; 1466215976Sjmallett cvmx_debug_update_state (state); 1467215976Sjmallett cvmx_spinlock_unlock(&cvmx_debug_globals->lock); 1468215976Sjmallett } 1469215976Sjmallett cvmx_debug_print_cause(context); 1470215976Sjmallett 1471215976Sjmallett do 1472215976Sjmallett { 1473215976Sjmallett int needs_proxy; 1474215976Sjmallett comms_changed = 0; 1475215976Sjmallett /* If the communication changes, change it. */ 1476215976Sjmallett cvmx_spinlock_lock(&cvmx_debug_globals->lock); 1477215976Sjmallett if (cvmx_debug_globals->comm_changed) 1478215976Sjmallett { 1479215976Sjmallett cvmx_debug_printf("Communication changed: %d\n", (int)cvmx_debug_globals->comm_changed); 1480215976Sjmallett if (cvmx_debug_globals->comm_changed > COMM_SIZE) 1481215976Sjmallett { 1482215976Sjmallett cvmx_dprintf("Unknown communication spinning: %lld > %d.\n", (long long)cvmx_debug_globals->comm_changed, (int)(COMM_SIZE)); 1483215976Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 1484215976Sjmallett panic("Unknown communication.\n"); 1485215976Sjmallett#endif 1486215976Sjmallett while (1) 1487215976Sjmallett ; 1488215976Sjmallett } 1489215976Sjmallett cvmx_debug_globals->comm_type = cvmx_debug_globals->comm_changed - 1; 1490215976Sjmallett cvmx_debug_globals->comm_changed = 0; 1491215976Sjmallett } 1492215976Sjmallett cvmx_spinlock_unlock(&cvmx_debug_globals->lock); 1493215976Sjmallett needs_proxy = cvmx_debug_comms[cvmx_debug_globals->comm_type]->needs_proxy; 1494215976Sjmallett 1495215976Sjmallett { 1496215976Sjmallett cvmx_debug_register_t debug_reg; 1497215976Sjmallett cvmx_debug_state_t state; 1498215976Sjmallett unsigned core = cvmx_get_core_num(); 1499215976Sjmallett 1500215976Sjmallett state = cvmx_debug_get_state(); 1501215976Sjmallett debug_reg.u64 = context->cop0.debug; 1502215976Sjmallett /* All cores stop on any exception. See if we want nothing from this and 1503215976Sjmallett it should resume. This needs to be done for non proxy based debugging 1504215976Sjmallett so that some non active-cores can control the other cores. */ 1505215976Sjmallett if (!cvmx_debug_stop_core(state, core, &debug_reg, needs_proxy)) 1506215976Sjmallett { 1507215976Sjmallett context->cop0.debug = debug_reg.u64; 1508215976Sjmallett break; 1509215976Sjmallett } 1510215976Sjmallett } 1511215976Sjmallett 1512215976Sjmallett if (needs_proxy) 1513215976Sjmallett { 1514215976Sjmallett cvmx_debug_register_t debug_reg; 1515215976Sjmallett debug_reg.u64 = context->cop0.debug; 1516215976Sjmallett cvmx_debug_printf("Starting to proxy\n"); 1517215976Sjmallett comms_changed = cvmx_debug_perform_proxy(&debug_reg, context); 1518215976Sjmallett context->cop0.debug = debug_reg.u64; 1519215976Sjmallett } 1520215976Sjmallett else 1521215976Sjmallett { 1522215976Sjmallett cvmx_debug_printf("Starting to wait for remote host\n"); 1523215976Sjmallett cvmx_debug_comms[cvmx_debug_globals->comm_type]->wait_for_resume(context, cvmx_debug_get_state()); 1524215976Sjmallett } 1525215976Sjmallett } while (comms_changed); 1526215976Sjmallett 1527215976Sjmallett cvmx_debug_clear_status(context); 1528215976Sjmallett 1529215976Sjmallett cvmx_debug_restore_core_context(context); 1530215976Sjmallett cvmx_debug_printf("Exiting debug exception handler\n"); 1531215976Sjmallett} 1532215976Sjmallett 1533215976Sjmallettvoid cvmx_debug_trigger_exception(void) 1534215976Sjmallett{ 1535215976Sjmallett /* Set CVMX_CIU_DINT to enter debug exception handler. */ 1536232812Sjmallett cvmx_write_csr (CVMX_CIU_DINT, 1u << cvmx_get_core_num ()); 1537215976Sjmallett /* Perform an immediate read after every write to an RSL register to force 1538215976Sjmallett the write to complete. It doesn't matter what RSL read we do, so we 1539215976Sjmallett choose CVMX_MIO_BOOT_BIST_STAT because it is fast and harmless */ 1540215976Sjmallett cvmx_read_csr (CVMX_MIO_BOOT_BIST_STAT); 1541215976Sjmallett} 1542215976Sjmallett 1543215976Sjmallett/** 1544215976Sjmallett * Inform debugger about the end of the program. This is 1545215976Sjmallett * called from crt0 after all the C cleanup code finishes. 1546215976Sjmallett * Our current stack is the C one, not the debug exception 1547215976Sjmallett * stack. */ 1548215976Sjmallettvoid cvmx_debug_finish(void) 1549215976Sjmallett{ 1550215976Sjmallett unsigned coreid = cvmx_get_core_num(); 1551215976Sjmallett cvmx_debug_state_t state; 1552215976Sjmallett 1553232812Sjmallett if (!cvmx_debug_globals) return; 1554215976Sjmallett cvmx_debug_printf ("Debug _exit reached!, core %d, cvmx_debug_globals = %p\n", coreid, cvmx_debug_globals); 1555215976Sjmallett 1556215976Sjmallett#ifndef CVMX_BUILD_FOR_LINUX_KERNEL 1557215976Sjmallett fflush (stdout); 1558215976Sjmallett fflush (stderr); 1559215976Sjmallett#endif 1560215976Sjmallett 1561215976Sjmallett cvmx_spinlock_lock(&cvmx_debug_globals->lock); 1562215976Sjmallett state = cvmx_debug_get_state(); 1563232812Sjmallett state.known_cores ^= (1u << coreid); 1564232812Sjmallett state.core_finished |= (1u <<coreid); 1565215976Sjmallett cvmx_debug_update_state(state); 1566215976Sjmallett 1567215976Sjmallett /* Tell the user the core has finished. */ 1568215976Sjmallett if (state.ever_been_in_debug) 1569232812Sjmallett cvmx_debug_putcorepacket("finished.", coreid); 1570215976Sjmallett 1571215976Sjmallett /* Notify the debugger if all cores have completed the program */ 1572215976Sjmallett if ((cvmx_debug_core_mask () & state.core_finished) == cvmx_debug_core_mask ()) 1573215976Sjmallett { 1574215976Sjmallett cvmx_debug_printf("All cores done!\n"); 1575215976Sjmallett if (state.ever_been_in_debug) 1576215976Sjmallett cvmx_debug_putpacket_noformat("D0"); 1577215976Sjmallett } 1578215976Sjmallett if (state.focus_core == coreid && state.known_cores != 0) 1579215976Sjmallett { 1580215976Sjmallett /* Loop through cores looking for someone to handle interrupts. 1581215976Sjmallett Since we already check that known_cores is non zero, this 1582215976Sjmallett should always find a core */ 1583215976Sjmallett unsigned newcore; 1584232812Sjmallett for (newcore = 0; newcore < CVMX_MAX_CORES; newcore++) 1585215976Sjmallett { 1586232812Sjmallett if (state.known_cores & (1u<<newcore)) 1587215976Sjmallett { 1588215976Sjmallett cvmx_debug_printf("Routing uart interrupts to Core #%u.\n", newcore); 1589215976Sjmallett cvmx_debug_set_focus_core(&state, newcore); 1590215976Sjmallett cvmx_debug_update_state(state); 1591215976Sjmallett break; 1592215976Sjmallett } 1593215976Sjmallett } 1594215976Sjmallett } 1595215976Sjmallett cvmx_spinlock_unlock(&cvmx_debug_globals->lock); 1596215976Sjmallett 1597215976Sjmallett /* If we ever been in the debug, report to it that we have exited the core. */ 1598215976Sjmallett if (state.ever_been_in_debug) 1599215976Sjmallett cvmx_debug_trigger_exception(); 1600215976Sjmallett} 1601