Skip to content

Commit 8ca9781

Browse files
jueatgithubsuryasaimadhu
authored andcommitted
x86/mce: Work around an erratum on fast string copy instructions
A rare kernel panic scenario can happen when the following conditions are met due to an erratum on fast string copy instructions: 1) An uncorrected error. 2) That error must be in first cache line of a page. 3) Kernel must execute page_copy from the page immediately before that page. The fast string copy instructions ("REP; MOVS*") could consume an uncorrectable memory error in the cache line _right after_ the desired region to copy and raise an MCE. Bit 0 of MSR_IA32_MISC_ENABLE can be cleared to disable fast string copy and will avoid such spurious machine checks. However, that is less preferable due to the permanent performance impact. Considering memory poison is rare, it's desirable to keep fast string copy enabled until an MCE is seen. Intel has confirmed the following: 1. The CPU erratum of fast string copy only applies to Skylake, Cascade Lake and Cooper Lake generations. Directly return from the MCE handler: 2. Will result in complete execution of the "REP; MOVS*" with no data loss or corruption. 3. Will not result in another MCE firing on the next poisoned cache line due to "REP; MOVS*". 4. Will resume execution from a correct point in code. 5. Will result in the same instruction that triggered the MCE firing a second MCE immediately for any other software recoverable data fetch errors. 6. Is not safe without disabling the fast string copy, as the next fast string copy of the same buffer on the same CPU would result in a PANIC MCE. This should mitigate the erratum completely with the only caveat that the fast string copy is disabled on the affected hyper thread thus performance degradation. This is still better than the OS crashing on MCEs raised on an irrelevant process due to "REP; MOVS*' accesses in a kernel context, e.g., copy_page. Tested: Injected errors on 1st cache line of 8 anonymous pages of process 'proc1' and observed MCE consumption from 'proc2' with no panic (directly returned). Without the fix, the host panicked within a few minutes on a random 'proc2' process due to kernel access from copy_page. [ bp: Fix comment style + touch ups, zap an unlikely(), improve the quirk function's readability. ] Signed-off-by: Jue Wang <juew@google.com> Signed-off-by: Borislav Petkov <bp@suse.de> Reviewed-by: Tony Luck <tony.luck@intel.com> Link: https://lore.kernel.org/r/20220218013209.2436006-1-juew@google.com
1 parent f11445b commit 8ca9781

2 files changed

Lines changed: 68 additions & 1 deletion

File tree

arch/x86/kernel/cpu/mce/core.c

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -814,6 +814,59 @@ quirk_sandybridge_ifu(int bank, struct mce *m, struct pt_regs *regs)
814814
m->cs = regs->cs;
815815
}
816816

817+
/*
818+
* Disable fast string copy and return from the MCE handler upon the first SRAR
819+
* MCE on bank 1 due to a CPU erratum on Intel Skylake/Cascade Lake/Cooper Lake
820+
* CPUs.
821+
* The fast string copy instructions ("REP; MOVS*") could consume an
822+
* uncorrectable memory error in the cache line _right after_ the desired region
823+
* to copy and raise an MCE with RIP pointing to the instruction _after_ the
824+
* "REP; MOVS*".
825+
* This mitigation addresses the issue completely with the caveat of performance
826+
* degradation on the CPU affected. This is still better than the OS crashing on
827+
* MCEs raised on an irrelevant process due to "REP; MOVS*" accesses from a
828+
* kernel context (e.g., copy_page).
829+
*
830+
* Returns true when fast string copy on CPU has been disabled.
831+
*/
832+
static noinstr bool quirk_skylake_repmov(void)
833+
{
834+
u64 mcgstatus = mce_rdmsrl(MSR_IA32_MCG_STATUS);
835+
u64 misc_enable = mce_rdmsrl(MSR_IA32_MISC_ENABLE);
836+
u64 mc1_status;
837+
838+
/*
839+
* Apply the quirk only to local machine checks, i.e., no broadcast
840+
* sync is needed.
841+
*/
842+
if (!(mcgstatus & MCG_STATUS_LMCES) ||
843+
!(misc_enable & MSR_IA32_MISC_ENABLE_FAST_STRING))
844+
return false;
845+
846+
mc1_status = mce_rdmsrl(MSR_IA32_MCx_STATUS(1));
847+
848+
/* Check for a software-recoverable data fetch error. */
849+
if ((mc1_status &
850+
(MCI_STATUS_VAL | MCI_STATUS_OVER | MCI_STATUS_UC | MCI_STATUS_EN |
851+
MCI_STATUS_ADDRV | MCI_STATUS_MISCV | MCI_STATUS_PCC |
852+
MCI_STATUS_AR | MCI_STATUS_S)) ==
853+
(MCI_STATUS_VAL | MCI_STATUS_UC | MCI_STATUS_EN |
854+
MCI_STATUS_ADDRV | MCI_STATUS_MISCV |
855+
MCI_STATUS_AR | MCI_STATUS_S)) {
856+
misc_enable &= ~MSR_IA32_MISC_ENABLE_FAST_STRING;
857+
mce_wrmsrl(MSR_IA32_MISC_ENABLE, misc_enable);
858+
mce_wrmsrl(MSR_IA32_MCx_STATUS(1), 0);
859+
860+
instrumentation_begin();
861+
pr_err_once("Erratum detected, disable fast string copy instructions.\n");
862+
instrumentation_end();
863+
864+
return true;
865+
}
866+
867+
return false;
868+
}
869+
817870
/*
818871
* Do a quick check if any of the events requires a panic.
819872
* This decides if we keep the events around or clear them.
@@ -1383,6 +1436,9 @@ noinstr void do_machine_check(struct pt_regs *regs)
13831436
else if (unlikely(!mca_cfg.initialized))
13841437
return unexpected_machine_check(regs);
13851438

1439+
if (mce_flags.skx_repmov_quirk && quirk_skylake_repmov())
1440+
goto clear;
1441+
13861442
/*
13871443
* Establish sequential order between the CPUs entering the machine
13881444
* check handler.
@@ -1525,6 +1581,7 @@ noinstr void do_machine_check(struct pt_regs *regs)
15251581
out:
15261582
instrumentation_end();
15271583

1584+
clear:
15281585
mce_wrmsrl(MSR_IA32_MCG_STATUS, 0);
15291586
}
15301587
EXPORT_SYMBOL_GPL(do_machine_check);
@@ -1838,6 +1895,13 @@ static int __mcheck_cpu_apply_quirks(struct cpuinfo_x86 *c)
18381895

18391896
if (c->x86 == 6 && c->x86_model == 45)
18401897
mce_flags.snb_ifu_quirk = 1;
1898+
1899+
/*
1900+
* Skylake, Cascacde Lake and Cooper Lake require a quirk on
1901+
* rep movs.
1902+
*/
1903+
if (c->x86 == 6 && c->x86_model == INTEL_FAM6_SKYLAKE_X)
1904+
mce_flags.skx_repmov_quirk = 1;
18411905
}
18421906

18431907
if (c->x86_vendor == X86_VENDOR_ZHAOXIN) {

arch/x86/kernel/cpu/mce/internal.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,10 @@ struct mce_vendor_flags {
170170
/* SandyBridge IFU quirk */
171171
snb_ifu_quirk : 1,
172172

173-
__reserved_0 : 57;
173+
/* Skylake, Cascade Lake, Cooper Lake REP;MOVS* quirk */
174+
skx_repmov_quirk : 1,
175+
176+
__reserved_0 : 56;
174177
};
175178

176179
extern struct mce_vendor_flags mce_flags;

0 commit comments

Comments
 (0)