Coverage Report

Created: 2017-10-25 09:10

/root/src/xen/xen/drivers/acpi/apei/apei-base.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * apei-base.c - ACPI Platform Error Interface (APEI) supporting
3
 * infrastructure
4
 *
5
 * APEI allows to report errors (for example from the chipset) to the
6
 * the operating system. This improves NMI handling especially. In
7
 * addition it supports error serialization and error injection.
8
 *
9
 * For more information about APEI, please refer to ACPI Specification
10
 * version 4.0, chapter 17.
11
 *
12
 * This file has Common functions used by more than one APEI table,
13
 * including framework of interpreter for ERST and EINJ; resource
14
 * management for APEI registers.
15
 *
16
 * This feature is ported from linux acpi tree
17
 * Copyright (C) 2009, Intel Corp.
18
 *  Author: Huang Ying <ying.huang@intel.com>
19
 *  Ported by: Liu, Jinsong <jinsong.liu@intel.com>
20
 *
21
 * This program is free software; you can redistribute it and/or
22
 * modify it under the terms of the GNU General Public License version
23
 * 2 as published by the Free Software Foundation.
24
 *
25
 * This program is distributed in the hope that it will be useful,
26
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
28
 * GNU General Public License for more details.
29
 *
30
 * You should have received a copy of the GNU General Public License
31
 * along with this program; If not, see <http://www.gnu.org/licenses/>.
32
 */
33
#include <xen/kernel.h>
34
#include <xen/errno.h>
35
#include <xen/delay.h>
36
#include <xen/string.h>
37
#include <xen/types.h>
38
#include <xen/spinlock.h>
39
#include <xen/init.h>
40
#include <xen/cper.h>
41
#include <asm/io.h>
42
#include <acpi/acpi.h>
43
#include <acpi/apei.h>
44
45
#include "apei-internal.h"
46
47
/*
48
 * APEI ERST (Error Record Serialization Table) and EINJ (Error
49
 * INJection) interpreter framework.
50
 */
51
52
0
#define APEI_EXEC_PRESERVE_REGISTER 0x1
53
54
int apei_exec_ctx_init(struct apei_exec_context *ctx,
55
      struct apei_exec_ins_type *ins_table,
56
      u32 instructions,
57
      struct acpi_whea_header *action_table,
58
      u32 entries)
59
2
{
60
2
  if (!ctx)
61
0
    return -EINVAL;
62
2
63
2
  ctx->ins_table = ins_table;
64
2
  ctx->instructions = instructions;
65
2
  ctx->action_table = action_table;
66
2
  ctx->entries = entries;
67
2
  return 0;
68
2
}
69
70
int __apei_exec_read_register(struct acpi_whea_header *entry, u64 *val)
71
3
{
72
3
  int rc;
73
3
74
3
  rc = apei_read(val, &entry->register_region);
75
3
  if (rc)
76
0
    return rc;
77
3
  *val >>= entry->register_region.bit_offset;
78
3
  *val &= entry->mask;
79
3
80
3
  return 0;
81
3
}
82
83
int apei_exec_read_register(struct apei_exec_context *ctx,
84
          struct acpi_whea_header *entry)
85
3
{
86
3
  int rc;
87
3
  u64 val = 0;
88
3
89
3
  rc = __apei_exec_read_register(entry, &val);
90
3
  if (rc)
91
0
    return rc;
92
3
  ctx->value = val;
93
3
94
3
  return 0;
95
3
}
96
97
int apei_exec_read_register_value(struct apei_exec_context *ctx,
98
          struct acpi_whea_header *entry)
99
0
{
100
0
  int rc;
101
0
102
0
  rc = apei_exec_read_register(ctx, entry);
103
0
  if (rc)
104
0
    return rc;
105
0
  ctx->value = (ctx->value == entry->value);
106
0
107
0
  return 0;
108
0
}
109
110
int __apei_exec_write_register(struct acpi_whea_header *entry, u64 val)
111
0
{
112
0
  int rc;
113
0
114
0
  val &= entry->mask;
115
0
  val <<= entry->register_region.bit_offset;
116
0
  if (entry->flags & APEI_EXEC_PRESERVE_REGISTER) {
117
0
    u64 valr = 0;
118
0
    rc = apei_read(&valr, &entry->register_region);
119
0
    if (rc)
120
0
      return rc;
121
0
    valr &= ~(entry->mask << entry->register_region.bit_offset);
122
0
    val |= valr;
123
0
  }
124
0
  rc = apei_write(val, &entry->register_region);
125
0
126
0
  return rc;
127
0
}
128
129
int apei_exec_write_register(struct apei_exec_context *ctx,
130
           struct acpi_whea_header *entry)
131
0
{
132
0
  return __apei_exec_write_register(entry, ctx->value);
133
0
}
134
135
int apei_exec_write_register_value(struct apei_exec_context *ctx,
136
           struct acpi_whea_header *entry)
137
0
{
138
0
  int rc;
139
0
140
0
  ctx->value = entry->value;
141
0
  rc = apei_exec_write_register(ctx, entry);
142
0
143
0
  return rc;
144
0
}
145
146
int apei_exec_noop(struct apei_exec_context *ctx,
147
       struct acpi_whea_header *entry)
