Skip to content

Commit

Permalink
ACPI, APEI, UEFI Common Platform Error Record (CPER) header
Browse files Browse the repository at this point in the history
CPER stands for Common Platform Error Record, it is the hardware error
record format used to describe platform hardware error by various APEI
tables, such as ERST, BERT and HEST etc.

For more information about CPER, please refer to Appendix N of UEFI
Specification version 2.3.

This patch mainly includes the data structure difinition header file
used by other files.

Signed-off-by: Huang Ying <ying.huang@intel.com>
Signed-off-by: Andi Kleen <ak@linux.intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
  • Loading branch information
Huang Ying authored and Len Brown committed May 20, 2010
1 parent fab1c23 commit 06d65de
Show file tree
Hide file tree
Showing 4 changed files with 418 additions and 1 deletion.
2 changes: 1 addition & 1 deletion drivers/acpi/apei/Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
obj-$(CONFIG_ACPI_APEI) += apei.o
obj-$(CONFIG_ACPI_APEI_EINJ) += einj.o

apei-y := apei-base.o hest.o
apei-y := apei-base.o hest.o cper.o
19 changes: 19 additions & 0 deletions drivers/acpi/apei/apei-internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
#ifndef APEI_INTERNAL_H
#define APEI_INTERNAL_H

#include <linux/cper.h>

struct apei_exec_context;

typedef int (*apei_exec_ins_func_t)(struct apei_exec_context *ctx,
Expand Down Expand Up @@ -92,4 +94,21 @@ int apei_exec_collect_resources(struct apei_exec_context *ctx,

struct dentry;
struct dentry *apei_get_debugfs_dir(void);

#define apei_estatus_for_each_section(estatus, section) \
for (section = (struct acpi_hest_generic_data *)(estatus + 1); \
(void *)section - (void *)estatus < estatus->data_length; \
section = (void *)(section+1) + section->error_data_length)

static inline u32 apei_estatus_len(struct acpi_hest_generic_status *estatus)
{
if (estatus->raw_data_length)
return estatus->raw_data_offset + \
estatus->raw_data_length;
else
return sizeof(*estatus) + estatus->data_length;
}

int apei_estatus_check_header(const struct acpi_hest_generic_status *estatus);
int apei_estatus_check(const struct acpi_hest_generic_status *estatus);
#endif
84 changes: 84 additions & 0 deletions drivers/acpi/apei/cper.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
* UEFI Common Platform Error Record (CPER) support
*
* Copyright (C) 2010, Intel Corp.
* Author: Huang Ying <ying.huang@intel.com>
*
* CPER is the format used to describe platform hardware error by
* various APEI tables, such as ERST, BERT and HEST etc.
*
* For more information about CPER, please refer to Appendix N of UEFI
* Specification version 2.3.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/time.h>
#include <linux/cper.h>
#include <linux/acpi.h>

/*
* CPER record ID need to be unique even after reboot, because record
* ID is used as index for ERST storage, while CPER records from
* multiple boot may co-exist in ERST.
*/
u64 cper_next_record_id(void)
{
static atomic64_t seq;

if (!atomic64_read(&seq))
atomic64_set(&seq, ((u64)get_seconds()) << 32);

return atomic64_inc_return(&seq);
}
EXPORT_SYMBOL_GPL(cper_next_record_id);

int apei_estatus_check_header(const struct acpi_hest_generic_status *estatus)
{
if (estatus->data_length &&
estatus->data_length < sizeof(struct acpi_hest_generic_data))
return -EINVAL;
if (estatus->raw_data_length &&
estatus->raw_data_offset < sizeof(*estatus) + estatus->data_length)
return -EINVAL;

return 0;
}
EXPORT_SYMBOL_GPL(apei_estatus_check_header);

int apei_estatus_check(const struct acpi_hest_generic_status *estatus)
{
struct acpi_hest_generic_data *gdata;
unsigned int data_len, gedata_len;
int rc;

rc = apei_estatus_check_header(estatus);
if (rc)
return rc;
data_len = estatus->data_length;
gdata = (struct acpi_hest_generic_data *)(estatus + 1);
while (data_len > sizeof(*gdata)) {
gedata_len = gdata->error_data_length;
if (gedata_len > data_len - sizeof(*gdata))
return -EINVAL;
data_len -= gedata_len + sizeof(*gdata);
}
if (data_len)
return -EINVAL;

return 0;
}
EXPORT_SYMBOL_GPL(apei_estatus_check);
Loading

0 comments on commit 06d65de

Please sign in to comment.