cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

severity.c (12406B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * MCE grading rules.
      4 * Copyright 2008, 2009 Intel Corporation.
      5 *
      6 * Author: Andi Kleen
      7 */
      8#include <linux/kernel.h>
      9#include <linux/seq_file.h>
     10#include <linux/init.h>
     11#include <linux/debugfs.h>
     12#include <linux/uaccess.h>
     13
     14#include <asm/mce.h>
     15#include <asm/intel-family.h>
     16#include <asm/traps.h>
     17#include <asm/insn.h>
     18#include <asm/insn-eval.h>
     19
     20#include "internal.h"
     21
     22/*
     23 * Grade an mce by severity. In general the most severe ones are processed
     24 * first. Since there are quite a lot of combinations test the bits in a
     25 * table-driven way. The rules are simply processed in order, first
     26 * match wins.
     27 *
     28 * Note this is only used for machine check exceptions, the corrected
     29 * errors use much simpler rules. The exceptions still check for the corrected
     30 * errors, but only to leave them alone for the CMCI handler (except for
     31 * panic situations)
     32 */
     33
     34enum context { IN_KERNEL = 1, IN_USER = 2, IN_KERNEL_RECOV = 3 };
     35enum ser { SER_REQUIRED = 1, NO_SER = 2 };
     36enum exception { EXCP_CONTEXT = 1, NO_EXCP = 2 };
     37
     38static struct severity {
     39	u64 mask;
     40	u64 result;
     41	unsigned char sev;
     42	unsigned char mcgmask;
     43	unsigned char mcgres;
     44	unsigned char ser;
     45	unsigned char context;
     46	unsigned char excp;
     47	unsigned char covered;
     48	unsigned char cpu_model;
     49	unsigned char cpu_minstepping;
     50	unsigned char bank_lo, bank_hi;
     51	char *msg;
     52} severities[] = {
     53#define MCESEV(s, m, c...) { .sev = MCE_ ## s ## _SEVERITY, .msg = m, ## c }
     54#define BANK_RANGE(l, h) .bank_lo = l, .bank_hi = h
     55#define MODEL_STEPPING(m, s) .cpu_model = m, .cpu_minstepping = s
     56#define  KERNEL		.context = IN_KERNEL
     57#define  USER		.context = IN_USER
     58#define  KERNEL_RECOV	.context = IN_KERNEL_RECOV
     59#define  SER		.ser = SER_REQUIRED
     60#define  NOSER		.ser = NO_SER
     61#define  EXCP		.excp = EXCP_CONTEXT
     62#define  NOEXCP		.excp = NO_EXCP
     63#define  BITCLR(x)	.mask = x, .result = 0
     64#define  BITSET(x)	.mask = x, .result = x
     65#define  MCGMASK(x, y)	.mcgmask = x, .mcgres = y
     66#define  MASK(x, y)	.mask = x, .result = y
     67#define MCI_UC_S (MCI_STATUS_UC|MCI_STATUS_S)
     68#define MCI_UC_AR (MCI_STATUS_UC|MCI_STATUS_AR)
     69#define MCI_UC_SAR (MCI_STATUS_UC|MCI_STATUS_S|MCI_STATUS_AR)
     70#define	MCI_ADDR (MCI_STATUS_ADDRV|MCI_STATUS_MISCV)
     71
     72	MCESEV(
     73		NO, "Invalid",
     74		BITCLR(MCI_STATUS_VAL)
     75		),
     76	MCESEV(
     77		NO, "Not enabled",
     78		EXCP, BITCLR(MCI_STATUS_EN)
     79		),
     80	MCESEV(
     81		PANIC, "Processor context corrupt",
     82		BITSET(MCI_STATUS_PCC)
     83		),
     84	/* When MCIP is not set something is very confused */
     85	MCESEV(
     86		PANIC, "MCIP not set in MCA handler",
     87		EXCP, MCGMASK(MCG_STATUS_MCIP, 0)
     88		),
     89	/* Neither return not error IP -- no chance to recover -> PANIC */
     90	MCESEV(
     91		PANIC, "Neither restart nor error IP",
     92		EXCP, MCGMASK(MCG_STATUS_RIPV|MCG_STATUS_EIPV, 0)
     93		),
     94	MCESEV(
     95		PANIC, "In kernel and no restart IP",
     96		EXCP, KERNEL, MCGMASK(MCG_STATUS_RIPV, 0)
     97		),
     98	MCESEV(
     99		PANIC, "In kernel and no restart IP",
    100		EXCP, KERNEL_RECOV, MCGMASK(MCG_STATUS_RIPV, 0)
    101		),
    102	MCESEV(
    103		KEEP, "Corrected error",
    104		NOSER, BITCLR(MCI_STATUS_UC)
    105		),
    106	/*
    107	 * known AO MCACODs reported via MCE or CMC:
    108	 *
    109	 * SRAO could be signaled either via a machine check exception or
    110	 * CMCI with the corresponding bit S 1 or 0. So we don't need to
    111	 * check bit S for SRAO.
    112	 */
    113	MCESEV(
    114		AO, "Action optional: memory scrubbing error",
    115		SER, MASK(MCI_UC_AR|MCACOD_SCRUBMSK, MCI_STATUS_UC|MCACOD_SCRUB)
    116		),
    117	MCESEV(
    118		AO, "Action optional: last level cache writeback error",
    119		SER, MASK(MCI_UC_AR|MCACOD, MCI_STATUS_UC|MCACOD_L3WB)
    120		),
    121	/*
    122	 * Quirk for Skylake/Cascade Lake. Patrol scrubber may be configured
    123	 * to report uncorrected errors using CMCI with a special signature.
    124	 * UC=0, MSCOD=0x0010, MCACOD=binary(000X 0000 1100 XXXX) reported
    125	 * in one of the memory controller banks.
    126	 * Set severity to "AO" for same action as normal patrol scrub error.
    127	 */
    128	MCESEV(
    129		AO, "Uncorrected Patrol Scrub Error",
    130		SER, MASK(MCI_STATUS_UC|MCI_ADDR|0xffffeff0, MCI_ADDR|0x001000c0),
    131		MODEL_STEPPING(INTEL_FAM6_SKYLAKE_X, 4), BANK_RANGE(13, 18)
    132	),
    133
    134	/* ignore OVER for UCNA */
    135	MCESEV(
    136		UCNA, "Uncorrected no action required",
    137		SER, MASK(MCI_UC_SAR, MCI_STATUS_UC)
    138		),
    139	MCESEV(
    140		PANIC, "Illegal combination (UCNA with AR=1)",
    141		SER,
    142		MASK(MCI_STATUS_OVER|MCI_UC_SAR, MCI_STATUS_UC|MCI_STATUS_AR)
    143		),
    144	MCESEV(
    145		KEEP, "Non signaled machine check",
    146		SER, BITCLR(MCI_STATUS_S)
    147		),
    148
    149	MCESEV(
    150		PANIC, "Action required with lost events",
    151		SER, BITSET(MCI_STATUS_OVER|MCI_UC_SAR)
    152		),
    153
    154	/* known AR MCACODs: */
    155#ifdef	CONFIG_MEMORY_FAILURE
    156	MCESEV(
    157		KEEP, "Action required but unaffected thread is continuable",
    158		SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR|MCI_ADDR, MCI_UC_SAR|MCI_ADDR),
    159		MCGMASK(MCG_STATUS_RIPV|MCG_STATUS_EIPV, MCG_STATUS_RIPV)
    160		),
    161	MCESEV(
    162		AR, "Action required: data load in error recoverable area of kernel",
    163		SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR|MCI_ADDR|MCACOD, MCI_UC_SAR|MCI_ADDR|MCACOD_DATA),
    164		KERNEL_RECOV
    165		),
    166	MCESEV(
    167		AR, "Action required: data load error in a user process",
    168		SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR|MCI_ADDR|MCACOD, MCI_UC_SAR|MCI_ADDR|MCACOD_DATA),
    169		USER
    170		),
    171	MCESEV(
    172		AR, "Action required: instruction fetch error in a user process",
    173		SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR|MCI_ADDR|MCACOD, MCI_UC_SAR|MCI_ADDR|MCACOD_INSTR),
    174		USER
    175		),
    176	MCESEV(
    177		PANIC, "Data load in unrecoverable area of kernel",
    178		SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR|MCI_ADDR|MCACOD, MCI_UC_SAR|MCI_ADDR|MCACOD_DATA),
    179		KERNEL
    180		),
    181	MCESEV(
    182		PANIC, "Instruction fetch error in kernel",
    183		SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR|MCI_ADDR|MCACOD, MCI_UC_SAR|MCI_ADDR|MCACOD_INSTR),
    184		KERNEL
    185		),
    186#endif
    187	MCESEV(
    188		PANIC, "Action required: unknown MCACOD",
    189		SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR, MCI_UC_SAR)
    190		),
    191
    192	MCESEV(
    193		SOME, "Action optional: unknown MCACOD",
    194		SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR, MCI_UC_S)
    195		),
    196	MCESEV(
    197		SOME, "Action optional with lost events",
    198		SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR, MCI_STATUS_OVER|MCI_UC_S)
    199		),
    200
    201	MCESEV(
    202		PANIC, "Overflowed uncorrected",
    203		BITSET(MCI_STATUS_OVER|MCI_STATUS_UC)
    204		),
    205	MCESEV(
    206		UC, "Uncorrected",
    207		BITSET(MCI_STATUS_UC)
    208		),
    209	MCESEV(
    210		SOME, "No match",
    211		BITSET(0)
    212		)	/* always matches. keep at end */
    213};
    214
    215#define mc_recoverable(mcg) (((mcg) & (MCG_STATUS_RIPV|MCG_STATUS_EIPV)) == \
    216				(MCG_STATUS_RIPV|MCG_STATUS_EIPV))
    217
    218static bool is_copy_from_user(struct pt_regs *regs)
    219{
    220	u8 insn_buf[MAX_INSN_SIZE];
    221	unsigned long addr;
    222	struct insn insn;
    223	int ret;
    224
    225	if (!regs)
    226		return false;
    227
    228	if (copy_from_kernel_nofault(insn_buf, (void *)regs->ip, MAX_INSN_SIZE))
    229		return false;
    230
    231	ret = insn_decode_kernel(&insn, insn_buf);
    232	if (ret < 0)
    233		return false;
    234
    235	switch (insn.opcode.value) {
    236	/* MOV mem,reg */
    237	case 0x8A: case 0x8B:
    238	/* MOVZ mem,reg */
    239	case 0xB60F: case 0xB70F:
    240		addr = (unsigned long)insn_get_addr_ref(&insn, regs);
    241		break;
    242	/* REP MOVS */
    243	case 0xA4: case 0xA5:
    244		addr = regs->si;
    245		break;
    246	default:
    247		return false;
    248	}
    249
    250	if (fault_in_kernel_space(addr))
    251		return false;
    252
    253	current->mce_vaddr = (void __user *)addr;
    254
    255	return true;
    256}
    257
    258/*
    259 * If mcgstatus indicated that ip/cs on the stack were
    260 * no good, then "m->cs" will be zero and we will have
    261 * to assume the worst case (IN_KERNEL) as we actually
    262 * have no idea what we were executing when the machine
    263 * check hit.
    264 * If we do have a good "m->cs" (or a faked one in the
    265 * case we were executing in VM86 mode) we can use it to
    266 * distinguish an exception taken in user from from one
    267 * taken in the kernel.
    268 */
    269static noinstr int error_context(struct mce *m, struct pt_regs *regs)
    270{
    271	int fixup_type;
    272	bool copy_user;
    273
    274	if ((m->cs & 3) == 3)
    275		return IN_USER;
    276
    277	if (!mc_recoverable(m->mcgstatus))
    278		return IN_KERNEL;
    279
    280	/* Allow instrumentation around external facilities usage. */
    281	instrumentation_begin();
    282	fixup_type = ex_get_fixup_type(m->ip);
    283	copy_user  = is_copy_from_user(regs);
    284	instrumentation_end();
    285
    286	switch (fixup_type) {
    287	case EX_TYPE_UACCESS:
    288	case EX_TYPE_COPY:
    289		if (!copy_user)
    290			return IN_KERNEL;
    291		m->kflags |= MCE_IN_KERNEL_COPYIN;
    292		fallthrough;
    293
    294	case EX_TYPE_FAULT_MCE_SAFE:
    295	case EX_TYPE_DEFAULT_MCE_SAFE:
    296		m->kflags |= MCE_IN_KERNEL_RECOV;
    297		return IN_KERNEL_RECOV;
    298
    299	default:
    300		return IN_KERNEL;
    301	}
    302}
    303
    304/* See AMD PPR(s) section Machine Check Error Handling. */
    305static noinstr int mce_severity_amd(struct mce *m, struct pt_regs *regs, char **msg, bool is_excp)
    306{
    307	char *panic_msg = NULL;
    308	int ret;
    309
    310	/*
    311	 * Default return value: Action required, the error must be handled
    312	 * immediately.
    313	 */
    314	ret = MCE_AR_SEVERITY;
    315
    316	/* Processor Context Corrupt, no need to fumble too much, die! */
    317	if (m->status & MCI_STATUS_PCC) {
    318		panic_msg = "Processor Context Corrupt";
    319		ret = MCE_PANIC_SEVERITY;
    320		goto out;
    321	}
    322
    323	if (m->status & MCI_STATUS_DEFERRED) {
    324		ret = MCE_DEFERRED_SEVERITY;
    325		goto out;
    326	}
    327
    328	/*
    329	 * If the UC bit is not set, the system either corrected or deferred
    330	 * the error. No action will be required after logging the error.
    331	 */
    332	if (!(m->status & MCI_STATUS_UC)) {
    333		ret = MCE_KEEP_SEVERITY;
    334		goto out;
    335	}
    336
    337	/*
    338	 * On MCA overflow, without the MCA overflow recovery feature the
    339	 * system will not be able to recover, panic.
    340	 */
    341	if ((m->status & MCI_STATUS_OVER) && !mce_flags.overflow_recov) {
    342		panic_msg = "Overflowed uncorrected error without MCA Overflow Recovery";
    343		ret = MCE_PANIC_SEVERITY;
    344		goto out;
    345	}
    346
    347	if (!mce_flags.succor) {
    348		panic_msg = "Uncorrected error without MCA Recovery";
    349		ret = MCE_PANIC_SEVERITY;
    350		goto out;
    351	}
    352
    353	if (error_context(m, regs) == IN_KERNEL) {
    354		panic_msg = "Uncorrected unrecoverable error in kernel context";
    355		ret = MCE_PANIC_SEVERITY;
    356	}
    357
    358out:
    359	if (msg && panic_msg)
    360		*msg = panic_msg;
    361
    362	return ret;
    363}
    364
    365static noinstr int mce_severity_intel(struct mce *m, struct pt_regs *regs, char **msg, bool is_excp)
    366{
    367	enum exception excp = (is_excp ? EXCP_CONTEXT : NO_EXCP);
    368	enum context ctx = error_context(m, regs);
    369	struct severity *s;
    370
    371	for (s = severities;; s++) {
    372		if ((m->status & s->mask) != s->result)
    373			continue;
    374		if ((m->mcgstatus & s->mcgmask) != s->mcgres)
    375			continue;
    376		if (s->ser == SER_REQUIRED && !mca_cfg.ser)
    377			continue;
    378		if (s->ser == NO_SER && mca_cfg.ser)
    379			continue;
    380		if (s->context && ctx != s->context)
    381			continue;
    382		if (s->excp && excp != s->excp)
    383			continue;
    384		if (s->cpu_model && boot_cpu_data.x86_model != s->cpu_model)
    385			continue;
    386		if (s->cpu_minstepping && boot_cpu_data.x86_stepping < s->cpu_minstepping)
    387			continue;
    388		if (s->bank_lo && (m->bank < s->bank_lo || m->bank > s->bank_hi))
    389			continue;
    390		if (msg)
    391			*msg = s->msg;
    392		s->covered = 1;
    393
    394		if (s->sev >= MCE_UC_SEVERITY && ctx == IN_KERNEL)
    395			return MCE_PANIC_SEVERITY;
    396
    397		return s->sev;
    398	}
    399}
    400
    401int noinstr mce_severity(struct mce *m, struct pt_regs *regs, char **msg, bool is_excp)
    402{
    403	if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD ||
    404	    boot_cpu_data.x86_vendor == X86_VENDOR_HYGON)
    405		return mce_severity_amd(m, regs, msg, is_excp);
    406	else
    407		return mce_severity_intel(m, regs, msg, is_excp);
    408}
    409
    410#ifdef CONFIG_DEBUG_FS
    411static void *s_start(struct seq_file *f, loff_t *pos)
    412{
    413	if (*pos >= ARRAY_SIZE(severities))
    414		return NULL;
    415	return &severities[*pos];
    416}
    417
    418static void *s_next(struct seq_file *f, void *data, loff_t *pos)
    419{
    420	if (++(*pos) >= ARRAY_SIZE(severities))
    421		return NULL;
    422	return &severities[*pos];
    423}
    424
    425static void s_stop(struct seq_file *f, void *data)
    426{
    427}
    428
    429static int s_show(struct seq_file *f, void *data)
    430{
    431	struct severity *ser = data;
    432	seq_printf(f, "%d\t%s\n", ser->covered, ser->msg);
    433	return 0;
    434}
    435
    436static const struct seq_operations severities_seq_ops = {
    437	.start	= s_start,
    438	.next	= s_next,
    439	.stop	= s_stop,
    440	.show	= s_show,
    441};
    442
    443static int severities_coverage_open(struct inode *inode, struct file *file)
    444{
    445	return seq_open(file, &severities_seq_ops);
    446}
    447
    448static ssize_t severities_coverage_write(struct file *file,
    449					 const char __user *ubuf,
    450					 size_t count, loff_t *ppos)
    451{
    452	int i;
    453	for (i = 0; i < ARRAY_SIZE(severities); i++)
    454		severities[i].covered = 0;
    455	return count;
    456}
    457
    458static const struct file_operations severities_coverage_fops = {
    459	.open		= severities_coverage_open,
    460	.release	= seq_release,
    461	.read		= seq_read,
    462	.write		= severities_coverage_write,
    463	.llseek		= seq_lseek,
    464};
    465
    466static int __init severities_debugfs_init(void)
    467{
    468	struct dentry *dmce;
    469
    470	dmce = mce_get_debugfs_dir();
    471
    472	debugfs_create_file("severities-coverage", 0444, dmce, NULL,
    473			    &severities_coverage_fops);
    474	return 0;
    475}
    476late_initcall(severities_debugfs_init);
    477#endif /* CONFIG_DEBUG_FS */