[BACK]Return to patch.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / arch / x86 / x86

Annotation of src/sys/arch/x86/x86/patch.c, Revision 1.32

1.32    ! maxv        1: /*     $NetBSD: patch.c,v 1.31 2018/01/27 09:33:25 maxv Exp $  */
1.2       ad          2:
                      3: /*-
1.16      ad          4:  * Copyright (c) 2007, 2008, 2009 The NetBSD Foundation, Inc.
1.2       ad          5:  * All rights reserved.
                      6:  *
                      7:  * This code is derived from software contributed to The NetBSD Foundation
                      8:  * by Andrew Doran.
                      9:  *
                     10:  * Redistribution and use in source and binary forms, with or without
                     11:  * modification, are permitted provided that the following conditions
                     12:  * are met:
                     13:  * 1. Redistributions of source code must retain the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer.
                     15:  * 2. Redistributions in binary form must reproduce the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer in the
                     17:  *    documentation and/or other materials provided with the distribution.
                     18:  *
                     19:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     20:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     21:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     22:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     23:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     24:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     25:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     26:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     27:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     28:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     29:  * POSSIBILITY OF SUCH DAMAGE.
                     30:  */
                     31:
                     32: /*
                     33:  * Patch kernel code at boot time, depending on available CPU features.
                     34:  */
                     35:
                     36: #include <sys/cdefs.h>
1.32    ! maxv       37: __KERNEL_RCSID(0, "$NetBSD: patch.c,v 1.31 2018/01/27 09:33:25 maxv Exp $");
1.2       ad         38:
                     39: #include "opt_lockdebug.h"
1.20      dyoung     40: #ifdef i386
1.19      dyoung     41: #include "opt_spldebug.h"
1.20      dyoung     42: #endif
1.2       ad         43:
                     44: #include <sys/types.h>
                     45: #include <sys/systm.h>
                     46:
                     47: #include <machine/cpu.h>
                     48: #include <machine/cpufunc.h>
                     49: #include <machine/specialreg.h>
1.26      maxv       50: #include <machine/frameasm.h>
1.2       ad         51:
                     52: #include <x86/cpuvar.h>
                     53: #include <x86/cputypes.h>
                     54:
1.26      maxv       55: struct hotpatch {
                     56:        uint8_t name;
                     57:        uint8_t size;
                     58:        void *addr;
                     59: } __packed;
                     60:
1.2       ad         61: void   spllower(int);
                     62: void   spllower_end(void);
1.6       ad         63: void   cx8_spllower(int);
                     64: void   cx8_spllower_end(void);
                     65: void   cx8_spllower_patch(void);
1.2       ad         66:
                     67: void   mutex_spin_exit_end(void);
                     68: void   i686_mutex_spin_exit(int);
                     69: void   i686_mutex_spin_exit_end(void);
                     70: void   i686_mutex_spin_exit_patch(void);
                     71:
1.8       ad         72: void   membar_consumer(void);
                     73: void   membar_consumer_end(void);
                     74: void   membar_sync(void);
                     75: void   membar_sync_end(void);
                     76: void   sse2_lfence(void);
                     77: void   sse2_lfence_end(void);
                     78: void   sse2_mfence(void);
                     79: void   sse2_mfence_end(void);
                     80:
1.10      ad         81: void   _atomic_cas_64(void);
                     82: void   _atomic_cas_64_end(void);
                     83: void   _atomic_cas_cx8(void);
                     84: void   _atomic_cas_cx8_end(void);
                     85:
1.8       ad         86: extern void    *atomic_lockpatch[];
1.6       ad         87:
1.2       ad         88: #define        X86_NOP         0x90
                     89: #define        X86_REP         0xf3
                     90: #define        X86_RET         0xc3
                     91: #define        X86_CS          0x2e
                     92: #define        X86_DS          0x3e
                     93: #define        X86_GROUP_0F    0x0f
                     94:
