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 = &current_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*)&regptr->SRR0,4);
479 				ptr = mem2hstr(ptr,(char*)&regptr->SRR1,4);
480 				ptr = mem2hstr(ptr,(char*)&regptr->CR,4);
481 				ptr = mem2hstr(ptr,(char*)&regptr->LR,4);
482 				ptr = mem2hstr(ptr,(char*)&regptr->CTR,4);
483 				ptr = mem2hstr(ptr,(char*)&regptr->XER,4);
484 				ptr = mem2hstr(ptr,(char*)&regptr->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,&current_thread_registers);
552 					if(tmp!=thread) {
553 						ret = gdbstub_getthreadregs(tmp,&current_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