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