Coverage Report

Created: 2017-10-25 09:10

/root/src/xen/xen/arch/x86/cpu/mcheck/mce-apei.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Bridge between MCE and APEI
3
 *
4
 * On some machine, corrected memory errors are reported via APEI
5
 * generic hardware error source (GHES) instead of corrected Machine
6
 * Check. These corrected memory errors can be reported to user space
7
 * through /dev/mcelog via faking a corrected Machine Check, so that
8
 * the error memory page can be offlined by /sbin/mcelog if the error
9
 * count for one page is beyond the threshold.
10
 *
11
 * For fatal MCE, save MCE record into persistent storage via ERST, so
12
 * that the MCE record can be logged after reboot via ERST.
13
 *
14
 * Copyright 2010 Intel Corp.
15
 *   Author: Huang Ying <ying.huang@intel.com>
16
 *   Ported by: Liu, Jinsong <jinsong.liu@intel.com>
17
 *
18
 * This program is free software; you can redistribute it and/or
19
 * modify it under the terms of the GNU General Public License version
20
 * 2 as published by the Free Software Foundation.
21
 *
22
 * This program is distributed in the hope that it will be useful,
23
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25
 * GNU General Public License for more details.
26
 *
27
 * You should have received a copy of the GNU General Public License
28
 * along with this program; If not, see <http://www.gnu.org/licenses/>.
29
 */
30
31
#include <xen/kernel.h>
32
#include <xen/cper.h>
33
#include <xen/errno.h>
34
#include <acpi/acpi.h>
35
#include <acpi/apei.h>
36
37
#include "mce.h"
38
39
#define CPER_CREATOR_MCE            \
40
0
  UUID_LE(0x75a574e3, 0x5052, 0x4b29, 0x8a, 0x8e, 0xbe, 0x2c,  \
41
0
    0x64, 0x90, 0xb8, 0x9d)
42
#define CPER_SECTION_TYPE_MCE           \
43
0
  UUID_LE(0xfe08ffbe, 0x95e4, 0x4be7, 0xbc, 0x73, 0x40, 0x96,  \
44
0
    0x04, 0x4a, 0x38, 0xfc)
45
46
/*
47
 * CPER specification (in UEFI specification 2.3 appendix N) requires
48
 * byte-packed.
49
 */
50
struct __packed cper_mce_record {
51
  struct cper_record_header hdr;
52
  struct cper_section_descriptor sec_hdr;
53
  struct mce mce;
54
};
55
56
int apei_write_mce(struct mce *m)
57
0
{
58
0
  struct cper_mce_record rcd;
59
0
60
0
  if (!m)
61
0
    return -EINVAL;
62
0
63
0
  memset(&rcd, 0, sizeof(rcd));
64
0
  memcpy(rcd.hdr.signature, CPER_SIG_RECORD, CPER_SIG_SIZE);
65
0
  rcd.hdr.revision = CPER_RECORD_REV;
66
0
  rcd.hdr.signature_end = CPER_SIG_END;
67
0
  rcd.hdr.section_count = 1;
68
0
  rcd.hdr.error_severity = CPER_SER_FATAL;
69
0
  /* timestamp, platform_id, partition_id are all invalid */
70
0
  rcd.hdr.validation_bits = 0;
71
0
  rcd.hdr.record_length = sizeof(rcd);
72
0
  rcd.hdr.creator_id = CPER_CREATOR_MCE;
73
0
  rcd.hdr.notification_type = CPER_NOTIFY_MCE;
74
0
  rcd.hdr.record_id = cper_next_record_id();
75
0
  rcd.hdr.flags = CPER_HW_ERROR_FLAGS_PREVERR;
76
0
77
0
  rcd.sec_hdr.section_offset = (void *)&rcd.mce - (void *)&rcd;
78
0
  rcd.sec_hdr.section_length = sizeof(rcd.mce);
79
0
  rcd.sec_hdr.revision = CPER_SEC_REV;
80
0
  /* fru_id and fru_text is invalid */
81
0
  rcd.sec_hdr.validation_bits = 0;
82
0
  rcd.sec_hdr.flags = CPER_SEC_PRIMARY;
83
0
  rcd.sec_hdr.section_type = CPER_SECTION_TYPE_MCE;
84
0
  rcd.sec_hdr.section_severity = CPER_SER_FATAL;
85
0
86
0
  memcpy(&rcd.mce, m, sizeof(*m));
87
0
88
0
  return erst_write(&rcd.hdr);
89
0
}
90
91
#ifndef NDEBUG /* currently dead code */
92
93
ssize_t apei_read_mce(struct mce *m, u64 *record_id)
94
0
{
95
0
  struct cper_mce_record rcd;
96
0
  ssize_t len;
97
0
98
0
  if (!m || !record_id)
99
0
    return -EINVAL;
100
0
101
0
  len = erst_read_next(&rcd.hdr, sizeof(rcd));
102
0
  if (len <= 0)
103
0
    return len;
104
0
  /* Can not skip other records in storage via ERST unless clear them */
105
0
  else if (len != sizeof(rcd) ||
106
0
     uuid_le_cmp(rcd.hdr.creator_id, CPER_CREATOR_MCE)) {
107
0
    printk(KERN_WARNING
108
0
      "MCE-APEI: Can not skip the unknown record in ERST");
109
0
    return -EIO;
110
0
  }
111
0
112
0
  memcpy(m, &rcd.mce, sizeof(*m));
113
0
  *record_id = rcd.hdr.record_id;
114
0
115
0
  return sizeof(*m);
116
0
}
117
118
/* Check whether there is record in ERST */
119
bool apei_check_mce(void)
120
0
{
121
0
  return erst_get_record_count() > 0;
122
0
}
123
124
int apei_clear_mce(u64 record_id)
125
0
{
126
0
  return erst_clear(record_id);
127
0
}
128
129
#endif /* currently dead code */