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