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, &regno))
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, &regno)
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