[PATCH][2.6] hardware breakpoint fix/support for xmon

Anton Blanchard anton at samba.org
Fri Feb 13 10:00:45 EST 2004


> Hmmm... We're all hacking on xmon these days, it seems.  Anton was
> making some changes to xmon just yesterday, and I am about to rework
> the xmon entry/exit and breakpoint insertion/removal to make it work
> properly on SMP systems.  Don't push for now, and I'll talk to Anton
> today about merging your changes in with ours.

For the benefit of others on the list, heres what Ive got:

- recover from bad SPR read/write (we get a program check)
- remove some old code (bat and segment register stuff)
- update the help text to match reality
- add a "press ? for help" when xmon first appears to make rusty happy
- protect against flushing bad parts of memory from Milton
- dont print iseries specific stuff on pseries in SPR dump (S)
- add code to dump the segment table or SLB
- remove a number of functions that wouldnt work on LPAR

Im trying to make sure xmon is solid so am interested in any way someone
can lock up xmon once this patch goes in.

Anton

===== arch/ppc64/kernel/traps.c 1.25 vs edited =====
--- 1.25/arch/ppc64/kernel/traps.c	Tue Jan 20 13:07:09 2004
+++ edited/arch/ppc64/kernel/traps.c	Thu Feb 12 15:54:09 2004
@@ -372,6 +372,13 @@
 {
 	siginfo_t info;

+#ifdef CONFIG_DEBUG_KERNEL
+	if (debugger_fault_handler) {
+		debugger_fault_handler(regs);
+		return;
+	}
+#endif
+
 	if (regs->msr & 0x100000) {
 		/* IEEE FP exception */

===== arch/ppc64/xmon/privinst.h 1.2 vs edited =====
--- 1.2/arch/ppc64/xmon/privinst.h	Mon Jun 10 12:37:26 2002
+++ edited/arch/ppc64/xmon/privinst.h	Thu Feb 12 16:18:53 2004
@@ -43,39 +43,12 @@
 GSETSPR(275, sprg3)
 GSETSPR(282, ear)
 GSETSPR(287, pvr)
-GSETSPR(528, bat0u)
-GSETSPR(529, bat0l)
-GSETSPR(530, bat1u)
-GSETSPR(531, bat1l)
-GSETSPR(532, bat2u)
-GSETSPR(533, bat2l)
-GSETSPR(534, bat3u)
-GSETSPR(535, bat3l)
 GSETSPR(1008, hid0)
 GSETSPR(1009, hid1)
 GSETSPR(1010, iabr)
 GSETSPR(1013, dabr)
 GSETSPR(1023, pir)

-static inline int get_sr(int n)
-{
-	int ret;
-
-#if 0
-	// DRENG does not assemble
-	asm (" mfsrin %0,%1" : "=r" (ret) : "r" (n << 28));
-#endif
-	return ret;
-}
-
-static inline void set_sr(int n, int val)
-{
-#if 0
-	// DRENG does not assemble
-	asm ("mtsrin %0,%1" : : "r" (val), "r" (n << 28));
-#endif
-}
-
 static inline void store_inst(void *p)
 {
 	asm volatile ("dcbst 0,%0; sync; icbi 0,%0; isync" : : "r" (p));
@@ -90,4 +63,3 @@
 {
 	asm volatile ("dcbi 0,%0; icbi 0,%0" : : "r" (p));
 }
-
===== arch/ppc64/xmon/xmon.c 1.33 vs edited =====
--- 1.33/arch/ppc64/xmon/xmon.c	Sat Feb  7 14:17:23 2004
+++ edited/arch/ppc64/xmon/xmon.c	Thu Feb 12 16:48:23 2004
@@ -115,10 +115,7 @@
 #endif /* CONFIG_SMP */
 static void csum(void);
 static void bootcmds(void);
-static void mem_translate(void);
-static void mem_check(void);
-static void mem_find_real(void);
-static void mem_find_vsid(void);
+void dump_segments(void);

 static void debug_trace(void);

@@ -149,7 +146,15 @@
   b	show breakpoints\n\
   bd	set data breakpoint\n\
   bi	set instruction breakpoint\n\
-  bc	clear breakpoint\n\
+  bc	clear breakpoint\n"
+#ifdef CONFIG_SMP
+  "\
+  c	print cpus stopped in xmon\n\
+  ci	send xmon interrupt to all other cpus\n\
+  c#	try to switch to cpu number h (in hex)\n"
+#endif
+  "\
+  C	checksum\n\
   d	dump bytes\n\
   di	dump instructions\n\
   df	dump float values\n\
@@ -162,7 +167,6 @@
   md	compare two blocks of memory\n\
   ml	locate a block of memory\n\
   mz	zero a block of memory\n\
-  mx	translation information for an effective address\n\
   mi	show information about memory allocation\n\
   p 	show the task list\n\
   r	print registers\n\
@@ -171,7 +175,14 @@
   t	print backtrace\n\
   T	Enable/Disable PPCDBG flags\n\
   x	exit monitor\n\
-";
+  u	dump segment table or SLB\n\
+  ?	help\n"
+#ifndef CONFIG_PPC_ISERIES
+  "\
+  zr	reboot\n\
+  zh	halt\n"
+#endif
+;

 static int xmon_trace[NR_CPUS];
 #define SSTEP	1		/* stepping because of 's' command */
@@ -308,6 +319,7 @@
 #endif /* CONFIG_SMP */
 	remove_bpts();
 	disable_surveillance();
+	printf("press ? for help ");
 	cmd = cmds(excp);
 	if (cmd == 's') {
 		xmon_trace[smp_processor_id()] = SSTEP;
@@ -332,17 +344,6 @@
 	set_msrd(msr);		/* restore interrupt enable */
 }

-void
-xmon_irq(int irq, void *d, struct pt_regs *regs)
-{
-	unsigned long flags;
-	local_save_flags(flags);
-	local_irq_disable();
-	printf("Keyboard interrupt\n");
-	xmon(regs);
-	local_irq_restore(flags);
-}
-
 int
 xmon_bpt(struct pt_regs *regs)
 {
@@ -524,18 +525,6 @@
 			case 'z':
 				memzcan();
 				break;
-			case 'x':
-				mem_translate();
-				break;
-			case 'c':
-				mem_check();
-				break;
-			case 'f':
-				mem_find_real();
-				break;
-			case 'e':
-				mem_find_vsid();
-				break;
 			case 'i':
 				show_mem();
 				break;
@@ -587,11 +576,16 @@
 			cpu_cmd();
 			break;
 #endif /* CONFIG_SMP */
+#ifndef CONFIG_PPC_ISERIES
 		case 'z':
 			bootcmds();
+#endif
 		case 'T':
 			debug_trace();
 			break;
+		case 'u':
+			dump_segments();
+			break;
 		default:
 			printf("Unrecognized command: ");
 		        do {
@@ -1056,14 +1050,23 @@
 		termch = 0;
 	nflush = 1;
 	scanhex(&nflush);
-	nflush = (nflush + 31) / 32;
-	if (cmd != 'i') {
-		for (; nflush > 0; --nflush, adrs += 0x20)
-			cflush((void *) adrs);
-	} else {
-		for (; nflush > 0; --nflush, adrs += 0x20)
-			cinval((void *) adrs);
+	nflush = (nflush + L1_CACHE_BYTES - 1) / L1_CACHE_BYTES;
+	if( setjmp(bus_error_jmp) == 0 ) {
+		debugger_fault_handler = handle_fault;
+		sync();
+
+		if (cmd != 'i') {
+			for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
+				cflush((void *) adrs);
+		} else {
+			for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
+				cinval((void *) adrs);
+		}
+		sync();
+		/* wait a little while to see if we get a machine check */
+		__delay(200);
 	}
+	debugger_fault_handler = 0;
 }

 unsigned long
@@ -1072,6 +1075,7 @@
 	unsigned int instrs[2];
 	unsigned long (*code)(void);
 	unsigned long opd[3];
+	unsigned long ret = -1UL;

 	instrs[0] = 0x7c6002a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
 	instrs[1] = 0x4e800020;
@@ -1082,7 +1086,22 @@
 	store_inst(instrs+1);
 	code = (unsigned long (*)(void)) opd;

-	return code();
+	if (setjmp(bus_error_jmp) == 0) {
+		debugger_fault_handler = handle_fault;
+		sync();
+
+		ret = code();
+
+		sync();
+		/* wait a little while to see if we get a machine check */
+		__delay(200);
+	} else {
+		printf("*** Error reading spr %x\n", n);
+	}
+
+	debugger_fault_handler = 0;
+
+	return ret;
 }

 void
@@ -1101,7 +1120,20 @@
 	store_inst(instrs+1);
 	code = (unsigned long (*)(unsigned long)) opd;

-	code(val);
+	if (setjmp(bus_error_jmp) == 0) {
+		debugger_fault_handler = handle_fault;
+		sync();
+
+		code(val);
+
+		sync();
+		/* wait a little while to see if we get a machine check */
+		__delay(200);
+	} else {
+		printf("*** Error writing spr %x\n", n);
+	}
+
+	debugger_fault_handler = 0;
 }

 static unsigned long regno;
@@ -1111,11 +1143,14 @@
 void
 super_regs()
 {
-	int i, cmd;
+	int cmd;
 	unsigned long val;
-	struct paca_struct*  ptrPaca = NULL;
-	struct ItLpPaca*  ptrLpPaca = NULL;
-	struct ItLpRegSave*  ptrLpRegSave = NULL;
+#ifdef CONFIG_PPC_ISERIES
+	int i;
+	struct paca_struct *ptrPaca = NULL;
+	struct ItLpPaca *ptrLpPaca = NULL;
+	struct ItLpRegSave *ptrLpRegSave = NULL;
+#endif

 	cmd = skipbl();
 	if (cmd == '\n') {
@@ -1129,10 +1164,7 @@
 		printf("sp   = %.16lx  sprg3= %.16lx\n", sp, get_sprg3());
 		printf("toc  = %.16lx  dar  = %.16lx\n", toc, get_dar());
 		printf("srr0 = %.16lx  srr1 = %.16lx\n", get_srr0(), get_srr1());
-		printf("asr  = %.16lx\n", mfasr());
-		for (i = 0; i < 8; ++i)
-			printf("sr%.2ld = %.16lx  sr%.2ld = %.16lx\n", i, get_sr(i), i+8, get_sr(i+8));
-
+#ifdef CONFIG_PPC_ISERIES
 		// Dump out relevant Paca data areas.
 		printf("Paca: \n");
 		ptrPaca = get_paca();
@@ -1148,7 +1180,8 @@
 		printf("    Saved Sprg0=%.16lx  Saved Sprg1=%.16lx \n", ptrLpRegSave->xSPRG0, ptrLpRegSave->xSPRG0);
 		printf("    Saved Sprg2=%.16lx  Saved Sprg3=%.16lx \n", ptrLpRegSave->xSPRG2, ptrLpRegSave->xSPRG3);
 		printf("    Saved Msr  =%.16lx  Saved Nia  =%.16lx \n", ptrLpRegSave->xMSR, ptrLpRegSave->xNIA);
-
+#endif
+
 		return;
 	}

@@ -1162,11 +1195,6 @@
 	case 'r':
 		printf("spr %lx = %lx\n", regno, read_spr(regno));
 		break;
-	case 's':
-		val = get_sr(regno);
-		scanhex(&val);
-		set_sr(regno, val);
-		break;
 	case 'm':
 		val = get_msr();
 		scanhex(&val);
@@ -1923,240 +1951,8 @@
 	}
 }

-void
-mem_translate()
-{
-	int c;
-	unsigned long ea, va, vsid, vpn, page, hpteg_slot_primary, hpteg_slot_secondary, primary_hash, i, *steg, esid, stabl;
-	HPTE *  hpte;
-	struct mm_struct * mm;
-	pte_t  *ptep = NULL;
-	void * pgdir;
-
-	c = inchar();
-	if ((isxdigit(c) && c != 'f' && c != 'd') || c == '\n')
-		termch = c;
-	scanhex((void *)&ea);
-
-	if ((ea >= KRANGE_START) && (ea <= (KRANGE_START + (1UL<<60)))) {
-		ptep = 0;
-		vsid = get_kernel_vsid(ea);
-		va = ( vsid << 28 ) | ( ea & 0x0fffffff );
-	} else {
-		// if in vmalloc range, use the vmalloc page directory
-		if ( ( ea >= VMALLOC_START ) && ( ea <= VMALLOC_END ) ) {
-			mm = &init_mm;
-			vsid = get_kernel_vsid( ea );
-		}
-		// if in ioremap range, use the ioremap page directory
-		else if ( ( ea >= IMALLOC_START ) && ( ea <= IMALLOC_END ) ) {
-			mm = &ioremap_mm;
-			vsid = get_kernel_vsid( ea );
-		}
-		// if in user range, use the current task's page directory
-		else if ( ( ea >= USER_START ) && ( ea <= USER_END ) ) {
-			mm = current->mm;
-			vsid = get_vsid(mm->context, ea );
-		}
-		pgdir = mm->pgd;
-		va = ( vsid << 28 ) | ( ea & 0x0fffffff );
-		ptep = find_linux_pte( pgdir, ea );
-	}
-
-	vpn = ((vsid << 28) | (((ea) & 0xFFFF000))) >> 12;
-	page = vpn & 0xffff;
-	esid = (ea >> 28)  & 0xFFFFFFFFF;
-
-  // Search the primary group for an available slot
-	primary_hash = ( vsid & 0x7fffffffff ) ^ page;
-	hpteg_slot_primary = ( primary_hash & htab_data.htab_hash_mask ) * HPTES_PER_GROUP;
-	hpteg_slot_secondary = ( ~primary_hash & htab_data.htab_hash_mask ) * HPTES_PER_GROUP;
-
-	printf("ea             : %.16lx\n", ea);
-	printf("esid           : %.16lx\n", esid);
-	printf("vsid           : %.16lx\n", vsid);
-
-	printf("\nSoftware Page Table\n-------------------\n");
-	printf("ptep           : %.16lx\n", ((unsigned long *)ptep));
-	if(ptep) {
-		printf("*ptep          : %.16lx\n", *((unsigned long *)ptep));
-	}
-
-	hpte  = htab_data.htab  + hpteg_slot_primary;
-	printf("\nHardware Page Table\n-------------------\n");
-	printf("htab base      : %.16lx\n", htab_data.htab);
-	printf("slot primary   : %.16lx\n", hpteg_slot_primary);
-	printf("slot secondary : %.16lx\n", hpteg_slot_secondary);
-	printf("\nPrimary Group\n");
-	for (i=0; i<8; ++i) {
-		if ( hpte->dw0.dw0.v != 0 ) {
-			printf("%d: (hpte)%.16lx %.16lx\n", i, hpte->dw0.dword0, hpte->dw1.dword1);
-			printf("          vsid: %.13lx   api: %.2lx  hash: %.1lx\n",
-			       (hpte->dw0.dw0.avpn)>>5,
-			       (hpte->dw0.dw0.avpn) & 0x1f,
-			       (hpte->dw0.dw0.h));
-			printf("          rpn: %.13lx \n", (hpte->dw1.dw1.rpn));
-			printf("           pp: %.1lx \n",
-			       ((hpte->dw1.dw1.pp0)<<2)|(hpte->dw1.dw1.pp));
-			printf("        wimgn: %.2lx  reference: %.1lx  change: %.1lx\n",
-			       ((hpte->dw1.dw1.w)<<4)|
-			       ((hpte->dw1.dw1.i)<<3)|
-			       ((hpte->dw1.dw1.m)<<2)|
-			       ((hpte->dw1.dw1.g)<<1)|
-			       ((hpte->dw1.dw1.n)<<0),
-			       hpte->dw1.dw1.r, hpte->dw1.dw1.c);
-		}
-		hpte++;
-	}
-
-	printf("\nSecondary Group\n");
-	// Search the secondary group
-	hpte  = htab_data.htab  + hpteg_slot_secondary;
-	for (i=0; i<8; ++i) {
-		if(hpte->dw0.dw0.v) {
-			printf("%d: (hpte)%.16lx %.16lx\n", i, hpte->dw0.dword0, hpte->dw1.dword1);
-			printf("          vsid: %.13lx   api: %.2lx  hash: %.1lx\n",
-			       (hpte->dw0.dw0.avpn)>>5,
-			       (hpte->dw0.dw0.avpn) & 0x1f,
-			       (hpte->dw0.dw0.h));
-			printf("          rpn: %.13lx \n", (hpte->dw1.dw1.rpn));
-			printf("           pp: %.1lx \n",
-			       ((hpte->dw1.dw1.pp0)<<2)|(hpte->dw1.dw1.pp));
-			printf("        wimgn: %.2lx  reference: %.1lx  change: %.1lx\n",
-			       ((hpte->dw1.dw1.w)<<4)|
-			       ((hpte->dw1.dw1.i)<<3)|
-			       ((hpte->dw1.dw1.m)<<2)|
-			       ((hpte->dw1.dw1.g)<<1)|
-			       ((hpte->dw1.dw1.n)<<0),
-			       hpte->dw1.dw1.r, hpte->dw1.dw1.c);
-		}
-		hpte++;
-	}
-
-	printf("\nHardware Segment Table\n-----------------------\n");
-	stabl = (unsigned long)(KERNELBASE+(_ASR&0xFFFFFFFFFFFFFFFE));
-	steg = (unsigned long *)((stabl) | ((esid & 0x1f) << 7));
-
-	printf("stab base      : %.16lx\n", stabl);
-	printf("slot           : %.16lx\n", steg);
-
-	for (i=0; i<8; ++i) {
-		printf("%d: (ste) %.16lx %.16lx\n", i,
-		       *((unsigned long *)(steg+i*2)),*((unsigned long *)(steg+i*2+1)) );
-	}
-}
-
-void mem_check()
-{
-	unsigned long htab_size_bytes;
-	unsigned long htab_end;
-	unsigned long last_rpn;
-	HPTE *hpte1, *hpte2;
-
-	htab_size_bytes = htab_data.htab_num_ptegs * 128; // 128B / PTEG
-	htab_end = (unsigned long)htab_data.htab + htab_size_bytes;
-	// last_rpn = (naca->physicalMemorySize-1) >> PAGE_SHIFT;
-	last_rpn = 0xfffff;
-
-	printf("\nHardware Page Table Check\n-------------------\n");
-	printf("htab base      : %.16lx\n", htab_data.htab);
-	printf("htab size      : %.16lx\n", htab_size_bytes);
-
-#if 1
-	for(hpte1 = htab_data.htab; hpte1 < (HPTE *)htab_end; hpte1++) {
-		if ( hpte1->dw0.dw0.v != 0 ) {
-			if ( hpte1->dw1.dw1.rpn <= last_rpn ) {
-				for(hpte2 = hpte1+1; hpte2 < (HPTE *)htab_end; hpte2++) {
-					if ( hpte2->dw0.dw0.v != 0 ) {
-						if(hpte1->dw1.dw1.rpn == hpte2->dw1.dw1.rpn) {
-							printf(" Duplicate rpn: %.13lx \n", (hpte1->dw1.dw1.rpn));
-							printf("   hpte1: %16.16lx  *hpte1: %16.16lx %16.16lx\n",
-							       hpte1, hpte1->dw0.dword0, hpte1->dw1.dword1);
-							printf("   hpte2: %16.16lx  *hpte2: %16.16lx %16.16lx\n",
-							       hpte2, hpte2->dw0.dword0, hpte2->dw1.dword1);
-						}
-					}
-				}
-			} else {
-				printf(" Bogus rpn: %.13lx \n", (hpte1->dw1.dw1.rpn));
-				printf("   hpte: %16.16lx  *hpte: %16.16lx %16.16lx\n",
-				       hpte1, hpte1->dw0.dword0, hpte1->dw1.dword1);
-			}
-		}
-	}
-#endif
-	printf("\nDone -------------------\n");
-}
-
-void mem_find_real()
+static void debug_trace(void)
 {
-	unsigned long htab_size_bytes;
-	unsigned long htab_end;
-	unsigned long last_rpn;
-	HPTE *hpte1;
-	unsigned long pa, rpn;
-	int c;
-
-	c = inchar();
-	if ((isxdigit(c) && c != 'f' && c != 'd') || c == '\n')
-		termch = c;
-	scanhex((void *)&pa);
-	rpn = pa >> 12;
-
-	htab_size_bytes = htab_data.htab_num_ptegs * 128; // 128B / PTEG
-	htab_end = (unsigned long)htab_data.htab + htab_size_bytes;
-	// last_rpn = (naca->physicalMemorySize-1) >> PAGE_SHIFT;
-	last_rpn = 0xfffff;
-
-	printf("\nMem Find RPN\n-------------------\n");
-	printf("htab base      : %.16lx\n", htab_data.htab);
-	printf("htab size      : %.16lx\n", htab_size_bytes);
-
-	for(hpte1 = htab_data.htab; hpte1 < (HPTE *)htab_end; hpte1++) {
-		if ( hpte1->dw0.dw0.v != 0 ) {
-			if ( hpte1->dw1.dw1.rpn == rpn ) {
-				printf(" Found rpn: %.13lx \n", (hpte1->dw1.dw1.rpn));
-				printf("      hpte: %16.16lx  *hpte1: %16.16lx %16.16lx\n",
-				       hpte1, hpte1->dw0.dword0, hpte1->dw1.dword1);
-			}
-		}
-	}
-	printf("\nDone -------------------\n");
-}
-
-void mem_find_vsid()
-{
-	unsigned long htab_size_bytes;
-	unsigned long htab_end;
-	HPTE *hpte1;
-	unsigned long vsid;
-	int c;
-
-	c = inchar();
-	if ((isxdigit(c) && c != 'f' && c != 'd') || c == '\n')
-		termch = c;
-	scanhex((void *)&vsid);
-
-	htab_size_bytes = htab_data.htab_num_ptegs * 128; // 128B / PTEG
-	htab_end = (unsigned long)htab_data.htab + htab_size_bytes;
-
-	printf("\nMem Find VSID\n-------------------\n");
-	printf("htab base      : %.16lx\n", htab_data.htab);
-	printf("htab size      : %.16lx\n", htab_size_bytes);
-
-	for(hpte1 = htab_data.htab; hpte1 < (HPTE *)htab_end; hpte1++) {
-		if ( hpte1->dw0.dw0.v != 0 ) {
-			if ( ((hpte1->dw0.dw0.avpn)>>5) == vsid ) {
-				printf(" Found vsid: %.16lx \n", ((hpte1->dw0.dw0.avpn) >> 5));
-				printf("       hpte: %16.16lx  *hpte1: %16.16lx %16.16lx\n",
-				       hpte1, hpte1->dw0.dword0, hpte1->dw1.dword1);
-			}
-		}
-	}
-	printf("\nDone -------------------\n");
-}
-
-static void debug_trace(void) {
         unsigned long val, cmd, on;

 	cmd = skipbl();
@@ -2202,4 +1998,48 @@
 		}
 		cmd = skipbl();
 	}
+}
+
+static void dump_slb(void)
+{
+	int i;
+	unsigned long tmp;
+
+	printf("SLB contents of cpu %d\n", smp_processor_id());
+
+	for (i = 0; i < naca->slb_size; i++) {
+		asm volatile("slbmfee  %0,%1" : "=r" (tmp) : "r" (i));
+		printf("%02d %016lx ", i, tmp);
+
+		asm volatile("slbmfev  %0,%1" : "=r" (tmp) : "r" (i));
+		printf("%016lx\n", tmp);
+	}
+}
+
+static void dump_stab(void)
+{
+	int i;
+	unsigned long *tmp = (unsigned long *)get_paca()->xStab_data.virt;
+
+	printf("Segment table contents of cpu %d\n", smp_processor_id());
+
+	for (i = 0; i < PAGE_SIZE/16; i++) {
+		unsigned long a, b;
+
+		a = *tmp++;
+		b = *tmp++;
+
+		if (a || b) {
+			printf("%03d %016lx ", i, a);
+			printf("%016lx\n", b);
+		}
+	}
+}
+
+void dump_segments(void)
+{
+	if (cur_cpu_spec->cpu_features & CPU_FTR_SLB)
+		dump_slb();
+	else
+		dump_stab();
 }

** Sent via the linuxppc64-dev mail list. See http://lists.linuxppc.org/





More information about the Linuxppc64-dev mailing list