diff options
author | Tom Cosgrove <tom@cvs.openbsd.org> | 2007-02-17 17:38:38 +0000 |
---|---|---|
committer | Tom Cosgrove <tom@cvs.openbsd.org> | 2007-02-17 17:38:38 +0000 |
commit | 574a3af15cc4802db79e1bab0f6fb86a1be67e35 (patch) | |
tree | 55bd86325bdab61acaca8a8c7129b3e8203b8f4b | |
parent | bedcf8741a00e4ceebdf990d943f1d85c88ce422 (diff) |
Bring in the AMD errata checks from amd64.
Changes to either copy of amd64errata.c must be replicated in the other.
ok deraadt@
-rw-r--r-- | sys/arch/i386/conf/files.i386 | 3 | ||||
-rw-r--r-- | sys/arch/i386/i386/amd64errata.c | 381 | ||||
-rw-r--r-- | sys/arch/i386/i386/machdep.c | 5 | ||||
-rw-r--r-- | sys/arch/i386/include/cpufunc.h | 32 | ||||
-rw-r--r-- | sys/arch/i386/include/specialreg.h | 47 |
5 files changed, 464 insertions, 4 deletions
diff --git a/sys/arch/i386/conf/files.i386 b/sys/arch/i386/conf/files.i386 index 0cfb5232e65..e0c62190346 100644 --- a/sys/arch/i386/conf/files.i386 +++ b/sys/arch/i386/conf/files.i386 @@ -1,4 +1,4 @@ -# $OpenBSD: files.i386,v 1.152 2006/11/27 18:04:28 gwk Exp $ +# $OpenBSD: files.i386,v 1.153 2007/02/17 17:38:37 tom Exp $ # # new style config file for i386 architecture # @@ -24,6 +24,7 @@ file arch/i386/i386/in_cksum.s inet file arch/i386/i386/ipx_cksum.c ipx file arch/i386/i386/machdep.c file arch/i386/i386/via.c i686_cpu +file arch/i386/i386/amd64errata.c i686_cpu file arch/i386/i386/kgdb_machdep.c kgdb file arch/i386/i386/longrun.c !small_kernel & i586_cpu file arch/i386/i386/mem.c diff --git a/sys/arch/i386/i386/amd64errata.c b/sys/arch/i386/i386/amd64errata.c new file mode 100644 index 00000000000..70310301122 --- /dev/null +++ b/sys/arch/i386/i386/amd64errata.c @@ -0,0 +1,381 @@ +/* $OpenBSD: amd64errata.c,v 1.1 2007/02/17 17:38:37 tom Exp $ */ +/* $NetBSD: errata.c,v 1.6 2007/02/05 21:05:45 ad Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Andrew Doran. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Detect, report on, and work around known errata with AMD amd64 CPUs. + * + * This is generalised because there are quite a few problems that the + * BIOS can patch via MSR, but it is not known if the OS can patch these + * yet. The list is expected to grow over time. + * + * The data here are from: Revision Guide for AMD Athlon 64 and + * AMD Opteron Processors, Publication #25759, Revision: 3.69, + * Issue Date: September 2006 + */ + +#include <sys/param.h> + +#include <sys/types.h> +#include <sys/systm.h> + +#include <machine/cpu.h> +#include <machine/cpufunc.h> +#include <machine/specialreg.h> + + +typedef struct errata { + u_short e_num; + u_short e_reported; + u_int e_data1; + const uint8_t *e_set; + int (*e_act)(struct cpu_info *, struct errata *); + uint64_t e_data2; +} errata_t; + +typedef enum cpurev { + BH_E4, CH_CG, CH_D0, DH_CG, DH_D0, DH_E3, DH_E6, JH_E1, + JH_E6, SH_B0, SH_B3, SH_C0, SH_CG, SH_D0, SH_E4, SH_E5, + OINK +} cpurev_t; + +static const u_int cpurevs[] = { + BH_E4, 0x0020fb1, CH_CG, 0x0000f82, CH_CG, 0x0000fb2, + CH_D0, 0x0010f80, CH_D0, 0x0010fb0, DH_CG, 0x0000fc0, + DH_CG, 0x0000fe0, DH_CG, 0x0000ff0, DH_D0, 0x0010fc0, + DH_D0, 0x0010ff0, DH_E3, 0x0020fc0, DH_E3, 0x0020ff0, + DH_E6, 0x0020fc2, DH_E6, 0x0020ff2, JH_E1, 0x0020f10, + JH_E6, 0x0020f12, JH_E6, 0x0020f32, SH_B0, 0x0000f40, + SH_B3, 0x0000f51, SH_C0, 0x0000f48, SH_C0, 0x0000f58, + SH_CG, 0x0000f4a, SH_CG, 0x0000f5a, SH_CG, 0x0000f7a, + SH_D0, 0x0010f40, SH_D0, 0x0010f50, SH_D0, 0x0010f70, + SH_E4, 0x0020f51, SH_E4, 0x0020f71, SH_E5, 0x0020f42, + OINK +}; + +static const uint8_t amd64_errata_set1[] = { + SH_B3, SH_C0, SH_CG, DH_CG, CH_CG, OINK +}; + +static const uint8_t amd64_errata_set2[] = { + SH_B3, SH_C0, SH_CG, DH_CG, CH_CG, SH_D0, DH_D0, CH_D0, OINK +}; + +static const uint8_t amd64_errata_set3[] = { + JH_E1, DH_E3, OINK +}; + +static const uint8_t amd64_errata_set4[] = { + SH_C0, SH_CG, DH_CG, CH_CG, SH_D0, DH_D0, CH_D0, JH_E1, + DH_E3, SH_E4, BH_E4, SH_E5, DH_E6, JH_E6, OINK +}; + +static const uint8_t amd64_errata_set5[] = { + SH_B3, OINK +}; + +static const uint8_t amd64_errata_set6[] = { + SH_C0, SH_CG, DH_CG, CH_CG, OINK +}; + +static const uint8_t amd64_errata_set7[] = { + SH_C0, SH_CG, DH_CG, CH_CG, SH_D0, DH_D0, CH_D0, OINK +}; + +static const uint8_t amd64_errata_set8[] = { + BH_E4, CH_CG, CH_CG, CH_D0, CH_D0, DH_CG, DH_CG, DH_CG, + DH_D0, DH_D0, DH_E3, DH_E3, DH_E6, DH_E6, JH_E1, JH_E6, + JH_E6, SH_B0, SH_B3, SH_C0, SH_C0, SH_CG, SH_CG, SH_CG, + SH_D0, SH_D0, SH_D0, SH_E4, SH_E4, SH_E5, OINK +}; + +static int amd64_errata_setmsr(struct cpu_info *, errata_t *); +static int amd64_errata_testmsr(struct cpu_info *, errata_t *); + +static errata_t errata[] = { + /* + * 81: Cache Coherency Problem with Hardware Prefetching + * and Streaming Stores + */ + { + 81, 0, MSR_DC_CFG, amd64_errata_set5, + amd64_errata_testmsr, DC_CFG_DIS_SMC_CHK_BUF + }, + /* + * 86: DRAM Data Masking Feature Can Cause ECC Failures + */ + { + 86, 0, MSR_NB_CFG, amd64_errata_set1, + amd64_errata_testmsr, NB_CFG_DISDATMSK + }, + /* + * 89: Potential Deadlock With Locked Transactions + */ + { + 89, 0, MSR_NB_CFG, amd64_errata_set8, + amd64_errata_testmsr, NB_CFG_DISIOREQLOCK + }, + /* + * 94: Sequential Prefetch Feature May Cause Incorrect + * Processor Operation + */ + { + 94, 0, MSR_IC_CFG, amd64_errata_set1, + amd64_errata_testmsr, IC_CFG_DIS_SEQ_PREFETCH + }, + /* + * 97: 128-Bit Streaming Stores May Cause Coherency + * Failure + * + * XXX "This workaround must not be applied to processors + * prior to revision C0." We don't apply it, but if it + * can't be applied, it shouldn't be reported. + */ + { + 97, 0, MSR_DC_CFG, amd64_errata_set6, + amd64_errata_testmsr, DC_CFG_DIS_CNV_WC_SSO + }, + /* + * 104: DRAM Data Masking Feature Causes ChipKill ECC + * Failures When Enabled With x8/x16 DRAM Devices + */ + { + 104, 0, MSR_NB_CFG, amd64_errata_set7, + amd64_errata_testmsr, NB_CFG_DISDATMSK + }, + /* + * 113: Enhanced Write-Combining Feature Causes System Hang + */ + { + 113, 0, MSR_BU_CFG, amd64_errata_set3, + amd64_errata_setmsr, BU_CFG_WBENHWSBDIS + }, +#ifdef MULTIPROCESSOR + /* + * 69: Multiprocessor Coherency Problem with Hardware + * Prefetch Mechanism + */ + { + 69, 0, MSR_BU_CFG, amd64_errata_set5, + amd64_errata_setmsr, BU_CFG_WBPFSMCCHKDIS + }, + /* + * 101: DRAM Scrubber May Cause Data Corruption When Using + * Node-Interleaved Memory + */ + { + 101, 0, 0, amd64_errata_set2, + NULL, 0 + }, + /* + * 106: Potential Deadlock with Tightly Coupled Semaphores + * in an MP System + */ + { + 106, 0, MSR_LS_CFG, amd64_errata_set2, + amd64_errata_testmsr, LS_CFG_DIS_LS2_SQUISH + }, + /* + * 107: Possible Multiprocessor Coherency Problem with + * Setting Page Table A/D Bits + */ + { + 107, 0, MSR_BU_CFG, amd64_errata_set2, + amd64_errata_testmsr, BU_CFG_THRL2IDXCMPDIS + }, +#if 0 + /* + * 122: TLB Flush Filter May Cause Coherency Problem in + * Multiprocessor Systems + */ + { + 122, 0, MSR_HWCR, amd64_errata_set4, + amd64_errata_setmsr, HWCR_FFDIS + }, +#endif +#endif /* MULTIPROCESSOR */ +}; + +static int +amd64_errata_testmsr(struct cpu_info *ci, errata_t *e) +{ + uint64_t val; + + (void)ci; + + val = rdmsr_locked(e->e_data1, OPTERON_MSR_PASSCODE); + if ((val & e->e_data2) != 0) + return 0; /* not found */ + + e->e_reported = 1; + return 1; /* found */ +} + +static int +amd64_errata_setmsr(struct cpu_info *ci, errata_t *e) +{ + uint64_t val; + + (void)ci; + + val = rdmsr_locked(e->e_data1, OPTERON_MSR_PASSCODE); + if ((val & e->e_data2) != 0) + return 0; /* not found */ + + wrmsr_locked(e->e_data1, OPTERON_MSR_PASSCODE, val | e->e_data2); + +#ifdef ERRATA_DEBUG + printf("ERRATA: writing a fix\n"); + val = rdmsr_locked(e->e_data1, OPTERON_MSR_PASSCODE); + if ((val & e->e_data2) != 0) + printf("ERRATA: fix seems to have worked!\n"); +#endif + + e->e_reported = 1; + return 2; /* found and fixed */ +} + +void +amd64_errata(struct cpu_info *ci) +{ + errata_t *e, *ex; + cpurev_t rev; + int i, j; + int rc; + int found = 0; + int corrected = 0; + u_int32_t regs[4]; + + cpuid(0x80000001, regs); + + for (i = 0; ; i += 2) { + if ((rev = cpurevs[i]) == OINK) { +#ifdef ERRATA_DEBUG + printf("ERRATA: this CPU ok\n"); +#endif + return; + } + if (cpurevs[i + 1] == regs[0]) { +#ifdef ERRATA_DEBUG + printf("ERRATA: this CPU has errata\n"); +#endif + break; + } + } + + ex = errata + sizeof(errata) / sizeof(errata[0]); + + /* Reset e_reporteds (for multiple CPUs) */ + for (e = errata; e < ex; e++) + e->e_reported = 0; + + for (e = errata; e < ex; e++) { + if (e->e_reported) + continue; + if (e->e_set != NULL) { + for (j = 0; e->e_set[j] != OINK; j++) + if (e->e_set[j] == rev) + break; + if (e->e_set[j] == OINK) + continue; + } + +#ifdef ERRATA_DEBUG + printf("%s: testing for erratum %d\n", + ci->ci_dev.dv_xname, e->e_num); +#endif + + /* + * If we have an action routine, call it, otherwise + * the default is that this erratum is present. + */ + rc = (e->e_act == NULL) ? 1 : (*e->e_act)(ci, e); + + if (rc == 0) /* not found */ + continue; + if (rc == 1) + found++; + if (rc == 2) + corrected++; + + e->e_reported = rc; + +#ifdef ERRATA_DEBUG + printf("%s: erratum %d present%s\n", + ci->ci_dev.dv_xname, e->e_num, + (rc == 2) ? " and patched" : ""); +#endif + } + +#define ERRATA_VERBOSE +#ifdef ERRATA_VERBOSE + if (corrected) { + int first = 1; + + /* Print out found and corrected */ + printf("%s: AMD %s", ci->ci_dev.dv_xname, + (corrected == 1) ? "erratum" : "errata"); + for (e = errata; e < ex; e++) { + if (e->e_reported == 2) { + if (! first) + printf(","); + printf(" %d", e->e_num); + first = 0; + } + } + printf(" detected and fixed\n"); + } +#endif + + if (found) { + int first = 1; + + /* Print out found but not corrected */ + printf("%s: AMD %s", ci->ci_dev.dv_xname, + (found == 1) ? "erratum" : "errata"); + for (e = errata; e < ex; e++) { + if (e->e_reported == 1) { + if (! first) + printf(","); + printf(" %d", e->e_num); + first = 0; + } + } + printf(" present, BIOS upgrade may be required\n"); + } +} diff --git a/sys/arch/i386/i386/machdep.c b/sys/arch/i386/i386/machdep.c index da1fb1ab044..838e9e45ce0 100644 --- a/sys/arch/i386/i386/machdep.c +++ b/sys/arch/i386/i386/machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: machdep.c,v 1.375 2007/02/13 00:22:48 jsg Exp $ */ +/* $OpenBSD: machdep.c,v 1.376 2007/02/17 17:38:37 tom Exp $ */ /* $NetBSD: machdep.c,v 1.214 1996/11/10 03:16:17 thorpej Exp $ */ /*- @@ -1952,6 +1952,9 @@ identifycpu(struct cpu_info *ci) } } else i386_use_fxsave = 0; + + if (vendor == CPUVENDOR_AMD) + amd64_errata(ci); #endif /* I686_CPU */ } diff --git a/sys/arch/i386/include/cpufunc.h b/sys/arch/i386/include/cpufunc.h index 832e4271142..0a4134b9462 100644 --- a/sys/arch/i386/include/cpufunc.h +++ b/sys/arch/i386/include/cpufunc.h @@ -1,4 +1,4 @@ -/* $OpenBSD: cpufunc.h,v 1.12 2004/06/13 21:49:16 niklas Exp $ */ +/* $OpenBSD: cpufunc.h,v 1.13 2007/02/17 17:38:37 tom Exp $ */ /* $NetBSD: cpufunc.h,v 1.8 1994/10/27 04:15:59 cgd Exp $ */ /* @@ -238,6 +238,32 @@ rdmsr(u_int msr) return (rv); } +/* + * Some of the undocumented AMD64 MSRs need a 'passcode' to access. + * + * See LinuxBIOSv2: src/cpu/amd/model_fxx/model_fxx_init.c + */ + +#define OPTERON_MSR_PASSCODE 0x9c5a203a + +static __inline u_int64_t +rdmsr_locked(u_int msr, u_int code) +{ + uint64_t rv; + __asm volatile("rdmsr" + : "=A" (rv) + : "c" (msr), "D" (code)); + return (rv); +} + +static __inline void +wrmsr_locked(u_int msr, u_int code, u_int64_t newval) +{ + __asm volatile("wrmsr" + : + : "A" (newval), "c" (msr), "D" (code)); +} + /* Break into DDB/KGDB. */ static __inline void breakpoint(void) @@ -245,5 +271,9 @@ breakpoint(void) __asm __volatile("int $3"); } +#ifdef I686_CPU +void amd64_errata(struct cpu_info *); +#endif + #endif /* _KERNEL */ #endif /* !_I386_CPUFUNC_H_ */ diff --git a/sys/arch/i386/include/specialreg.h b/sys/arch/i386/include/specialreg.h index 91a33c214fa..cc64e01a069 100644 --- a/sys/arch/i386/include/specialreg.h +++ b/sys/arch/i386/include/specialreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: specialreg.h,v 1.29 2007/02/13 00:22:48 jsg Exp $ */ +/* $OpenBSD: specialreg.h,v 1.30 2007/02/17 17:38:37 tom Exp $ */ /* $NetBSD: specialreg.h,v 1.7 1994/10/27 04:16:26 cgd Exp $ */ /*- @@ -243,6 +243,51 @@ #define MSR_K6_EPMR 0xc0000086 /* + * AMD K8 (Opteron) MSRs. + */ +#define MSR_SYSCFG 0xc0000010 + +#define MSR_EFER 0xc0000080 /* Extended feature enable */ +#define EFER_SCE 0x00000001 /* SYSCALL extension */ +#define EFER_LME 0x00000100 /* Long Mode Active */ +#define EFER_LMA 0x00000400 /* Long Mode Enabled */ +#define EFER_NXE 0x00000800 /* No-Execute Enabled */ + +#define MSR_STAR 0xc0000081 /* 32 bit syscall gate addr */ +#define MSR_LSTAR 0xc0000082 /* 64 bit syscall gate addr */ +#define MSR_CSTAR 0xc0000083 /* compat syscall gate addr */ +#define MSR_SFMASK 0xc0000084 /* flags to clear on syscall */ + +#define MSR_FSBASE 0xc0000100 /* 64bit offset for fs: */ +#define MSR_GSBASE 0xc0000101 /* 64bit offset for gs: */ +#define MSR_KERNELGSBASE 0xc0000102 /* storage for swapgs ins */ + +/* + * These require a 'passcode' for access. See cpufunc.h. + */ +#define MSR_HWCR 0xc0010015 +#define HWCR_FFDIS 0x00000040 + +#define MSR_NB_CFG 0xc001001f +#define NB_CFG_DISIOREQLOCK 0x0000000000000004ULL +#define NB_CFG_DISDATMSK 0x0000001000000000ULL + +#define MSR_LS_CFG 0xc0011020 +#define LS_CFG_DIS_LS2_SQUISH 0x02000000 + +#define MSR_IC_CFG 0xc0011021 +#define IC_CFG_DIS_SEQ_PREFETCH 0x00000800 + +#define MSR_DC_CFG 0xc0011022 +#define DC_CFG_DIS_CNV_WC_SSO 0x00000004 +#define DC_CFG_DIS_SMC_CHK_BUF 0x00000400 + +#define MSR_BU_CFG 0xc0011023 +#define BU_CFG_THRL2IDXCMPDIS 0x0000080000000000ULL +#define BU_CFG_WBPFSMCCHKDIS 0x0000200000000000ULL +#define BU_CFG_WBENHWSBDIS 0x0001000000000000ULL + +/* * Constants related to MTRRs */ #define MTRR_N64K 8 /* numbers of fixed-size entries */ |