1.17      enami      95: static void
                     96: adjust_jumpoff(uint8_t *ptr, void *from_s, void *to_s)
                     97: {
                     98:
                     99:        /* Branch hints */
                    100:        if (ptr[0] == X86_CS || ptr[0] == X86_DS)
                    101:                ptr++;
                    102:        /* Conditional jumps */
                    103:        if (ptr[0] == X86_GROUP_0F)
                    104:                ptr++;
                    105:        /* 4-byte relative jump or call */
                    106:        *(uint32_t *)(ptr + 1 - (uintptr_t)from_s + (uintptr_t)to_s) +=
                    107:            ((uint32_t)(uintptr_t)from_s - (uint32_t)(uintptr_t)to_s);
                    108: }
                    109:
1.14      gmcgarry  110: static void __unused
1.2       ad        111: patchfunc(void *from_s, void *from_e, void *to_s, void *to_e,
                    112:          void *pcrel)
                    113: {
                    114:
                    115:        if ((uintptr_t)from_e - (uintptr_t)from_s !=
                    116:            (uintptr_t)to_e - (uintptr_t)to_s)
                    117:                panic("patchfunc: sizes do not match (from=%p)", from_s);
                    118:
                    119:        memcpy(to_s, from_s, (uintptr_t)to_e - (uintptr_t)to_s);
1.17      enami     120:        if (pcrel != NULL)
                    121:                adjust_jumpoff(pcrel, from_s, to_s);
                    122:
                    123: #ifdef GPROF
                    124: #ifdef i386
                    125: #define        MCOUNT_CALL_OFFSET      3
                    126: #endif
                    127: #ifdef __x86_64__
                    128: #define        MCOUNT_CALL_OFFSET      5
                    129: #endif
                    130:        /* Patch mcount call offset */
                    131:        adjust_jumpoff((uint8_t *)from_s + MCOUNT_CALL_OFFSET, from_s, to_s);
                    132: #endif
1.2       ad        133: }
                    134:
1.14      gmcgarry  135: static inline void __unused
1.25      maxv      136: patchbytes(void *addr, const uint8_t *bytes, size_t size)
1.2       ad        137: {
1.25      maxv      138:        uint8_t *ptr = (uint8_t *)addr;
                    139:        size_t i;
1.6       ad        140:
1.25      maxv      141:        for (i = 0; i < size; i++) {
                    142:                ptr[i] = bytes[i];
                    143:        }
1.2       ad        144: }
                    145:
1.26      maxv      146: static void
                    147: x86_hotpatch(uint32_t name, const uint8_t *bytes, size_t size)
                    148: {
                    149:        extern char __rodata_hotpatch_start;
                    150:        extern char __rodata_hotpatch_end;
                    151:        struct hotpatch *hps, *hpe, *hp;
                    152:
                    153:        hps = (struct hotpatch *)&__rodata_hotpatch_start;
                    154:        hpe = (struct hotpatch *)&__rodata_hotpatch_end;
                    155:
                    156:        for (hp = hps; hp < hpe; hp++) {
                    157:                if (hp->name != name) {
                    158:                        continue;
                    159:                }
                    160:                if (hp->size != size) {
                    161:                        panic("x86_hotpatch: incorrect size");
                    162:                }
                    163:                patchbytes(hp->addr, bytes, size);
                    164:        }
                    165: }
                    166:
