Module Name:    src
Committed By:   matt
Date:           Sun Feb 28 03:21:07 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

Log Message:
Add code which can change a direct jump to stub with an indirect call to
a direct jump to the actual routine.


To generate a diff of this commit:
cvs rdiff -u -r1.78.36.1.2.16 -r1.78.36.1.2.17 \
    src/sys/arch/mips/include/locore.h
cvs rdiff -u -r1.1.2.2 -r1.1.2.3 src/sys/arch/mips/mips/mips_fixup.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.16 src/sys/arch/mips/include/locore.h:1.78.36.1.2.17
--- src/sys/arch/mips/include/locore.h:1.78.36.1.2.16	Sat Feb 27 07:58:52 2010
+++ src/sys/arch/mips/include/locore.h	Sun Feb 28 03:21:06 2010
@@ -1,4 +1,4 @@
-/* $NetBSD: locore.h,v 1.78.36.1.2.16 2010/02/27 07:58:52 matt Exp $ */
+/* $NetBSD: locore.h,v 1.78.36.1.2.17 2010/02/28 03:21:06 matt Exp $ */
 
 /*
  * This file should not be included by MI code!!!
@@ -47,8 +47,14 @@
 
 typedef bool (*mips_fixup_callback_t)(int32_t, uint32_t [2]);
  
+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	fixup_mips_cpu_switch_resume(void);
+
+void	mips_cpu_switch_resume(struct lwp *);
 
 #ifdef MIPS1
 void	mips1_tlb_set_asid(uint32_t);

Index: src/sys/arch/mips/mips/mips_fixup.c
diff -u src/sys/arch/mips/mips/mips_fixup.c:1.1.2.2 src/sys/arch/mips/mips/mips_fixup.c:1.1.2.3
--- src/sys/arch/mips/mips/mips_fixup.c:1.1.2.2	Sat Feb 27 18:25:25 2010
+++ src/sys/arch/mips/mips/mips_fixup.c	Sun Feb 28 03:21:07 2010
@@ -29,7 +29,7 @@
 
 #include <sys/cdefs.h>
 
-__KERNEL_RCSID(0, "$NetBSD: mips_fixup.c,v 1.1.2.2 2010/02/27 18:25:25 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: mips_fixup.c,v 1.1.2.3 2010/02/28 03:21:07 matt Exp $");
 
 #include <sys/param.h>
 
@@ -71,20 +71,20 @@
 		if (INSN_LUI_P(insn)) {
 			const int32_t offset = insn << 16;
 			lui_reg = (insn >> 16) & 31;
-#ifdef DEBUG
-			printf("%s: %#x: insn %08x: lui r%zu, %%hi(%#x)", 
+#ifdef DEBUG_VERBOSE
+			printf("%s: %#x: insn %08x: lui r%zu, %%hi(%#x)",
 			    __func__, (int32_t)(intptr_t)insnp,
 			    insn, lui_reg, offset);
 #endif
 			if (upper_addr == offset) {
 				lui_insnp = insnp;
-#ifdef DEBUG
+#ifdef DEBUG_VERBOSE
 				printf(" (maybe)");
 #endif
 			} else {
 				lui_insnp = NULL;
 			}
-#ifdef DEBUG
+#ifdef DEBUG_VERBOSE
 			printf("\n");
 #endif
 		} else if (lui_insnp != NULL && INSN_LOAD_P(insn)) {
@@ -95,8 +95,8 @@
 			    && load_addr < addr + size
 			    && base == lui_reg
 			    && rt == lui_reg) {
-#ifdef DEBUG
-				printf("%s: %#x: insn %08x: %s r%zu, %%lo(%08x)(r%zu)\n", 
+#ifdef DEBUG_VERBOSE
+				printf("%s: %#x: insn %08x: %s r%zu, %%lo(%08x)(r%zu)\n",
 				    __func__, (int32_t)(intptr_t)insnp,
 				    insn, INSN_LW_P(insn) ? "lw" : "ld",
 				    rt, load_addr, base);
@@ -143,8 +143,8 @@
 	new_insns[0] =
 	    (new_insns[1] & (0xfc1f0000|PAGE_MASK)) | (0xffff & ~PAGE_MASK);
 	new_insns[1] = 0;
-#ifdef DEBUG
-	printf("%s: %08x: insn#1 %08x: %s r%u, %d(r%u)\n", 
+#ifdef DEBUG_VERBOSE
+	printf("%s: %08x: insn#1 %08x: %s r%u, %d(r%u)\n",
 	    __func__, (int32_t)load_addr, new_insns[0],
 	    INSN_LW_P(new_insns[0]) ? "lw" : "ld",
 	    (new_insns[0] >> 16) & 31,
@@ -171,3 +171,121 @@
 
 	return true;
 }
+
+#define OPCODE_J		002
+#define OPCODE_JAL		003
+
+static void
+fixup_mips_jump(uint32_t *insnp, uint32_t stub, uint32_t real)
+{
+	uint32_t insn = *insnp;
+
+	KASSERT((insn >> (26+1)) == (OPCODE_J >> 1));
+	KASSERT((insn << 6) == (stub << 4));
+
+	insn ^= (stub ^ real) << 4 >> 6;
+
+	KASSERT((insn << 6) == (real << 4));
+
+	*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)
+{
+	uint32_t min_offset = 0x03ffffff;
+	uint32_t max_offset = 0x00000000;
+#ifdef DEBUG
+	size_t fixups = 0;
+	uint32_t cycles = (CPUISMIPS3 ? mips3_cp0_count_read() : 0);
+#endif
+
+	/*
+	 * Find the lowest and highest jumps we will be replacing.  We don't
+	 * need to do but it does make weeding out the non-matching jumps
+	 * faster.
+	 */
+	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 (uint32_t *insnp = start; insnp < end; insnp++) {
+		uint32_t insn = *insnp;
+		uint32_t offset = insn & 0x03ffffff;
+		uint32_t opcode = insn >> 26;
+
+		/*
+		 * First we check to see if this is a jump and whether its
+		 * within the range we are interested in.
+		 */
+		if ((opcode != OPCODE_J && opcode != OPCODE_JAL)
+		    || offset < min_offset || max_offset < offset)
+			continue;
+
+		/*
+		 * 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;
+			/*
+			 * 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 cacheline
+			 * we fixed.
+			 */
+			*insnp ^= offset ^ real_offsets[i];
+#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++;
+#endif
+			break;
+		}
+	}
+
+	if (sizeof(uint32_t [end - start]) > mips_cache_info.mci_picache_size)
+		mips_icache_sync_all();
+	else
+		mips_icache_sync_range((vaddr_t)start,
+		    sizeof(uint32_t [end - start]));
+
+#ifdef DEBUG
+	if (CPUISMIPS3)
+		cycles = mips3_cp0_count_read() - cycles;
+	printf("%s: %zu fixup%s done in %u cycles\n", __func__,
+	    fixups, fixups == 1 ? "" : "s",
+	    cycles);
+#endif
+}
+
+void mips_cpu_switch_resume(struct lwp *l) __section(".stub");
+
+void
+mips_cpu_switch_resume(struct lwp *l)
+{
+	(*mips_locoresw.lsw_cpu_switch_resume)(l);
+}
+
+void
+fixup_mips_cpu_switch_resume(void)
+{
+	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);
+}

Reply via email to