Module Name:    src
Committed By:   matt
Date:           Mon Mar  1 19:26:01 UTC 2010

Modified Files:
        src/sys/arch/mips/include [matt-nb5-mips64]: locore.h
        src/sys/arch/mips/mips [matt-nb5-mips64]: mips_fixup.c spl_stubs.c

Log Message:
Rework fixups support a bit (add a convience macro, require fixups to be
sorted).


To generate a diff of this commit:
cvs rdiff -u -r1.78.36.1.2.18 -r1.78.36.1.2.19 \
    src/sys/arch/mips/include/locore.h
cvs rdiff -u -r1.1.2.4 -r1.1.2.5 src/sys/arch/mips/mips/mips_fixup.c
cvs rdiff -u -r1.1.2.1 -r1.1.2.2 src/sys/arch/mips/mips/spl_stubs.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/mips/include/locore.h
diff -u src/sys/arch/mips/include/locore.h:1.78.36.1.2.18 src/sys/arch/mips/include/locore.h:1.78.36.1.2.19
--- src/sys/arch/mips/include/locore.h:1.78.36.1.2.18	Sun Feb 28 23:45:07 2010
+++ src/sys/arch/mips/include/locore.h	Mon Mar  1 19:26:00 2010
@@ -1,4 +1,4 @@
-/* $NetBSD: locore.h,v 1.78.36.1.2.18 2010/02/28 23:45:07 matt Exp $ */
+/* $NetBSD: locore.h,v 1.78.36.1.2.19 2010/03/01 19:26:00 matt Exp $ */
 
 /*
  * This file should not be included by MI code!!!
@@ -45,13 +45,26 @@
 void	softint_process(uint32_t);
 void	softint_fast_dispatch(struct lwp *, int);
 
+/*
+ * Convert an address to an offset used in a MIPS jump instruction.  The offset
+ * contains the low 28 bits (allowing a jump to anywhere within the same 256MB
+ * segment of address space) of the address but since mips instructions are
+ * always on a 4 byte boundary the low 2 bits are always zero so the 28 bits
+ * get shifted right by 2 bits leaving us with a 26 bit result.  To make the
+ * offset, we shift left to clear the upper four bits and then right by 6.
+ */
+#define	fixup_addr2offset(x)	((((uint32_t)(uintptr_t)(x)) << 4) >> 6)
 typedef bool (*mips_fixup_callback_t)(int32_t, uint32_t [2]);
+struct mips_jump_fixup_info {
+	uint32_t jfi_stub;
+	uint32_t jfi_real;
+};
  
 void	fixup_splcalls(void);				/* splstubs.c */
 bool	mips_fixup_exceptions(mips_fixup_callback_t);
 bool	mips_fixup_zero_relative(int32_t, uint32_t [2]);
-void	mips_fixup_stubs(uint32_t *, uint32_t *, const uint32_t *,
-	    const uint32_t *, size_t);
+void	mips_fixup_stubs(uint32_t *, uint32_t *,
+	    const struct mips_jump_fixup_info *, size_t);
 void	fixup_mips_cpu_switch_resume(void);
 
 void	mips_cpu_switch_resume(struct lwp *);

Index: src/sys/arch/mips/mips/mips_fixup.c
diff -u src/sys/arch/mips/mips/mips_fixup.c:1.1.2.4 src/sys/arch/mips/mips/mips_fixup.c:1.1.2.5
--- src/sys/arch/mips/mips/mips_fixup.c:1.1.2.4	Sun Feb 28 15:32:32 2010
+++ src/sys/arch/mips/mips/mips_fixup.c	Mon Mar  1 19:26:01 2010
@@ -29,7 +29,7 @@
 
 #include <sys/cdefs.h>
 
-__KERNEL_RCSID(0, "$NetBSD: mips_fixup.c,v 1.1.2.4 2010/02/28 15:32:32 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: mips_fixup.c,v 1.1.2.5 2010/03/01 19:26:01 matt Exp $");
 
 #include <sys/param.h>
 
@@ -175,44 +175,53 @@
 #define OPCODE_J		002
 #define OPCODE_JAL		003
 
