Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /* kgdb.c: KGDB support for 64-bit sparc.
0003  *
0004  * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
0005  */
0006 
0007 #include <linux/kgdb.h>
0008 #include <linux/kdebug.h>
0009 #include <linux/ftrace.h>
0010 #include <linux/context_tracking.h>
0011 
0012 #include <asm/cacheflush.h>
0013 #include <asm/kdebug.h>
0014 #include <asm/ptrace.h>
0015 #include <asm/irq.h>
0016 
0017 #include "kernel.h"
0018 
0019 void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
0020 {
0021     struct reg_window *win;
0022     int i;
0023 
0024     gdb_regs[GDB_G0] = 0;
0025     for (i = 0; i < 15; i++)
0026         gdb_regs[GDB_G1 + i] = regs->u_regs[UREG_G1 + i];
0027 
0028     win = (struct reg_window *) (regs->u_regs[UREG_FP] + STACK_BIAS);
0029     for (i = 0; i < 8; i++)
0030         gdb_regs[GDB_L0 + i] = win->locals[i];
0031     for (i = 0; i < 8; i++)
0032         gdb_regs[GDB_I0 + i] = win->ins[i];
0033 
0034     for (i = GDB_F0; i <= GDB_F62; i++)
0035         gdb_regs[i] = 0;
0036 
0037     gdb_regs[GDB_PC] = regs->tpc;
0038     gdb_regs[GDB_NPC] = regs->tnpc;
0039     gdb_regs[GDB_STATE] = regs->tstate;
0040     gdb_regs[GDB_FSR] = 0;
0041     gdb_regs[GDB_FPRS] = 0;
0042     gdb_regs[GDB_Y] = regs->y;
0043 }
0044 
0045 void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
0046 {
0047     struct thread_info *t = task_thread_info(p);
0048     extern unsigned int switch_to_pc;
0049     extern unsigned int ret_from_fork;
0050     struct reg_window *win;
0051     unsigned long pc, cwp;
0052     int i;
0053 
0054     for (i = GDB_G0; i < GDB_G6; i++)
0055         gdb_regs[i] = 0;
0056     gdb_regs[GDB_G6] = (unsigned long) t;
0057     gdb_regs[GDB_G7] = (unsigned long) p;
0058     for (i = GDB_O0; i < GDB_SP; i++)
0059         gdb_regs[i] = 0;
0060     gdb_regs[GDB_SP] = t->ksp;
0061     gdb_regs[GDB_O7] = 0;
0062 
0063     win = (struct reg_window *) (t->ksp + STACK_BIAS);
0064     for (i = 0; i < 8; i++)
0065         gdb_regs[GDB_L0 + i] = win->locals[i];
0066     for (i = 0; i < 8; i++)
0067         gdb_regs[GDB_I0 + i] = win->ins[i];
0068 
0069     for (i = GDB_F0; i <= GDB_F62; i++)
0070         gdb_regs[i] = 0;
0071 
0072     if (t->new_child)
0073         pc = (unsigned long) &ret_from_fork;
0074     else
0075         pc = (unsigned long) &switch_to_pc;
0076 
0077     gdb_regs[GDB_PC] = pc;
0078     gdb_regs[GDB_NPC] = pc + 4;
0079 
0080     cwp = __thread_flag_byte_ptr(t)[TI_FLAG_BYTE_CWP];
0081 
0082     gdb_regs[GDB_STATE] = (TSTATE_PRIV | TSTATE_IE | cwp);
0083     gdb_regs[GDB_FSR] = 0;
0084     gdb_regs[GDB_FPRS] = 0;
0085     gdb_regs[GDB_Y] = 0;
0086 }
0087 
0088 void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs)
0089 {
0090     struct reg_window *win;
0091     int i;
0092 
0093     for (i = 0; i < 15; i++)
0094         regs->u_regs[UREG_G1 + i] = gdb_regs[GDB_G1 + i];
0095 
0096     /* If the TSTATE register is changing, we have to preserve
0097      * the CWP field, otherwise window save/restore explodes.
0098      */
0099     if (regs->tstate != gdb_regs[GDB_STATE]) {
0100         unsigned long cwp = regs->tstate & TSTATE_CWP;
0101 
0102         regs->tstate = (gdb_regs[GDB_STATE] & ~TSTATE_CWP) | cwp;
0103     }
0104 
0105     regs->tpc = gdb_regs[GDB_PC];
0106     regs->tnpc = gdb_regs[GDB_NPC];
0107     regs->y = gdb_regs[GDB_Y];
0108 
0109     win = (struct reg_window *) (regs->u_regs[UREG_FP] + STACK_BIAS);
0110     for (i = 0; i < 8; i++)
0111         win->locals[i] = gdb_regs[GDB_L0 + i];
0112     for (i = 0; i < 8; i++)
0113         win->ins[i] = gdb_regs[GDB_I0 + i];
0114 }
0115 
0116 #ifdef CONFIG_SMP
0117 void __irq_entry smp_kgdb_capture_client(int irq, struct pt_regs *regs)
0118 {
0119     unsigned long flags;
0120 
0121     __asm__ __volatile__("rdpr      %%pstate, %0\n\t"
0122                  "wrpr      %0, %1, %%pstate"
0123                  : "=r" (flags)
0124                  : "i" (PSTATE_IE));
0125 
0126     flushw_all();
0127 
0128     if (atomic_read(&kgdb_active) != -1)
0129         kgdb_nmicallback(raw_smp_processor_id(), regs);
0130 
0131     __asm__ __volatile__("wrpr  %0, 0, %%pstate"
0132                  : : "r" (flags));
0133 }
0134 #endif
0135 
0136 int kgdb_arch_handle_exception(int e_vector, int signo, int err_code,
0137                    char *remcomInBuffer, char *remcomOutBuffer,
0138                    struct pt_regs *linux_regs)
0139 {
0140     unsigned long addr;
0141     char *ptr;
0142 
0143     switch (remcomInBuffer[0]) {
0144     case 'c':
0145         /* try to read optional parameter, pc unchanged if no parm */
0146         ptr = &remcomInBuffer[1];
0147         if (kgdb_hex2long(&ptr, &addr)) {
0148             linux_regs->tpc = addr;
0149             linux_regs->tnpc = addr + 4;
0150         }
0151         fallthrough;
0152 
0153     case 'D':
0154     case 'k':
0155         if (linux_regs->tpc == (unsigned long) arch_kgdb_breakpoint) {
0156             linux_regs->tpc = linux_regs->tnpc;
0157             linux_regs->tnpc += 4;
0158         }
0159         return 0;
0160     }
0161     return -1;
0162 }
0163 
0164 asmlinkage void kgdb_trap(unsigned long trap_level, struct pt_regs *regs)
0165 {
0166     enum ctx_state prev_state = exception_enter();
0167     unsigned long flags;
0168 
0169     if (user_mode(regs)) {
0170         bad_trap(regs, trap_level);
0171         goto out;
0172     }
0173 
0174     flushw_all();
0175 
0176     local_irq_save(flags);
0177     kgdb_handle_exception(0x172, SIGTRAP, 0, regs);
0178     local_irq_restore(flags);
0179 out:
0180     exception_exit(prev_state);
0181 }
0182 
0183 int kgdb_arch_init(void)
0184 {
0185     return 0;
0186 }
0187 
0188 void kgdb_arch_exit(void)
0189 {
0190 }
0191 
0192 void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long ip)
0193 {
0194     regs->tpc = ip;
0195     regs->tnpc = regs->tpc + 4;
0196 }
0197 
0198 const struct kgdb_arch arch_kgdb_ops = {
0199     /* Breakpoint instruction: ta 0x72 */
0200     .gdb_bpt_instr      = { 0x91, 0xd0, 0x20, 0x72 },
0201 };