Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /* kgdb.c: KGDB support for 32-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/sched.h>
0010 
0011 #include <asm/kdebug.h>
0012 #include <asm/ptrace.h>
0013 #include <asm/irq.h>
0014 #include <asm/cacheflush.h>
0015 
0016 #include "kernel.h"
0017 #include "entry.h"
0018 
0019 void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
0020 {
0021     struct reg_window32 *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_window32 *) regs->u_regs[UREG_FP];
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_F31; i++)
0035         gdb_regs[i] = 0;
0036 
0037     gdb_regs[GDB_Y] = regs->y;
0038     gdb_regs[GDB_PSR] = regs->psr;
0039     gdb_regs[GDB_WIM] = 0;
0040     gdb_regs[GDB_TBR] = (unsigned long) &trapbase;
0041     gdb_regs[GDB_PC] = regs->pc;
0042     gdb_regs[GDB_NPC] = regs->npc;
0043     gdb_regs[GDB_FSR] = 0;
0044     gdb_regs[GDB_CSR] = 0;
0045 }
0046 
0047 void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
0048 {
0049     struct thread_info *t = task_thread_info(p);
0050     struct reg_window32 *win;
0051     int i;
0052 
0053     for (i = GDB_G0; i < GDB_G6; i++)
0054         gdb_regs[i] = 0;
0055     gdb_regs[GDB_G6] = (unsigned long) t;
0056     gdb_regs[GDB_G7] = 0;
0057     for (i = GDB_O0; i < GDB_SP; i++)
0058         gdb_regs[i] = 0;
0059     gdb_regs[GDB_SP] = t->ksp;
0060     gdb_regs[GDB_O7] = 0;
0061 
0062     win = (struct reg_window32 *) t->ksp;
0063     for (i = 0; i < 8; i++)
0064         gdb_regs[GDB_L0 + i] = win->locals[i];
0065     for (i = 0; i < 8; i++)
0066         gdb_regs[GDB_I0 + i] = win->ins[i];
0067 
0068     for (i = GDB_F0; i <= GDB_F31; i++)
0069         gdb_regs[i] = 0;
0070 
0071     gdb_regs[GDB_Y] = 0;
0072 
0073     gdb_regs[GDB_PSR] = t->kpsr;
0074     gdb_regs[GDB_WIM] = t->kwim;
0075     gdb_regs[GDB_TBR] = (unsigned long) &trapbase;
0076     gdb_regs[GDB_PC] = t->kpc;
0077     gdb_regs[GDB_NPC] = t->kpc + 4;
0078     gdb_regs[GDB_FSR] = 0;
0079     gdb_regs[GDB_CSR] = 0;
0080 }
0081 
0082 void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs)
0083 {
0084     struct reg_window32 *win;
0085     int i;
0086 
0087     for (i = 0; i < 15; i++)
0088         regs->u_regs[UREG_G1 + i] = gdb_regs[GDB_G1 + i];
0089 
0090     /* If the PSR register is changing, we have to preserve
0091      * the CWP field, otherwise window save/restore explodes.
0092      */
0093     if (regs->psr != gdb_regs[GDB_PSR]) {
0094         unsigned long cwp = regs->psr & PSR_CWP;
0095 
0096         regs->psr = (gdb_regs[GDB_PSR] & ~PSR_CWP) | cwp;
0097     }
0098 
0099     regs->pc = gdb_regs[GDB_PC];
0100     regs->npc = gdb_regs[GDB_NPC];
0101     regs->y = gdb_regs[GDB_Y];
0102 
0103     win = (struct reg_window32 *) regs->u_regs[UREG_FP];
0104     for (i = 0; i < 8; i++)
0105         win->locals[i] = gdb_regs[GDB_L0 + i];
0106     for (i = 0; i < 8; i++)
0107         win->ins[i] = gdb_regs[GDB_I0 + i];
0108 }
0109 
0110 int kgdb_arch_handle_exception(int e_vector, int signo, int err_code,
0111                    char *remcomInBuffer, char *remcomOutBuffer,
0112                    struct pt_regs *linux_regs)
0113 {
0114     unsigned long addr;
0115     char *ptr;
0116 
0117     switch (remcomInBuffer[0]) {
0118     case 'c':
0119         /* try to read optional parameter, pc unchanged if no parm */
0120         ptr = &remcomInBuffer[1];
0121         if (kgdb_hex2long(&ptr, &addr)) {
0122             linux_regs->pc = addr;
0123             linux_regs->npc = addr + 4;
0124         }
0125         fallthrough;
0126 
0127     case 'D':
0128     case 'k':
0129         if (linux_regs->pc == (unsigned long) arch_kgdb_breakpoint) {
0130             linux_regs->pc = linux_regs->npc;
0131             linux_regs->npc += 4;
0132         }
0133         return 0;
0134     }
0135     return -1;
0136 }
0137 
0138 asmlinkage void kgdb_trap(unsigned long trap_level, struct pt_regs *regs)
0139 {
0140     unsigned long flags;
0141 
0142     if (user_mode(regs)) {
0143         do_hw_interrupt(regs, trap_level);
0144         return;
0145     }
0146 
0147     flushw_all();
0148 
0149     local_irq_save(flags);
0150     kgdb_handle_exception(trap_level, SIGTRAP, 0, regs);
0151     local_irq_restore(flags);
0152 }
0153 
0154 int kgdb_arch_init(void)
0155 {
0156     return 0;
0157 }
0158 
0159 void kgdb_arch_exit(void)
0160 {
0161 }
0162 
0163 void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long ip)
0164 {
0165     regs->pc = ip;
0166     regs->npc = regs->pc + 4;
0167 }
0168 
0169 const struct kgdb_arch arch_kgdb_ops = {
0170     /* Breakpoint instruction: ta 0x7d */
0171     .gdb_bpt_instr      = { 0x91, 0xd0, 0x20, 0x7d },
0172 };