1.2       ad        167: void
1.15      ad        168: x86_patch(bool early)
1.2       ad        169: {
1.16      ad        170:        static bool first, second;
1.6       ad        171:        u_long psl;
1.2       ad        172:        u_long cr0;
                    173:
1.16      ad        174:        if (early) {
                    175:                if (first)
                    176:                        return;
                    177:                first = true;
                    178:        } else {
                    179:                if (second)
                    180:                        return;
                    181:                second = true;
                    182:        }
1.2       ad        183:
1.6       ad        184:        /* Disable interrupts. */
                    185:        psl = x86_read_psl();
                    186:        x86_disable_intr();
                    187:
1.2       ad        188:        /* Disable write protection in supervisor mode. */
                    189:        cr0 = rcr0();
                    190:        lcr0(cr0 & ~CR0_WP);
                    191:
1.15      ad        192: #if !defined(GPROF)
                    193:        if (!early && ncpu == 1) {
1.10      ad        194: #ifndef LOCKDEBUG
1.27      maxv      195:                /*
                    196:                 * Uniprocessor: kill LOCK prefixes.
                    197:                 */
1.25      maxv      198:                const uint8_t bytes[] = {
                    199:                        X86_NOP
                    200:                };
                    201:
1.27      maxv      202:                /* lock -> nop */
                    203:                x86_hotpatch(HP_NAME_NOLOCK, bytes, sizeof(bytes));
1.30      christos  204:                for (int i = 0; atomic_lockpatch[i] != 0; i++)
1.28      maxv      205:                        patchbytes(atomic_lockpatch[i], bytes, sizeof(bytes));
1.27      maxv      206: #endif
1.15      ad        207:        }
1.27      maxv      208:
1.21      jym       209:        if (!early && (cpu_feature[0] & CPUID_SSE2) != 0) {
1.24      riastrad  210:                /*
                    211:                 * Faster memory barriers.  We do not need to patch
                    212:                 * membar_producer to use SFENCE because on x86
                    213:                 * ordinary non-temporal stores are always issued in
                    214:                 * program order to main memory and to other CPUs.
                    215:                 */
1.2       ad        216:                patchfunc(
1.8       ad        217:                    sse2_lfence, sse2_lfence_end,
                    218:                    membar_consumer, membar_consumer_end,
                    219:                    NULL
                    220:                );
                    221:                patchfunc(
                    222:                    sse2_mfence, sse2_mfence_end,
                    223:                    membar_sync, membar_sync_end,
                    224:                    NULL
                    225:                );
1.2       ad        226:        }
1.15      ad        227: #endif /* GPROF */
1.2       ad        228:
1.15      ad        229: #ifdef i386
                    230:        /*
                    231:         * Patch early and late.  Second time around the 'lock' prefix
                    232:         * may be gone.
                    233:         */
1.21      jym       234:        if ((cpu_feature[0] & CPUID_CX8) != 0) {
1.15      ad        235:                patchfunc(
                    236:                    _atomic_cas_cx8, _atomic_cas_cx8_end,
                    237:                    _atomic_cas_64, _atomic_cas_64_end,
                    238:                    NULL
                    239:                );
                    240:        }
                    241: #endif /* i386 */
                    242:
1.19      dyoung    243: #if !defined(SPLDEBUG)
1.21      jym       244:        if (!early && (cpu_feature[0] & CPUID_CX8) != 0) {
1.6       ad        245:                /* Faster splx(), mutex_spin_exit(). */
                    246:                patchfunc(
                    247:                    cx8_spllower, cx8_spllower_end,
                    248:                    spllower, spllower_end,
                    249:                    cx8_spllower_patch
                    250:                );
1.15      ad        251: #if defined(i386) && !defined(LOCKDEBUG)
1.6       ad        252:                patchfunc(
                    253:                    i686_mutex_spin_exit, i686_mutex_spin_exit_end,
                    254:                    mutex_spin_exit, mutex_spin_exit_end,
                    255:                    i686_mutex_spin_exit_patch
                    256:                );
1.19      dyoung    257: #endif /* i386 && !LOCKDEBUG */
1.6       ad        258:        }
1.19      dyoung    259: #endif /* !SPLDEBUG */
1.6       ad        260:
1.18      ad        261:        /*
                    262:         * On some Opteron revisions, locked operations erroneously
                    263:         * allow memory references to be `bled' outside of critical
                    264:         * sections.  Apply workaround.
                    265:         */
                    266:        if (cpu_vendor == CPUVENDOR_AMD &&
1.22      msaitoh   267:            (CPUID_TO_FAMILY(cpu_info_primary.ci_signature) == 0xe ||
                    268:            (CPUID_TO_FAMILY(cpu_info_primary.ci_signature) == 0xf &&
                    269:            CPUID_TO_EXTMODEL(cpu_info_primary.ci_signature) < 0x4))) {
1.25      maxv      270:                const uint8_t bytes[] = {
                    271:                        0x0F, 0xAE, 0xE8 /* lfence */
                    272:                };
                    273:
1.29      maxv      274:                /* ret,nop,nop -> lfence */
                    275:                x86_hotpatch(HP_NAME_RETFENCE, bytes, sizeof(bytes));
1.18      ad        276:        }
                    277:
1.23      maxv      278:        /*
                    279:         * If SMAP is present then patch the prepared holes with clac/stac
                    280:         * instructions.
                    281:         *
                    282:         * clac = 0x0f, 0x01, 0xca
                    283:         * stac = 0x0f, 0x01, 0xcb
                    284:         */
                    285:        if (!early && cpu_feature[5] & CPUID_SEF_SMAP) {
                    286:                KASSERT(rcr4() & CR4_SMAP);
1.25      maxv      287:                const uint8_t clac_bytes[] = {
                    288:                        0x0F, 0x01, 0xCA /* clac */
                    289:                };
                    290:                const uint8_t stac_bytes[] = {
                    291:                        0x0F, 0x01, 0xCB /* stac */
                    292:                };
                    293:
1.26      maxv      294:                /* nop,nop,nop -> clac */
                    295:                x86_hotpatch(HP_NAME_CLAC, clac_bytes, sizeof(clac_bytes));
                    296:
                    297:                /* nop,nop,nop -> stac */
                    298:                x86_hotpatch(HP_NAME_STAC, stac_bytes, sizeof(stac_bytes));
1.23      maxv      299:        }
                    300:
1.32    ! maxv      301: #ifdef SVS
        !           302:        if (early && cpu_vendor == CPUVENDOR_INTEL) {
        !           303:                extern uint8_t svs_enter, svs_enter_end;
        !           304:                extern uint8_t svs_enter_altstack, svs_enter_altstack_end;
        !           305:                extern uint8_t svs_leave, svs_leave_end;
        !           306:                extern uint8_t svs_leave_altstack, svs_leave_altstack_end;
        !           307:                extern bool svs_enabled;
        !           308:                uint8_t *bytes;
        !           309:                size_t size;
        !           310:
        !           311:                svs_enabled = true;
        !           312:
        !           313:                bytes = &svs_enter;
        !           314:                size = (size_t)&svs_enter_end - (size_t)&svs_enter;
        !           315:                x86_hotpatch(HP_NAME_SVS_ENTER, bytes, size);
        !           316:
        !           317:                bytes = &svs_enter_altstack;
        !           318:                size = (size_t)&svs_enter_altstack_end -
        !           319:                    (size_t)&svs_enter_altstack;
        !           320:                x86_hotpatch(HP_NAME_SVS_ENTER_ALT, bytes, size);
        !           321:
        !           322:                bytes = &svs_leave;
        !           323:                size = (size_t)&svs_leave_end - (size_t)&svs_leave;
        !           324:                x86_hotpatch(HP_NAME_SVS_LEAVE, bytes, size);
        !           325:
        !           326:                bytes = &svs_leave_altstack;
        !           327:                size = (size_t)&svs_leave_altstack_end -
        !           328:                    (size_t)&svs_leave_altstack;
        !           329:                x86_hotpatch(HP_NAME_SVS_LEAVE_ALT, bytes, size);
        !           330:        }
        !           331: #endif
        !           332:
1.6       ad        333:        /* Write back and invalidate cache, flush pipelines. */
                    334:        wbinvd();
                    335:        x86_flush();
                    336:        x86_write_psl(psl);
1.2       ad        337:
                    338:        /* Re-enable write protection. */
                    339:        lcr0(cr0);
                    340: }

CVSweb <webmaster@jp.NetBSD.org>