148
0
{
149
0
  return 0;
150
0
}
151
152
/*
153
 * Interpret the specified action. Go through whole action table,
154
 * execute all instructions belong to the action.
155
 */
156
int __apei_exec_run(struct apei_exec_context *ctx, u8 action,
157
        bool_t optional)
158
3
{
159
3
  int rc = -ENOENT;
160
3
  u32 i, ip;
161
3
  struct acpi_whea_header *entry;
162
3
  apei_exec_ins_func_t run;
163
3
164
3
  ctx->ip = 0;
165
3
166
3
  /*
167
3
   * "ip" is the instruction pointer of current instruction,
168
3
   * "ctx->ip" specifies the next instruction to executed,
169
3
   * instruction "run" function may change the "ctx->ip" to
170
3
   * implement "goto" semantics.
171
3
   */
172
3
rewind:
173
3
  ip = 0;
174
51
  for (i = 0; i < ctx->entries; i++) {
175
48
    entry = &ctx->action_table[i];
176
48
    if (entry->action != action)
177
45
      continue;
178
3
    if (ip == ctx->ip) {
179
3
      if (entry->instruction >= ctx->instructions ||
180
3
          !ctx->ins_table[entry->instruction].run) {
181
0
        printk(KERN_WARNING
182
0
        "Invalid action table, unknown instruction "
183
0
        "type: %d\n", entry->instruction);
184
0
        return -EINVAL;
185
0
      }
186
3
      run = ctx->ins_table[entry->instruction].run;
187
3
      rc = run(ctx, entry);
188
3
      if (rc < 0)
189
0
        return rc;
190
3
      else if (rc != APEI_EXEC_SET_IP)
191
3
        ctx->ip++;
192
3
    }
193
3
    ip++;
194
3
    if (ctx->ip < ip)
195
0
      goto rewind;
196
3
  }
197
3
198
3
  return !optional && rc < 0 ? rc : 0;
199
3
}
200
201
typedef int (*apei_exec_entry_func_t)(struct apei_exec_context *ctx,
202
              struct acpi_whea_header *entry,
203
              void *data);
204
205
static int __init apei_exec_for_each_entry(struct apei_exec_context *ctx,
206
             apei_exec_entry_func_t func,
207
             void *data,
208
             int *end)
209
1
{
210
1
  u8 ins;
211
1
  int i, rc;
212
1
  struct acpi_whea_header *entry;
213
1
  struct apei_exec_ins_type *ins_table = ctx->ins_table;
214
1
215
17
  for (i = 0; i < ctx->entries; i++) {
216
16
    entry = ctx->action_table + i;
217
16
    ins = entry->instruction;
218
16
    if (end)
219
16
      *end = i;
220
16
    if (ins >= ctx->instructions || !ins_table[ins].run) {
221
0
      printk(KERN_WARNING "Invalid action table, "
222
0
      "unknown instruction type: %d\n", ins);
223
0
      return -EINVAL;
224
0
    }
225
16
    rc = func(ctx, entry, data);
226
16
    if (rc)
227
0
      return rc;
228
16
  }
229
1
230
1
  return 0;
231
1
}
232
233
static int __init pre_map_gar_callback(struct apei_exec_context *ctx,
234
               struct acpi_whea_header *entry,
235
               void *data)
236
16
{
237
16
  u8 ins = entry->instruction;
238
16
239
16
  if (ctx->ins_table[ins].flags & APEI_EXEC_INS_ACCESS_REGISTER)
240
15
    return apei_pre_map_gar(&entry->register_region);
241
16
242
1
  return 0;
243
16
}
244
245
/* Pre-map all GARs in action table. */
246
int __init apei_exec_pre_map_gars(struct apei_exec_context *ctx)
247
1
{
248
1
  int rc, end;
249
1
250
1
  rc = apei_exec_for_each_entry(ctx, pre_map_gar_callback,
251
1
              NULL, &end);
252
1
  if (rc) {
253
0
    struct apei_exec_context ctx_unmap;
254
0
    memcpy(&ctx_unmap, ctx, sizeof(*ctx));
255
0
    ctx_unmap.entries = end;
256
0
    apei_exec_post_unmap_gars(&ctx_unmap);
257
0
  }
258
1
259
1
  return rc;
260
1
}
261
262
static int __init post_unmap_gar_callback(struct apei_exec_context *ctx,
263
            struct acpi_whea_header *entry,
264
            void *data)
265
0
{
266
0
  u8 ins = entry->instruction;
267
0
268
0
  if (ctx->ins_table[ins].flags & APEI_EXEC_INS_ACCESS_REGISTER)
269
0
    apei_post_unmap_gar(&entry->register_region);
270
0
271
0
  return 0;
272
0
}
273
274
/* Post-unmap all GAR in action table. */
275
int __init apei_exec_post_unmap_gars(struct apei_exec_context *ctx)
276
0
{
277
0
  return apei_exec_for_each_entry(ctx, post_unmap_gar_callback,
278
0
          NULL, NULL);
279
0
}