~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/riscv/kernel/kgdb.c

Version: ~ [ linux-6.12-rc7 ] ~ [ linux-6.11.7 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.60 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.116 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.171 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.229 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.285 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.323 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.12 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

Diff markup

Differences between /arch/riscv/kernel/kgdb.c (Version linux-6.12-rc7) and /arch/i386/kernel/kgdb.c (Version linux-5.10.229)


  1 // SPDX-License-Identifier: GPL-2.0-only            1 
  2 /*                                                
  3  * Copyright (C) 2020 SiFive                      
  4  */                                               
  5                                                   
  6 #include <linux/ptrace.h>                         
  7 #include <linux/kdebug.h>                         
  8 #include <linux/bug.h>                            
  9 #include <linux/kgdb.h>                           
 10 #include <linux/irqflags.h>                       
 11 #include <linux/string.h>                         
 12 #include <asm/cacheflush.h>                       
 13 #include <asm/gdb_xml.h>                          
 14 #include <asm/insn.h>                             
 15                                                   
 16 enum {                                            
 17         NOT_KGDB_BREAK = 0,                       
 18         KGDB_SW_BREAK,                            
 19         KGDB_COMPILED_BREAK,                      
 20         KGDB_SW_SINGLE_STEP                       
 21 };                                                
 22                                                   
 23 static unsigned long stepped_address;             
 24 static unsigned int stepped_opcode;               
 25                                                   
 26 static int decode_register_index(unsigned long    
 27 {                                                 
 28         return (opcode >> offset) & 0x1F;         
 29 }                                                 
 30                                                   
 31 static int decode_register_index_short(unsigne    
 32 {                                                 
 33         return ((opcode >> offset) & 0x7) + 8;    
 34 }                                                 
 35                                                   
 36 /* Calculate the new address for after a step     
 37 static int get_step_address(struct pt_regs *re    
 38 {                                                 
 39         unsigned long pc = regs->epc;             
 40         unsigned long *regs_ptr = (unsigned lo    
 41         unsigned int rs1_num, rs2_num;            
 42         int op_code;                              
 43                                                   
 44         if (get_kernel_nofault(op_code, (void     
 45                 return -EINVAL;                   
 46         if ((op_code & __INSN_LENGTH_MASK) !=     
 47                 if (riscv_insn_is_c_jalr(op_co    
 48                     riscv_insn_is_c_jr(op_code    
 49                         rs1_num = decode_regis    
 50                         *next_addr = regs_ptr[    
 51                 } else if (riscv_insn_is_c_j(o    
 52                            riscv_insn_is_c_jal    
 53                         *next_addr = RVC_EXTRA    
 54                 } else if (riscv_insn_is_c_beq    
 55                         rs1_num = decode_regis    
 56                                                   
 57                         if (!rs1_num || regs_p    
 58                                 *next_addr = R    
 59                         else                      
 60                                 *next_addr = p    
 61                 } else if (riscv_insn_is_c_bne    
 62                         rs1_num =                 
 63                             decode_register_in    
 64                         if (rs1_num && regs_pt    
 65                                 *next_addr = R    
 66                         else                      
 67                                 *next_addr = p    
 68                 } else {                          
 69                         *next_addr = pc + 2;      
 70                 }                                 
 71         } else {                                  
 72                 if ((op_code & __INSN_OPCODE_M    
 73                         bool result = false;      
 74                         long imm = RV_EXTRACT_    
 75                         unsigned long rs1_val     
 76                                                   
 77                         rs1_num = decode_regis    
 78                         rs2_num = decode_regis    
 79                         if (rs1_num)              
 80                                 rs1_val = regs    
 81                         if (rs2_num)              
 82                                 rs2_val = regs    
 83                                                   
 84                         if (riscv_insn_is_beq(    
 85                                 result = (rs1_    
 86                         else if (riscv_insn_is    
 87                                 result = (rs1_    
 88                         else if (riscv_insn_is    
 89                                 result =          
 90                                     ((long)rs1    
 91                                      (long)rs2    
 92                         else if (riscv_insn_is    
 93                                 result =          
 94                                     ((long)rs1    
 95                                      (long)rs2    
 96                         else if (riscv_insn_is    
 97                                 result = (rs1_    
 98                         else if (riscv_insn_is    
 99                                 result = (rs1_    
100                         if (result)               
101                                 *next_addr = i    
102                         else                      
103                                 *next_addr = p    
104                 } else if (riscv_insn_is_jal(o    
105                         *next_addr = RV_EXTRAC    
106                 } else if (riscv_insn_is_jalr(    
107                         rs1_num = decode_regis    
108                         if (rs1_num)              
109                                 *next_addr = (    
110                         *next_addr += RV_EXTRA    
111                 } else if (riscv_insn_is_sret(    
112                         *next_addr = pc;          
113                 } else {                          
114                         *next_addr = pc + 4;      
115                 }                                 
116         }                                         
117         return 0;                                 
118 }                                                 
119                                                   
120 static int do_single_step(struct pt_regs *regs    
121 {                                                 
122         /* Determine where the target instruct    
123         unsigned long addr = 0;                   
124         int error = get_step_address(regs, &ad    
125                                                   
126         if (error)                                
127                 return error;                     
128                                                   
129         /* Store the op code in the stepped ad    
130         error = get_kernel_nofault(stepped_opc    
131         if (error)                                
132                 return error;                     
133                                                   
134         stepped_address = addr;                   
135                                                   
136         /* Replace the op code with the break     
137         error = copy_to_kernel_nofault((void *    
138                                    arch_kgdb_o    
139                                    BREAK_INSTR    
140         /* Flush and return */                    
141         if (!error) {                             
142                 flush_icache_range(addr, addr     
143                 kgdb_single_step = 1;             
144                 atomic_set(&kgdb_cpu_doing_sin    
145                            raw_smp_processor_i    
146         } else {                                  
147                 stepped_address = 0;              
148                 stepped_opcode = 0;               
149         }                                         
150         return error;                             
151 }                                                 
152                                                   
153 /* Undo a single step */                          
154 static void undo_single_step(struct pt_regs *r    
155 {                                                 
156         if (stepped_opcode != 0) {                
157                 copy_to_kernel_nofault((void *    
158                                    (void *)&st    
159                 flush_icache_range(stepped_add    
160                                    stepped_add    
161         }                                         
162         stepped_address = 0;                      
163         stepped_opcode = 0;                       
164         kgdb_single_step = 0;                     
165         atomic_set(&kgdb_cpu_doing_single_step    
166 }                                                 
167                                                   
168 struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_N    
169         {DBG_REG_ZERO, GDB_SIZEOF_REG, -1},       
170         {DBG_REG_RA, GDB_SIZEOF_REG, offsetof(    
171         {DBG_REG_SP, GDB_SIZEOF_REG, offsetof(    
172         {DBG_REG_GP, GDB_SIZEOF_REG, offsetof(    
173         {DBG_REG_TP, GDB_SIZEOF_REG, offsetof(    
174         {DBG_REG_T0, GDB_SIZEOF_REG, offsetof(    
175         {DBG_REG_T1, GDB_SIZEOF_REG, offsetof(    
176         {DBG_REG_T2, GDB_SIZEOF_REG, offsetof(    
177         {DBG_REG_FP, GDB_SIZEOF_REG, offsetof(    
178         {DBG_REG_S1, GDB_SIZEOF_REG, offsetof(    
179         {DBG_REG_A0, GDB_SIZEOF_REG, offsetof(    
180         {DBG_REG_A1, GDB_SIZEOF_REG, offsetof(    
181         {DBG_REG_A2, GDB_SIZEOF_REG, offsetof(    
182         {DBG_REG_A3, GDB_SIZEOF_REG, offsetof(    
183         {DBG_REG_A4, GDB_SIZEOF_REG, offsetof(    
184         {DBG_REG_A5, GDB_SIZEOF_REG, offsetof(    
185         {DBG_REG_A6, GDB_SIZEOF_REG, offsetof(    
186         {DBG_REG_A7, GDB_SIZEOF_REG, offsetof(    
187         {DBG_REG_S2, GDB_SIZEOF_REG, offsetof(    
188         {DBG_REG_S3, GDB_SIZEOF_REG, offsetof(    
189         {DBG_REG_S4, GDB_SIZEOF_REG, offsetof(    
190         {DBG_REG_S5, GDB_SIZEOF_REG, offsetof(    
191         {DBG_REG_S6, GDB_SIZEOF_REG, offsetof(    
192         {DBG_REG_S7, GDB_SIZEOF_REG, offsetof(    
193         {DBG_REG_S8, GDB_SIZEOF_REG, offsetof(    
194         {DBG_REG_S9, GDB_SIZEOF_REG, offsetof(    
195         {DBG_REG_S10, GDB_SIZEOF_REG, offsetof    
196         {DBG_REG_S11, GDB_SIZEOF_REG, offsetof    
197         {DBG_REG_T3, GDB_SIZEOF_REG, offsetof(    
198         {DBG_REG_T4, GDB_SIZEOF_REG, offsetof(    
199         {DBG_REG_T5, GDB_SIZEOF_REG, offsetof(    
200         {DBG_REG_T6, GDB_SIZEOF_REG, offsetof(    
201         {DBG_REG_EPC, GDB_SIZEOF_REG, offsetof    
202         {DBG_REG_STATUS, GDB_SIZEOF_REG, offse    
203         {DBG_REG_BADADDR, GDB_SIZEOF_REG, offs    
204         {DBG_REG_CAUSE, GDB_SIZEOF_REG, offset    
205 };                                                
206                                                   
207 char *dbg_get_reg(int regno, void *mem, struct    
208 {                                                 
209         if (regno >= DBG_MAX_REG_NUM || regno     
210                 return NULL;                      
211                                                   
212         if (dbg_reg_def[regno].offset != -1)      
213                 memcpy(mem, (void *)regs + dbg    
214                        dbg_reg_def[regno].size    
215         else                                      
216                 memset(mem, 0, dbg_reg_def[reg    
217         return dbg_reg_def[regno].name;           
218 }                                                 
219                                                   
220 int dbg_set_reg(int regno, void *mem, struct p    
221 {                                                 
222         if (regno >= DBG_MAX_REG_NUM || regno     
223                 return -EINVAL;                   
224                                                   
225         if (dbg_reg_def[regno].offset != -1)      
226                 memcpy((void *)regs + dbg_reg_    
227                        dbg_reg_def[regno].size    
228         return 0;                                 
229 }                                                 
230                                                   
231 void                                              
232 sleeping_thread_to_gdb_regs(unsigned long *gdb    
233 {                                                 
234         /* Initialize to zero */                  
235         memset((char *)gdb_regs, 0, NUMREGBYTE    
236                                                   
237         gdb_regs[DBG_REG_SP_OFF] = task->threa    
238         gdb_regs[DBG_REG_FP_OFF] = task->threa    
239         gdb_regs[DBG_REG_S1_OFF] = task->threa    
240         gdb_regs[DBG_REG_S2_OFF] = task->threa    
241         gdb_regs[DBG_REG_S3_OFF] = task->threa    
242         gdb_regs[DBG_REG_S4_OFF] = task->threa    
243         gdb_regs[DBG_REG_S5_OFF] = task->threa    
244         gdb_regs[DBG_REG_S6_OFF] = task->threa    
245         gdb_regs[DBG_REG_S7_OFF] = task->threa    
246         gdb_regs[DBG_REG_S8_OFF] = task->threa    
247         gdb_regs[DBG_REG_S9_OFF] = task->threa    
248         gdb_regs[DBG_REG_S10_OFF] = task->thre    
249         gdb_regs[DBG_REG_EPC_OFF] = task->thre    
250 }                                                 
251                                                   
252 void kgdb_arch_set_pc(struct pt_regs *regs, un    
253 {                                                 
254         regs->epc = pc;                           
255 }                                                 
256                                                   
257 void kgdb_arch_handle_qxfer_pkt(char *remcom_i    
258                                 char *remcom_o    
259 {                                                 
260         if (!strncmp(remcom_in_buffer, gdb_xfe    
261                      sizeof(gdb_xfer_read_targ    
262                 strcpy(remcom_out_buffer, risc    
263         else if (!strncmp(remcom_in_buffer, gd    
264                           sizeof(gdb_xfer_read    
265                 strcpy(remcom_out_buffer, risc    
266 }                                                 
267                                                   
268 static inline void kgdb_arch_update_addr(struc    
269                                          char     
270 {                                                 
271         unsigned long addr;                       
272         char *ptr;                                
273                                                   
274         ptr = &remcom_in_buffer[1];               
275         if (kgdb_hex2long(&ptr, &addr))           
276                 regs->epc = addr;                 
277 }                                                 
278                                                   
279 int kgdb_arch_handle_exception(int vector, int    
280                                char *remcom_in    
281                                struct pt_regs     
282 {                                                 
283         int err = 0;                              
284                                                   
285         undo_single_step(regs);                   
286                                                   
287         switch (remcom_in_buffer[0]) {            
288         case 'c':                                 
289         case 'D':                                 
290         case 'k':                                 
291                 if (remcom_in_buffer[0] == 'c'    
292                         kgdb_arch_update_addr(    
293                 break;                            
294         case 's':                                 
295                 kgdb_arch_update_addr(regs, re    
296                 err = do_single_step(regs);       
297                 break;                            
298         default:                                  
299                 err = -1;                         
300         }                                         
301         return err;                               
302 }                                                 
303                                                   
304 static int kgdb_riscv_kgdbbreak(unsigned long     
305 {                                                 
306         if (stepped_address == addr)              
307                 return KGDB_SW_SINGLE_STEP;       
308         if (atomic_read(&kgdb_setting_breakpoi    
309                 if (addr == (unsigned long)&kg    
310                         return KGDB_COMPILED_B    
311                                                   
312         return kgdb_has_hit_break(addr);          
313 }                                                 
314                                                   
315 static int kgdb_riscv_notify(struct notifier_b    
316                              void *ptr)           
317 {                                                 
318         struct die_args *args = (struct die_ar    
319         struct pt_regs *regs = args->regs;        
320         unsigned long flags;                      
321         int type;                                 
322                                                   
323         if (user_mode(regs))                      
324                 return NOTIFY_DONE;               
325                                                   
326         type = kgdb_riscv_kgdbbreak(regs->epc)    
327         if (type == NOT_KGDB_BREAK && cmd == D    
328                 return NOTIFY_DONE;               
329                                                   
330         local_irq_save(flags);                    
331                                                   
332         if (kgdb_handle_exception(type == KGDB    
333                                   args->signr,    
334                 return NOTIFY_DONE;               
335                                                   
336         if (type == KGDB_COMPILED_BREAK)          
337                 regs->epc += 4;                   
338                                                   
339         local_irq_restore(flags);                 
340                                                   
341         return NOTIFY_STOP;                       
342 }                                                 
343                                                   
344 static struct notifier_block kgdb_notifier = {    
345         .notifier_call = kgdb_riscv_notify,       
346 };                                                
347                                                   
348 int kgdb_arch_init(void)                          
349 {                                                 
350         register_die_notifier(&kgdb_notifier);    
351                                                   
352         return 0;                                 
353 }                                                 
354                                                   
355 void kgdb_arch_exit(void)                         
356 {                                                 
357         unregister_die_notifier(&kgdb_notifier    
358 }                                                 
359                                                   
360 /*                                                
361  * Global data                                    
362  */                                               
363 #ifdef CONFIG_RISCV_ISA_C                         
364 const struct kgdb_arch arch_kgdb_ops = {          
365         .gdb_bpt_instr = {0x02, 0x90},  /* c.e    
366 };                                                
367 #else                                             
368 const struct kgdb_arch arch_kgdb_ops = {          
369         .gdb_bpt_instr = {0x73, 0x00, 0x10, 0x    
370 };                                                
371 #endif                                            
372                                                   

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php