1 #include <stdlib.h>
2 #include <string.h>
3 #include <stdio.h>
4 #include <errno.h>
5 #include <signal.h>
6 #include "asm.h"
7 #include "processor.h"
8 #include "spinlock.h"
9 #include "lwp.h"
10 #include "lwp_threads.h"
11 #include "sys_state.h"
12 #include "context.h"
13 #include "cache.h"
14 #include "video.h"
15 #include "ogcsys.h"
16
17 #include "lwp_config.h"
18
19 #include "tcpip.h"
20 #include "geckousb.h"
21 #include "debug_if.h"
22 #include "debug_supp.h"
23
24 #define GEKKO_MAX_BP 256
25
26 #define SP_REGNUM 1 //register no. for stackpointer
27 #define PC_REGNUM 64 //register no. for programcounter (srr0)
28
29 #define BUFMAX 2048 //we take the same as in ppc-stub.c
30
31 #define BPCODE 0x7d821008
32
33 #define highhex(x) hexchars [((x)>>4)&0xf]
34 #define lowhex(x) hexchars [(x)&0xf]
35
36 #if UIP_LOGGING == 1
37 #include <stdio.h>
38 #define UIP_LOG(m) uip_log(__FILE__,__LINE__,m)
39 #else
40 #define UIP_LOG(m)
41 #endif /* UIP_LOGGING == 1 */
42
43 static s32 dbg_active = 0;
44 static s32 dbg_instep = 0;
45 static s32 dbg_initialized = 0;
46
47 static struct dbginterface *current_device = NULL;
48
49 static char remcomInBuffer[BUFMAX];
50 static char remcomOutBuffer[BUFMAX];
51
52 const char hexchars[]="0123456789abcdef";
53
54 static struct hard_trap_info {
55 u32 tt;
56 u8 signo;
57 } hard_trap_info[] = {
58 {EX_MACH_CHECK,SIGSEGV},/* Machine Check */
59 {EX_DSI,SIGSEGV}, /* Adress Error(store) DSI */
60 {EX_ISI,SIGBUS}, /* Instruction Bus Error ISI */
61 {EX_INT,SIGINT}, /* Interrupt */
62 {EX_ALIGN,SIGBUS}, /* Alignment */
63 {EX_PRG,SIGTRAP}, /* Breakpoint Trap */
64 {EX_FP,SIGFPE}, /* FPU unavail */
65 {EX_DEC,SIGALRM}, /* Decrementer */
66 {EX_SYS_CALL,SIGSYS}, /* System Call */
67 {EX_TRACE,SIGTRAP}, /* Singel-Step/Watch */
68 {0xB,SIGILL}, /* Reserved */
69 {EX_IABR,SIGTRAP}, /* Instruction Address Breakpoint (GEKKO) */
70 {0xD,SIGFPE}, /* FP assist */
71 {0,0} /* MUST be the last */
72 };
73
74 static struct bp_entry {
75 u32 *address;
76 u32 instr;
77 struct bp_entry *next;
78 } bp_entries[GEKKO_MAX_BP];
79
80 static struct bp_entry *p_bpentries = NULL;
81 static frame_context current_thread_registers;
82
83 void __breakinst();
84 void c_debug_handler(frame_context *ctx);
85
86 extern void dbg_exceptionhandler();
87 extern void __exception_sethandler(u32 nExcept, void (*pHndl)(frame_context*));
88
89 extern void __clr_iabr();
90 extern void __enable_iabr();
91 extern void __disable_iabr();
92 extern void __set_iabr(void *);
93
94 extern const char *tcp_localip;
95 extern const char *tcp_netmask;
96 extern const char *tcp_gateway;
97 extern u8 __text_start[],__data_start[],__bss_start[];
98 extern u8 __text_fstart[],__data_fstart[],__bss_fstart[];
99
bp_init()100 static __inline__ void bp_init()
101 {
102 s32 i;
103
104 for(i=0;i<GEKKO_MAX_BP;i++) {
105 bp_entries[i].address = NULL;
106 bp_entries[i].instr = 0xffffffff;
107 bp_entries[i].next = NULL;
108 }
109 }
110
hex(char ch)111 static s32 hex(char ch)
112 {
113 if (ch >= 'a' && ch <= 'f')
114 return ch-'a'+10;
115 if (ch >= '0' && ch <= '9')
116 return ch-'0';
117 if (ch >= 'A' && ch <= 'F')
118 return ch-'A'+10;
119 return -1;
120 }
121
hexToInt(char ** ptr,s32 * ival)122 static s32 hexToInt(char **ptr, s32 *ival)
123 {
124 s32 cnt;
125 s32 val,nibble;
126
127 val = 0;
128 cnt = 0;
129 while(**ptr) {
130 nibble = hex(**ptr);
131 if(nibble<0) break;
132
133 val = (val<<4)|nibble;
134 cnt++;
135
136 (*ptr)++;
137 }
138 *ival = val;
139 return cnt;
140 }
141
computeSignal(s32 excpt)142 static s32 computeSignal(s32 excpt)
143 {
144 struct hard_trap_info *ht;
145 for(ht = hard_trap_info;ht->tt && ht->signo;ht++) {
146 if(ht->tt==excpt) return ht->signo;
147 }
148 return SIGHUP;
149 }
150
insert_bp(void * mem)151 static u32 insert_bp(void *mem)
152 {
153 u32 i;
154 struct bp_entry *p;
155
156 for(i=0;i<GEKKO_MAX_BP;i++) {
157 if(bp_entries[i].address == NULL) break;
158 }
159 if(i==GEKKO_MAX_BP) return 0;
160
161 p = &bp_entries[i];
162 p->next = p_bpentries;
163 p->address = mem;
164 p_bpentries = p;
165
166 p->instr = *(p->address);
167 *(p->address) = BPCODE;
168
169 DCStoreRangeNoSync((void*)((u32)mem&~0x1f),32);
170 ICInvalidateRange((void*)((u32)mem&~0x1f),32);
171 _sync();
172
173 return 1;
174 }
175
remove_bp(void * mem)176 static u32 remove_bp(void *mem)
177 {
178 struct bp_entry *e = p_bpentries;
179 struct bp_entry *f = NULL;
180
181 if(!e) return 0;
182 if(e->address==mem) {
183 p_bpentries = e->next;
184 f = e;
185 } else {
186 for(;e->next;e=e->next) {
187 if(e->next->address==mem) {
188 f = e->next;
189 e->next = f->next;
190 break;
191 }
192 }
193 }
194 if(!f) return 0;
195
196 *(f->address) = f->instr;
197 f->instr = 0xffffffff;
198 f->address = NULL;
199
200 DCStoreRangeNoSync((void*)((u32)mem&~0x1f),32);
201 ICInvalidateRange((void*)((u32)mem&~0x1f),32);
202 _sync();
203
204 return 1;
205 }
206
getdbgchar()207 static char getdbgchar()
208 {
209 char ch = 0;
210 s32 len = 0;
211
212 len = current_device->read(current_device,&ch,1);
213
214 return (len>0)?ch:0;
215 }
216
putdbgchar(char ch)217 static void putdbgchar(char ch)
218 {
219 current_device->write(current_device,&ch,1);
220 }
221
putdbgstr(const char * str)222 static void putdbgstr(const char *str)
223 {
224 current_device->write(current_device,str,strlen(str));
225 }
226
putpacket(const char * buffer)227 static void putpacket(const char *buffer)
228 {
229 u8 recv;
230 u8 chksum,ch;
231 char *ptr;
232 const char *inp;
233 static char outbuf[2048];
234
235 do {
236 inp = buffer;
237 ptr = outbuf;
238
239 *ptr++ = '$';
240
241 chksum = 0;
242 while((ch=*inp++)!='\0') {
243 *ptr++ = ch;
244 chksum += ch;
245 }
246
247 *ptr++ = '#';
248 *ptr++ = hexchars[chksum>>4];
249 *ptr++ = hexchars[chksum&0x0f];
250 *ptr = '\0';
251
252 putdbgstr(outbuf);
253
254 recv = getdbgchar();
255 } while((recv&0x7f)!='+');
256 }
257
getpacket(char * buffer)258 static void getpacket(char *buffer)
259 {
260 char ch;
261 u8 chksum,xmitsum;
262 s32 i,cnt;
263
264 do {
265 while((ch=(getdbgchar()&0x7f))!='$');
266
267 cnt = 0;
268 chksum = 0;
269 xmitsum = -1;
270
271 while(cnt<BUFMAX) {
272 ch = getdbgchar()&0x7f;
273 if(ch=='#') break;
274
275 chksum += ch;
276 buffer[cnt] = ch;
277 cnt++;
278 }
279 if(cnt>=BUFMAX) continue;
280
281 buffer[cnt] = 0;
282 if(ch=='#') {
283 xmitsum = hex(getdbgchar()&0x7f)<<4;
284 xmitsum |= hex(getdbgchar()&0x7f);
285
286 if(chksum!=xmitsum) putdbgchar('-');
287 else {
288 putdbgchar('+');
289 if(buffer[2]==':') {
290 putdbgchar(buffer[0]);
291 putdbgchar(buffer[1]);
292
293 cnt = strlen((const char*)buffer);
294 for(i=3;i<=cnt;i++) buffer[i-3] = buffer[i];
295 }
296 }
297 }
298 } while(chksum!=xmitsum);
299 }
300
process_query(const char * inp,char * outp,s32 thread)301 static void process_query(const char *inp,char *outp,s32 thread)
302 {
303 char *optr;
304
305 switch(inp[1]) {
306 case 'C':
307 optr = outp;
308 *optr++ = 'Q';
309 *optr++ = 'C';
310 optr = thread2vhstr(optr,thread);
311 *optr++ = 0;
312 break;
313 case 'P':
314 {
315 s32 ret,rthread,mask;
316 struct gdbstub_threadinfo info;
317
318 ret = parseqp(inp,&mask,&rthread);
319 if(!ret || mask&~0x1f) {
320 strcpy(outp,"E01");
321 break;
322 }
323
324 ret = gdbstub_getthreadinfo(rthread,&info);
325 if(!ret) {
326 strcpy(outp,"E02");
327 break;
328 }
329 packqq(outp,mask,rthread,&info);
330 }
331 break;
332 case 'L':
333 {
334 s32 ret,athread,first,max_cnt,i,done,rthread;
335
336 ret = parseql(inp,&first,&max_cnt,&athread);
337 if(!ret) {
338 strcpy(outp,"E02");
339 break;
340 }
341 if(max_cnt==0) {
342 strcpy(outp,"E02");
343 break;
344 }
345 if(max_cnt>QM_MAXTHREADS) max_cnt = QM_MAXTHREADS;
346
347 optr = reserve_qmheader(outp);
348 if(first) rthread = 0;
349 else rthread = athread;
350
351 done = 0;
352 for(i=0;i<max_cnt;i++) {
353 rthread = gdbstub_getnextthread(rthread);
354 if(rthread<=0) {
355 done = 1;
356 break;
357 }
358 optr = packqmthread(optr,rthread);
359 }
360 *optr = 0;
361 packqmheader(outp,i,done,athread);
362 }
363 break;
364 default:
365 break;
366 }
367 }
368
gdbstub_setthreadregs(s32 thread,frame_context * frame)369 static s32 gdbstub_setthreadregs(s32 thread,frame_context *frame)
370 {
371 return 1;
372 }
373
gdbstub_getthreadregs(s32 thread,frame_context * frame)374 static s32 gdbstub_getthreadregs(s32 thread,frame_context *frame)
375 {
376 lwp_cntrl *th;
377
378 th = gdbstub_indextoid(thread);
379 if(th) {
380 memcpy(frame->GPR,th->context.GPR,(32*4));
381 memcpy(frame->FPR,th->context.FPR,(32*8));
382 frame->SRR0 = th->context.LR;
383 frame->SRR1 = th->context.MSR;
384 frame->CR = th->context.CR;
385 frame->LR = th->context.LR;
386 frame->CTR = th->context.CTR;
387 frame->XER = th->context.XER;
388 frame->FPSCR = th->context.FPSCR;
389 return 1;
390 }
391 return 0;
392 }
393
gdbstub_report_exception(frame_context * frame,s32 thread)394 static void gdbstub_report_exception(frame_context *frame,s32 thread)
395 {
396 s32 sigval;
397 char *ptr;
398
399 ptr = remcomOutBuffer;
400 sigval = computeSignal(frame->EXCPT_Number);
401 *ptr++ = 'T';
402 *ptr++ = highhex(sigval);
403 *ptr++ = lowhex(sigval);
404 *ptr++ = highhex(SP_REGNUM);
405 *ptr++ = lowhex(SP_REGNUM);
406 *ptr++ = ':';
407 ptr = mem2hstr(ptr,(char*)&frame->GPR[1],4);
408 *ptr++ = ';';
409 *ptr++ = highhex(PC_REGNUM);
410 *ptr++ = lowhex(PC_REGNUM);
411 *ptr++ = ':';
412 ptr = mem2hstr(ptr,(char*)&frame->SRR0,4);
413 *ptr++ = ';';
414
415 *ptr++ = 't';
416 *ptr++ = 'h';
417 *ptr++ = 'r';
418 *ptr++ = 'e';
419 *ptr++ = 'a';
420 *ptr++ = 'd';
421 *ptr++ = ':';
422 ptr = thread2vhstr(ptr,thread);
423 *ptr++ = ';';
424
425 *ptr++ = '\0';
426
427 }
428
c_debug_handler(frame_context * frame)429 void c_debug_handler(frame_context *frame)
430 {
431 char *ptr;
432 s32 addr,len;
433 s32 thread,current_thread;
434 s32 host_has_detached;
435 frame_context *regptr;
436
437 thread = gdbstub_getcurrentthread();
438 current_thread = thread;
439
440 if(current_device->open(current_device)<0) return;
441
442 if(dbg_active) {
443 gdbstub_report_exception(frame,thread);
444 putpacket(remcomOutBuffer);
445 }
446
447 if(frame->SRR0==(u32)__breakinst) frame->SRR0 += 4;
448
449 host_has_detached = 0;
450 while(!host_has_detached) {
451 remcomOutBuffer[0]= 0;
452 getpacket(remcomInBuffer);
453 switch(remcomInBuffer[0]) {
454 case '?':
455 gdbstub_report_exception(frame,thread);
456 break;
457 case 'D':
458 dbg_instep = 0;
459 dbg_active = 0;
460 frame->SRR1 &= ~MSR_SE;
461 strcpy(remcomOutBuffer,"OK");
462 host_has_detached = 1;
463 break;
464 case 'k':
465 dbg_instep = 0;
466 dbg_active = 0;
467 frame->SRR1 &= ~MSR_SE;
468 frame->SRR0 = 0x80001800;
469 host_has_detached = 1;
470 goto exit;
471 case 'g':
472 regptr = frame;
473 ptr = remcomOutBuffer;
474 if(current_thread!=thread) regptr = ¤t_thread_registers;
475
476 ptr = mem2hstr(ptr,(char*)regptr->GPR,32*4);
477 ptr = mem2hstr(ptr,(char*)regptr->FPR,32*8);
478 ptr = mem2hstr(ptr,(char*)®ptr->SRR0,4);
479 ptr = mem2hstr(ptr,(char*)®ptr->SRR1,4);
480 ptr = mem2hstr(ptr,(char*)®ptr->CR,4);
481 ptr = mem2hstr(ptr,(char*)®ptr->LR,4);
482 ptr = mem2hstr(ptr,(char*)®ptr->CTR,4);
483 ptr = mem2hstr(ptr,(char*)®ptr->XER,4);
484 ptr = mem2hstr(ptr,(char*)®ptr->FPSCR,4);
485 break;
486 case 'm':
487 ptr = &remcomInBuffer[1];
488 if(hexToInt(&ptr,&addr) && ((addr&0xC0000000)==0xC0000000 || (addr&0xC0000000)==0x80000000)
489 && *ptr++==','
490 && hexToInt(&ptr,&len) && len<=((BUFMAX - 4)/2))
491 mem2hstr(remcomOutBuffer,(void*)addr,len);
492 else
493 strcpy(remcomOutBuffer,"E00");
494 break;
495 case 'q':
496 process_query(remcomInBuffer,remcomOutBuffer,thread);
497 break;
498 case 'c':
499 dbg_instep = 0;
500 dbg_active = 1;
501 frame->SRR1 &= ~MSR_SE;
502 current_device->wait(current_device);
503 goto exit;
504 case 's':
505 dbg_instep = 1;
506 dbg_active = 1;
507 frame->SRR1 |= MSR_SE;
508 current_device->wait(current_device);
509 goto exit;
510 case 'z':
511 {
512 s32 ret,type;
513 u32 len;
514 char *addr;
515
516 ret = parsezbreak(remcomInBuffer,&type,&addr,&len);
517 if(!ret) {
518 strcpy(remcomOutBuffer,"E01");
519 break;
520 }
521 if(type!=0) break;
522
523 if(len<4) {
524 strcpy(remcomOutBuffer,"E02");
525 break;
526 }
527
528 ret = remove_bp(addr);
529 if(!ret) {
530 strcpy(remcomOutBuffer,"E03");
531 break;
532 }
533 strcpy(remcomOutBuffer,"OK");
534 }
535 break;
536 case 'H':
537 if(remcomInBuffer[1]=='g')
538 {
539 s32 tmp,ret;
540
541 if(vhstr2thread(&remcomInBuffer[2],&tmp)==NULL) {
542 strcpy(remcomOutBuffer,"E01");
543 break;
544 }
545 if(!tmp) tmp = thread;
546 if(tmp==current_thread) {
547 strcpy(remcomOutBuffer,"OK");
548 break;
549 }
550
551 if(current_thread!=thread) ret = gdbstub_setthreadregs(current_thread,¤t_thread_registers);
552 if(tmp!=thread) {
553 ret = gdbstub_getthreadregs(tmp,¤t_thread_registers);
554 if(!ret) {
555 strcpy(remcomOutBuffer,"E02");
556 break;
557 }
558 }
559 current_thread= tmp;
560 }
561 strcpy(remcomOutBuffer,"OK");
562 break;
563 case 'T':
564 {
565 s32 tmp;
566
567 if(vhstr2thread(&remcomInBuffer[1],&tmp)==NULL) {
568 strcpy(remcomOutBuffer,"E01");
569 break;
570 }
571 if(gdbstub_indextoid(tmp)==NULL) strcpy(remcomOutBuffer,"E02");
572 else strcpy(remcomOutBuffer,"OK");
573 }
574 break;
575 case 'Z':
576 {
577 s32 ret,type;
578 u32 len;
579 char *addr;
580
581 ret = parsezbreak(remcomInBuffer,&type,&addr,&len);
582 if(!ret) {
583 strcpy(remcomOutBuffer,"E01");
584 break;
585 }
586 if(type!=0) {
587 strcpy(remcomOutBuffer,"E02");
588 break;
589 }
590 if(len<4) {
591 strcpy(remcomOutBuffer,"E03");
592 break;
593 }
594
595 ret = insert_bp(addr);
596 if(!ret) {
597 strcpy(remcomOutBuffer,"E04");
598 break;
599 }
600 strcpy(remcomOutBuffer,"OK");
601 }
602 break;
603 }
604 putpacket(remcomOutBuffer);
605 }
606 current_device->close(current_device);
607 exit:
608 return;
609 }
610
_break(void)611 void _break(void)
612 {
613 if(!dbg_initialized) return;
614 __asm__ __volatile__ (".globl __breakinst\n\
615 __breakinst: .long 0x7d821008");
616 }
617
DEBUG_Init(s32 device_type,s32 channel_port)618 void DEBUG_Init(s32 device_type,s32 channel_port)
619 {
620 u32 level;
621 struct uip_ip_addr localip,netmask,gateway;
622
623 UIP_LOG("DEBUG_Init()\n");
624
625 __lwp_thread_dispatchdisable();
626
627 bp_init();
628
629 if(device_type==GDBSTUB_DEVICE_USB) {
630 current_device = usb_init(channel_port);
631 } else {
632 localip.addr = uip_ipaddr((const u8_t*)tcp_localip);
633 netmask.addr = uip_ipaddr((const u8_t*)tcp_netmask);
634 gateway.addr = uip_ipaddr((const u8_t*)tcp_gateway);
635
636 current_device = tcpip_init(&localip,&netmask,&gateway,(u16)channel_port);
637 }
638
639 if(current_device!=NULL) {
640 _CPU_ISR_Disable(level);
641 __exception_sethandler(EX_DSI,dbg_exceptionhandler);
642 __exception_sethandler(EX_PRG,dbg_exceptionhandler);
643 __exception_sethandler(EX_TRACE,dbg_exceptionhandler);
644 __exception_sethandler(EX_IABR,dbg_exceptionhandler);
645 _CPU_ISR_Restore(level);
646
647 dbg_initialized = 1;
648
649 }
650 __lwp_thread_dispatchenable();
651 }
652