-static void
-fixup_mips_jump(uint32_t *insnp, uint32_t stub, uint32_t real)
+static inline void
+fixup_mips_jump(uint32_t *insnp, const struct mips_jump_fixup_info *jfi)
 {
 	uint32_t insn = *insnp;
 
 	KASSERT((insn >> (26+1)) == (OPCODE_J >> 1));
-	KASSERT((insn << 6) == (stub << 4));
+	KASSERT((insn << 6) == (jfi->jfi_stub << 6));
 
-	insn ^= (stub ^ real) << 4 >> 6;
+	insn ^= (jfi->jfi_stub ^ jfi->jfi_real);
 
-	KASSERT((insn << 6) == (real << 4));
+	KASSERT((insn << 6) == (jfi->jfi_real << 6));
 
+#ifdef DEBUG
+#if 0
+	int32_t va = ((intptr_t) insnp >> 26) << 26;
+	printf("%s: %08x: [%08x] %s %08x -> [%08x] %s %08x\n",
+	    __func__, (int32_t)(intptr_t)insnp,
+	    insn, opcode == OPCODE_J ? "j" : "jal",
+	    va | (jfi->jfo_stub << 2),
+	    *insnp, opcode == OPCODE_J ? "j" : "jal",
+	    va | (jfi->jfi_real << 2));
+#endif
+#endif
 	*insnp = insn;
 }
 
 void
 mips_fixup_stubs(uint32_t *start, uint32_t *end,
-	const uint32_t *stub_offsets, const uint32_t *real_offsets,
-	size_t noffsets)
+	const struct mips_jump_fixup_info *fixups,
+	size_t nfixups)
 {
-	uint32_t min_offset = 0x03ffffff;
-	uint32_t max_offset = 0x00000000;
+	const uint32_t min_offset = fixups[0].jfi_stub;
+	const uint32_t max_offset = fixups[nfixups-1].jfi_stub;
 #ifdef DEBUG
-	size_t fixups = 0;
+	size_t fixups_done = 0;
 	uint32_t cycles = (CPUISMIPS3 ? mips3_cp0_count_read() : 0);
 #endif
 
+#ifdef DIAGNOGSTIC
 	/*
-	 * Find the lowest and highest jumps we will be replacing.  We don't
-	 * need to do it but it does make weeding out the non-matching jumps
-	 * faster.
+	 * Verify the fixup list is sorted from low stub to high stub.
 	 */
-	for (size_t i = 0; i < noffsets; i++) {
-		if (stub_offsets[i] < min_offset)
-			min_offset = stub_offsets[i];
-		if (max_offset < stub_offsets[i])
-			max_offset = stub_offsets[i];
+	for (const struct mips_jump_fixup_info *jfi = fixups + 1;
+	     jfi < fixups + nfixups; jfi++) {
+		KASSERT(jfi[-1].jfi_stub < jfi[0].jfi_stub);
 	}
+#endif
 
 	for (uint32_t *insnp = start; insnp < end; insnp++) {
 		uint32_t insn = *insnp;
@@ -231,29 +240,28 @@
 		 * We know it's a jump, but does it match one we want to
 		 * fixup?
 		 */
-		for (size_t i = 0; i < noffsets; i++) {
-			if (stub_offsets[i] != offset)
-				continue;
+		for (const struct mips_jump_fixup_info *jfi = fixups;
+		     jfi < fixups + nfixups; jfi++) {
 			/*
-			 * Yes, we need to fix it up.  Replace the old
-			 * displacement with the real displacement.  If we've
-			 * moved to a new cache line, sync the last cache line
-			 * we fixed.
+			 * The caller has sorted the fixup list from lowest
+			 * stub to highest stub so if the current offset is
+			 * less than the this fixup's stub offset, we know
+			 * can't match anything else in the fixup list.
 			 */
-			*insnp ^= offset ^ real_offsets[i];
+			if (jfi->jfi_stub > offset)
+				break;
+
+			if (jfi->jfi_stub == offset) {
+				/*
+				 * Yes, we need to fix it up.  Replace the old
+				 * displacement with the real displacement.
+				 */
+				fixup_mips_jump(insnp, jfi);
 #ifdef DEBUG
-#if 0
-			int32_t va = ((intptr_t) insnp >> 26) << 26;
-			printf("%s: %08x: [%08x] %s %08x -> [%08x] %s %08x\n",
-			    __func__, (int32_t)(intptr_t)insnp,
-			    insn, opcode == OPCODE_J ? "j" : "jal",
-			    va | (offset << 2),
-			    *insnp, opcode == OPCODE_J ? "j" : "jal",
-			    va | (real_offsets[i] << 2));
-#endif
-			fixups++;
+				fixups_done++;
 #endif
-			break;
+				break;
+			}
 		}
 	}
 
@@ -267,7 +275,7 @@
 	if (CPUISMIPS3)
 		cycles = mips3_cp0_count_read() - cycles;
 	printf("%s: %zu fixup%s done in %u cycles\n", __func__,
-	    fixups, fixups == 1 ? "" : "s",
+	    fixups_done, fixups_done == 1 ? "" : "s",
 	    cycles);
 #endif
 }
@@ -285,7 +293,10 @@
 {
 	extern uint32_t __cpu_switchto_fixup[];
 
-	fixup_mips_jump(__cpu_switchto_fixup,
-	    (uintptr_t)mips_cpu_switch_resume,
-	    (uintptr_t)mips_locoresw.lsw_cpu_switch_resume);
+	struct mips_jump_fixup_info fixup = {
+		fixup_addr2offset(mips_cpu_switch_resume),
+		fixup_addr2offset(mips_locoresw.lsw_cpu_switch_resume)
+	};
+
+	fixup_mips_jump(__cpu_switchto_fixup, &fixup);
 }

Index: src/sys/arch/mips/mips/spl_stubs.c
diff -u src/sys/arch/mips/mips/spl_stubs.c:1.1.2.1 src/sys/arch/mips/mips/spl_stubs.c:1.1.2.2
--- src/sys/arch/mips/mips/spl_stubs.c:1.1.2.1	Sun Feb 28 03:23:06 2010
+++ src/sys/arch/mips/mips/spl_stubs.c	Mon Mar  1 19:26:01 2010
@@ -1,4 +1,4 @@
-/* $NetBSD: spl_stubs.c,v 1.1.2.1 2010/02/28 03:23:06 matt Exp $ */
+/* $NetBSD: spl_stubs.c,v 1.1.2.2 2010/03/01 19:26:01 matt Exp $ */
 /*-
  * Copyright (c) 2010 The NetBSD Foundation, Inc.
  * All rights reserved.
@@ -30,7 +30,7 @@
 
 #include <sys/cdefs.h>
 
-__KERNEL_RCSID(0, "$NetBSD: spl_stubs.c,v 1.1.2.1 2010/02/28 03:23:06 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: spl_stubs.c,v 1.1.2.2 2010/03/01 19:26:01 matt Exp $");
 
 #define __INTR_PRIVATE
 
@@ -55,134 +55,103 @@
 int	splintr(uint32_t *)	__section(".stub");
 void	_setsoftintr(uint32_t)	__section(".stub");
 void	_clrsoftintr(uint32_t)	__section(".stub");
+void	splcheck(void)		__section(".stub");
 
-#define	J_SPLHIGH	0
 int
 splhigh(void)
 {
 	return (*mips_splsw.splsw_splhigh)();
 }
 
-#define	J_SPLHIGH_NOPROF	(J_SPLHIGH+1)
 int
 splhigh_noprof(void)
 {
 	return (*mips_splsw.splsw_splhigh_noprof)();
 }
 
-#define	J_SPLSCHED		(J_SPLHIGH_NOPROF+1)
 int
 splsched(void)
 {
 	return (*mips_splsw.splsw_splsched)();
 }
 
-#define	J_SPLVM			(J_SPLSCHED+1)
 int
 splvm(void)
 {
 	return (*mips_splsw.splsw_splvm)();
 }
 
-#define	J_SPLSOFTSERIAL		(J_SPLVM+1)
 int
 splsoftserial(void)
 {
 	return (*mips_splsw.splsw_splsoftserial)();
 }
 
-#define	J_SPLSOFTNET		(J_SPLSOFTSERIAL+1)
 int
 splsoftnet(void)
 {
 	return (*mips_splsw.splsw_splsoftnet)();
 }
 
-#define	J_SPLSOFTBIO		(J_SPLSOFTNET+1)
 int
 splsoftbio(void)
 {
 	return (*mips_splsw.splsw_splsoftbio)();
 }
 
-#define	J_SPLSOFTCLOCK		(J_SPLSOFTBIO+1)
 int
 splsoftclock(void)
 {
 	return (*mips_splsw.splsw_splsoftclock)();
 }
 
-#define	J_SPL0			(J_SPLSOFTCLOCK+1)
 void
 spl0(void)
 {
 	(*mips_splsw.splsw_spl0)();
 }
 
-#define	J_SPLX			(J_SPL0+1)
 void
 splx(int s)
 {
 	(*mips_splsw.splsw_splx)(s);
 }
 
-#define	J_SPLX_NOPROF		(J_SPLX+1)
 void
 splx_noprof(int s)
 {
 	(*mips_splsw.splsw_splx_noprof)(s);
 }
 
-#define	J_SPLRAISE		(J_SPLX_NOPROF+1)
 int
 splraise(int s)
 {
         return (*mips_splsw.splsw_splraise)(s);
 }
 
-#define	J_SPLINTR		(J_SPLRAISE+1)
 int
 splintr(uint32_t *p)
 {
 	return (*mips_splsw.splsw_splintr)(p);
 }
 
-#define	J_SETSOFTINTR		(J_SPLINTR+1)
 void
 _setsoftintr(uint32_t m)
 {
 	(*mips_splsw.splsw__setsoftintr)(m);
 }
 
-#define	J_CLRSOFTINTR		(J_SETSOFTINTR+1)
 void
 _clrsoftintr(uint32_t m)
 {
 	(*mips_splsw.splsw__clrsoftintr)(m);
 }
 
-#define	J_SPLMAX		(J_CLRSOFTINTR+1)
-
-#if 0
-#define	offsetofsplsw(x)	(offsetof(struct splsw, x) / sizeof(uint32_t))
-static uint32_t splreal[J_SPLMAX] = {
-	[J_SPLHIGH] =		offsetofsplsw(splsw_splhigh),
-	[J_SPLHIGH_NOPROF] =	offsetofsplsw(splsw_splhigh_noprof),
-	[J_SPLSCHED] =		offsetofsplsw(splsw_splsched),
-	[J_SPLVM] =		offsetofsplsw(splsw_splvm),
-	[J_SPLSOFTSERIAL] =	offsetofsplsw(splsw_splsoftserial),
-	[J_SPLSOFTNET] =	offsetofsplsw(splsw_splsoftnet),
-	[J_SPLSOFTBIO] =	offsetofsplsw(splsw_splsoftbio),
-	[J_SPLSOFTCLOCK] =	offsetofsplsw(splsw_splsoftclock),
-	[J_SPL0] =		offsetofsplsw(splsw_spl0),
-	[J_SPLX] =		offsetofsplsw(splsw_splx),
-	[J_SPLX_NOPROF] =	offsetofsplsw(splsw_splx_noprof),
-	[J_SPLRAISE] =		offsetofsplsw(splsw_splraise),
-	[J_SPLINTR] =		offsetofsplsw(splsw_splintr),
-	[J_SETSOFTINTR] =	offsetofsplsw(splsw_setsoftintr),
-	[J_CLRSOFTINTR] =	offsetofsplsw(splsw_clrsoftintr),
-};
-#endif
+void
+splcheck(void)
+{
+	(*mips_splsw.splsw_splcheck)();
+}
 
 void
 fixup_splcalls(void)
@@ -190,49 +159,39 @@
 	extern uint32_t _ftext[];
 	extern uint32_t _etext[];
 
-#define	addr2offset(x)	((((uint32_t)(uintptr_t)(x)) << 4) >> 6)
-#define	stuboffset(x)	addr2offset(x)
-	uint32_t splstubs[J_SPLMAX] = {
-		[J_SPLHIGH] =		stuboffset(splhigh),
-		[J_SPLHIGH_NOPROF] =	stuboffset(splhigh_noprof),
-		[J_SPLSCHED] =		stuboffset(splsched),
-		[J_SPLVM] =		stuboffset(splvm),
-		[J_SPLSOFTSERIAL] =	stuboffset(splsoftserial),
-		[J_SPLSOFTNET] =	stuboffset(splsoftnet),
-		[J_SPLSOFTBIO] =	stuboffset(splsoftbio),
-		[J_SPLSOFTCLOCK] =	stuboffset(splsoftclock),
-		[J_SPL0] =		stuboffset(spl0),
-		[J_SPLX] =		stuboffset(splx),
-		[J_SPLX_NOPROF] =	stuboffset(splx_noprof),
-		[J_SPLRAISE] =		stuboffset(splraise),
-		[J_SPLINTR] =		stuboffset(splintr),
-		[J_SETSOFTINTR] =	stuboffset(_setsoftintr),
-		[J_CLRSOFTINTR] =	stuboffset(_clrsoftintr),
+#define	splfixupinfo(x)	{ fixup_addr2offset(x), \
+			  fixup_addr2offset(mips_splsw.splsw_##x) }
+	struct mips_jump_fixup_info fixups[] = {
+		splfixupinfo(splhigh),
+		splfixupinfo(splhigh_noprof),
+		splfixupinfo(splsched),
+		splfixupinfo(splvm),
+		splfixupinfo(splsoftserial),
+		splfixupinfo(splsoftnet),
+		splfixupinfo(splsoftbio),
+		splfixupinfo(splsoftclock),
+		splfixupinfo(spl0),
+		splfixupinfo(splx),
+		splfixupinfo(splx_noprof),
+		splfixupinfo(splraise),
+		splfixupinfo(splintr),
+		splfixupinfo(_setsoftintr),
+		splfixupinfo(_clrsoftintr),
+		splfixupinfo(splcheck),
 	};
 
-#define	realoffset(x)	addr2offset(mips_splsw.splsw_##x)
-	uint32_t splreal[J_SPLMAX] = {
-		[J_SPLHIGH] =		realoffset(splhigh),
-		[J_SPLHIGH_NOPROF] =	realoffset(splhigh_noprof),
-		[J_SPLSCHED] =		realoffset(splsched),
-		[J_SPLVM] =		realoffset(splvm),
-		[J_SPLSOFTSERIAL] =	realoffset(splsoftserial),
-		[J_SPLSOFTNET] =	realoffset(splsoftnet),
-		[J_SPLSOFTBIO] =	realoffset(splsoftbio),
-		[J_SPLSOFTCLOCK] =	realoffset(splsoftclock),
-		[J_SPL0] =		realoffset(spl0),
-		[J_SPLX] =		realoffset(splx),
-		[J_SPLX_NOPROF] =	realoffset(splx_noprof),
-		[J_SPLRAISE] =		realoffset(splraise),
-		[J_SPLINTR] =		realoffset(splintr),
-		[J_SETSOFTINTR] =	realoffset(_setsoftintr),
-		[J_CLRSOFTINTR] =	realoffset(_clrsoftintr),
-	};
-
-#if 0
-	for (size_t i = 0; i < J_SPLMAX; i++) {
-		splreal[i] = (((uint32_t *)&mips_splsw)[splreal[i]] << 4) >> 6;
+	/*
+	 * [bubble] sort fixups from lowest stub to highest stub.
+	 */
+	for (size_t i = 0; i < __arraycount(fixups) - 1; i++) {
+		for (size_t j = i + 1; j < __arraycount(fixups); j++) {
+			if (fixups[i].jfi_stub > fixups[j].jfi_stub) {
+				struct mips_jump_fixup_info tmp = fixups[i];
+				fixups[i] = fixups[j];
+				fixups[j] = tmp;
+			}
+		}
 	}
-#endif
-	mips_fixup_stubs(_ftext, _etext, splstubs, splreal, J_SPLMAX);
+
+	mips_fixup_stubs(_ftext, _etext, fixups, __arraycount(fixups));
 }

Reply via email to