|
@@ -14,6 +14,7 @@
|
|
#include <linux/init.h>
|
|
#include <linux/init.h>
|
|
#include <linux/debugfs.h>
|
|
#include <linux/debugfs.h>
|
|
#include <asm/mce.h>
|
|
#include <asm/mce.h>
|
|
|
|
+#include <asm/uaccess.h>
|
|
|
|
|
|
#include "mce-internal.h"
|
|
#include "mce-internal.h"
|
|
|
|
|
|
@@ -29,7 +30,7 @@
|
|
* panic situations)
|
|
* panic situations)
|
|
*/
|
|
*/
|
|
|
|
|
|
-enum context { IN_KERNEL = 1, IN_USER = 2 };
|
|
|
|
|
|
+enum context { IN_KERNEL = 1, IN_USER = 2, IN_KERNEL_RECOV = 3 };
|
|
enum ser { SER_REQUIRED = 1, NO_SER = 2 };
|
|
enum ser { SER_REQUIRED = 1, NO_SER = 2 };
|
|
enum exception { EXCP_CONTEXT = 1, NO_EXCP = 2 };
|
|
enum exception { EXCP_CONTEXT = 1, NO_EXCP = 2 };
|
|
|
|
|
|
@@ -48,6 +49,7 @@ static struct severity {
|
|
#define MCESEV(s, m, c...) { .sev = MCE_ ## s ## _SEVERITY, .msg = m, ## c }
|
|
#define MCESEV(s, m, c...) { .sev = MCE_ ## s ## _SEVERITY, .msg = m, ## c }
|
|
#define KERNEL .context = IN_KERNEL
|
|
#define KERNEL .context = IN_KERNEL
|
|
#define USER .context = IN_USER
|
|
#define USER .context = IN_USER
|
|
|
|
+#define KERNEL_RECOV .context = IN_KERNEL_RECOV
|
|
#define SER .ser = SER_REQUIRED
|
|
#define SER .ser = SER_REQUIRED
|
|
#define NOSER .ser = NO_SER
|
|
#define NOSER .ser = NO_SER
|
|
#define EXCP .excp = EXCP_CONTEXT
|
|
#define EXCP .excp = EXCP_CONTEXT
|
|
@@ -86,6 +88,10 @@ static struct severity {
|
|
PANIC, "In kernel and no restart IP",
|
|
PANIC, "In kernel and no restart IP",
|
|
EXCP, KERNEL, MCGMASK(MCG_STATUS_RIPV, 0)
|
|
EXCP, KERNEL, MCGMASK(MCG_STATUS_RIPV, 0)
|
|
),
|
|
),
|
|
|
|
+ MCESEV(
|
|
|
|
+ PANIC, "In kernel and no restart IP",
|
|
|
|
+ EXCP, KERNEL_RECOV, MCGMASK(MCG_STATUS_RIPV, 0)
|
|
|
|
+ ),
|
|
MCESEV(
|
|
MCESEV(
|
|
DEFERRED, "Deferred error",
|
|
DEFERRED, "Deferred error",
|
|
NOSER, MASK(MCI_STATUS_UC|MCI_STATUS_DEFERRED|MCI_STATUS_POISON, MCI_STATUS_DEFERRED)
|
|
NOSER, MASK(MCI_STATUS_UC|MCI_STATUS_DEFERRED|MCI_STATUS_POISON, MCI_STATUS_DEFERRED)
|
|
@@ -122,6 +128,11 @@ static struct severity {
|
|
SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR|MCI_ADDR, MCI_UC_SAR|MCI_ADDR),
|
|
SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR|MCI_ADDR, MCI_UC_SAR|MCI_ADDR),
|
|
MCGMASK(MCG_STATUS_RIPV|MCG_STATUS_EIPV, MCG_STATUS_RIPV)
|
|
MCGMASK(MCG_STATUS_RIPV|MCG_STATUS_EIPV, MCG_STATUS_RIPV)
|
|
),
|
|
),
|
|
|
|
+ MCESEV(
|
|
|
|
+ AR, "Action required: data load in error recoverable area of kernel",
|
|
|
|
+ SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR|MCI_ADDR|MCACOD, MCI_UC_SAR|MCI_ADDR|MCACOD_DATA),
|
|
|
|
+ KERNEL_RECOV
|
|
|
|
+ ),
|
|
MCESEV(
|
|
MCESEV(
|
|
AR, "Action required: data load error in a user process",
|
|
AR, "Action required: data load error in a user process",
|
|
SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR|MCI_ADDR|MCACOD, MCI_UC_SAR|MCI_ADDR|MCACOD_DATA),
|
|
SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR|MCI_ADDR|MCACOD, MCI_UC_SAR|MCI_ADDR|MCACOD_DATA),
|
|
@@ -170,6 +181,9 @@ static struct severity {
|
|
) /* always matches. keep at end */
|
|
) /* always matches. keep at end */
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+#define mc_recoverable(mcg) (((mcg) & (MCG_STATUS_RIPV|MCG_STATUS_EIPV)) == \
|
|
|
|
+ (MCG_STATUS_RIPV|MCG_STATUS_EIPV))
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* If mcgstatus indicated that ip/cs on the stack were
|
|
* If mcgstatus indicated that ip/cs on the stack were
|
|
* no good, then "m->cs" will be zero and we will have
|
|
* no good, then "m->cs" will be zero and we will have
|
|
@@ -183,7 +197,11 @@ static struct severity {
|
|
*/
|
|
*/
|
|
static int error_context(struct mce *m)
|
|
static int error_context(struct mce *m)
|
|
{
|
|
{
|
|
- return ((m->cs & 3) == 3) ? IN_USER : IN_KERNEL;
|
|
|
|
|
|
+ if ((m->cs & 3) == 3)
|
|
|
|
+ return IN_USER;
|
|
|
|
+ if (mc_recoverable(m->mcgstatus) && ex_has_fault_handler(m->ip))
|
|
|
|
+ return IN_KERNEL_RECOV;
|
|
|
|
+ return IN_KERNEL;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|