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));
}