diff options
Diffstat (limited to 'core')
-rw-r--r-- | core/Makefile.inc | 2 | ||||
-rw-r--r-- | core/pel.c | 254 | ||||
-rw-r--r-- | core/test/Makefile.check | 4 | ||||
-rw-r--r-- | core/test/run-pel.c | 81 |
4 files changed, 338 insertions, 3 deletions
diff --git a/core/Makefile.inc b/core/Makefile.inc index 714da3a..8b9a03b 100644 --- a/core/Makefile.inc +++ b/core/Makefile.inc @@ -6,7 +6,7 @@ CORE_OBJS += malloc.o lock.o cpu.o utils.o fdt.o opal.o interrupts.o CORE_OBJS += timebase.o opal-msg.o pci.o pci-opal.o fast-reboot.o CORE_OBJS += device.o exceptions.o trace.o affinity.o vpd.o CORE_OBJS += hostservices.o platform.o nvram.o flash-nvram.o hmi.o -CORE_OBJS += console-log.o ipmi.o time-utils.o +CORE_OBJS += console-log.o ipmi.o time-utils.o pel.o CORE=core/built-in.o $(CORE): $(CORE_OBJS:%=core/%) diff --git a/core/pel.c b/core/pel.c new file mode 100644 index 0000000..1f6d11b --- /dev/null +++ b/core/pel.c @@ -0,0 +1,254 @@ +#include <string.h> +#include <fsp-elog.h> +#include <device.h> +#include <fsp.h> +#include <pel.h> + +/* Create MTMS section for sapphire log */ +static void create_mtms_section(struct errorlog *elog_data, + char *pel_buffer, int *pel_offset) +{ + struct opal_mtms_section *mtms = (struct opal_mtms_section *) + (pel_buffer + *pel_offset); + + mtms->v6header.id = ELOG_SID_MACHINE_TYPE; + mtms->v6header.length = MTMS_SECTION_SIZE; + mtms->v6header.version = OPAL_EXT_HRD_VER; + mtms->v6header.subtype = 0; + mtms->v6header.component_id = elog_data->component_id; + + memset(mtms->model, 0x00, sizeof(mtms->model)); + memcpy(mtms->model, dt_prop_get(dt_root, "model"), OPAL_SYS_MODEL_LEN); + memset(mtms->serial_no, 0x00, sizeof(mtms->serial_no)); + + memcpy(mtms->serial_no, dt_prop_get(dt_root, "system-id"), + OPAL_SYS_SERIAL_LEN); + *pel_offset += MTMS_SECTION_SIZE; +} + +/* Create extended header section */ +static void create_extended_header_section(struct errorlog *elog_data, + char *pel_buffer, int *pel_offset) +{ + const char *opalmodel = NULL; + uint64_t extd_time; + + struct opal_extended_header_section *extdhdr = + (struct opal_extended_header_section *) + (pel_buffer + *pel_offset); + + extdhdr->v6header.id = ELOG_SID_EXTENDED_HEADER; + extdhdr->v6header.length = EXTENDED_HEADER_SECTION_SIZE; + extdhdr->v6header.version = OPAL_EXT_HRD_VER; + extdhdr->v6header.subtype = 0; + extdhdr->v6header.component_id = elog_data->component_id; + + memset(extdhdr->model, 0x00, sizeof(extdhdr->model)); + opalmodel = dt_prop_get(dt_root, "model"); + memcpy(extdhdr->model, opalmodel, OPAL_SYS_MODEL_LEN); + + memset(extdhdr->serial_no, 0x00, sizeof(extdhdr->serial_no)); + memcpy(extdhdr->serial_no, dt_prop_get(dt_root, "system-id"), + OPAL_SYS_SERIAL_LEN); + + memset(extdhdr->opal_release_version, 0x00, + sizeof(extdhdr->opal_release_version)); + memset(extdhdr->opal_subsys_version, 0x00, + sizeof(extdhdr->opal_subsys_version)); + + fsp_rtc_get_cached_tod(&extdhdr->extended_header_date, &extd_time); + extdhdr->extended_header_time = extd_time >> 32; + extdhdr->opal_symid_len = 0; + + *pel_offset += EXTENDED_HEADER_SECTION_SIZE; +} + +/* set src type */ +static void settype(struct opal_src_section *src, uint8_t src_type) +{ + char type[4]; + sprintf(type, "%02X", src_type); + memcpy(src->srcstring, type, 2); +} + +/* set SRC subsystem type */ +static void setsubsys(struct opal_src_section *src, uint8_t src_subsys) +{ + char subsys[4]; + sprintf(subsys, "%02X", src_subsys); + memcpy(src->srcstring+2, subsys, 2); +} + +/* Ser reason code of SRC */ +static void setrefcode(struct opal_src_section *src, uint16_t src_refcode) +{ + char refcode[8]; + sprintf(refcode, "%04X", src_refcode); + memcpy(src->srcstring+4, refcode, 4); +} + +/* Create SRC section of OPAL log */ +static void create_src_section(struct errorlog *elog_data, + char *pel_buffer, int *pel_offset) +{ + struct opal_src_section *src = (struct opal_src_section *) + (pel_buffer + *pel_offset); + + src->v6header.id = ELOG_SID_PRIMARY_SRC; + src->v6header.length = SRC_SECTION_SIZE; + src->v6header.version = OPAL_ELOG_VERSION; + src->v6header.subtype = OPAL_ELOG_SST; + src->v6header.component_id = elog_data->component_id; + + src->version = OPAL_SRC_SEC_VER; + src->flags = 0; + src->wordcount = OPAL_SRC_MAX_WORD_COUNT; + src->srclength = SRC_LENGTH; + settype(src, OPAL_SRC_TYPE_ERROR); + setsubsys(src, OPAL_FAILING_SUBSYSTEM); + setrefcode(src, elog_data->reason_code); + memset(src->hexwords, 0 , (8 * 4)); + src->hexwords[0] = OPAL_SRC_FORMAT; + src->hexwords[4] = elog_data->additional_info[0]; + src->hexwords[5] = elog_data->additional_info[1]; + src->hexwords[6] = elog_data->additional_info[2]; + src->hexwords[7] = elog_data->additional_info[3]; + *pel_offset += SRC_SECTION_SIZE; +} + +/* Create user header section */ +static void create_user_header_section(struct errorlog *elog_data, + char *pel_buffer, int *pel_offset) +{ + struct opal_user_header_section *usrhdr = + (struct opal_user_header_section *) + (pel_buffer + *pel_offset); + + usrhdr->v6header.id = ELOG_SID_USER_HEADER; + usrhdr->v6header.length = USER_HEADER_SECTION_SIZE; + usrhdr->v6header.version = OPAL_ELOG_VERSION; + usrhdr->v6header.subtype = OPAL_ELOG_SST; + usrhdr->v6header.component_id = elog_data->component_id; + + usrhdr->subsystem_id = elog_data->subsystem_id; + usrhdr->event_scope = 0; + usrhdr->event_severity = elog_data->event_severity; + usrhdr->event_type = elog_data->event_subtype; + + if (elog_data->elog_origin == ORG_SAPPHIRE) + usrhdr->action_flags = ERRL_ACTION_REPORT; + else + usrhdr->action_flags = ERRL_ACTION_NONE; + + *pel_offset += USER_HEADER_SECTION_SIZE; +} + +/* Create private header section */ +static void create_private_header_section(struct errorlog *elog_data, + char *pel_buffer, int *pel_offset) +{ + uint64_t ctime; + struct opal_private_header_section *privhdr = + (struct opal_private_header_section *) + pel_buffer; + + privhdr->v6header.id = ELOG_SID_PRIVATE_HEADER; + privhdr->v6header.length = PRIVATE_HEADER_SECTION_SIZE; + privhdr->v6header.version = OPAL_ELOG_VERSION; + privhdr->v6header.subtype = OPAL_ELOG_SST; + privhdr->v6header.component_id = elog_data->component_id; + privhdr->plid = elog_data->plid; + + fsp_rtc_get_cached_tod(&privhdr->create_date, &ctime); + privhdr->create_time = ctime >> 32; + privhdr->section_count = 5; + + privhdr->creator_subid_hi = 0x00; + privhdr->creator_subid_lo = 0x00; + + if (elog_data->elog_origin == ORG_SAPPHIRE) + privhdr->creator_id = OPAL_CID_SAPPHIRE; + else + privhdr->creator_id = OPAL_CID_POWERNV; + + privhdr->log_entry_id = elog_data->plid; /*entry id is updated by FSP*/ + + *pel_offset += PRIVATE_HEADER_SECTION_SIZE; +} + +static void create_user_defined_section(struct errorlog *elog_data, + char *pel_buffer, int *pel_offset) +{ + char *dump = (char *)pel_buffer + *pel_offset; + char *opal_buf = (char *)elog_data->user_data_dump; + struct opal_user_section *usrhdr; + struct elog_user_data_section *opal_usr_data; + struct opal_private_header_section *privhdr = + (struct opal_private_header_section *)pel_buffer; + int i; + + for (i = 0; i < elog_data->user_section_count; i++) { + + usrhdr = (struct opal_user_section *)dump; + opal_usr_data = (struct elog_user_data_section *)opal_buf; + + usrhdr->v6header.id = ELOG_SID_USER_DEFINED; + usrhdr->v6header.version = OPAL_ELOG_VERSION; + usrhdr->v6header.length = sizeof(struct opal_v6_header) + + opal_usr_data->size; + usrhdr->v6header.subtype = OPAL_ELOG_SST; + usrhdr->v6header.component_id = elog_data->component_id; + + memcpy(usrhdr->dump, opal_buf, opal_usr_data->size); + *pel_offset += usrhdr->v6header.length; + dump += usrhdr->v6header.length; + opal_buf += opal_usr_data->size; + privhdr->section_count++; + } +} + +static size_t pel_user_section_size(struct errorlog *elog_data) +{ + int i; + size_t total = 0; + char *opal_buf = (char *)elog_data->user_data_dump; + struct elog_user_data_section *opal_usr_data; + + for (i = 0; i < elog_data->user_section_count; i++) { + opal_usr_data = (struct elog_user_data_section *)opal_buf; + total += sizeof(struct opal_v6_header) + + opal_usr_data->size; + opal_buf += opal_usr_data->size; + } + + return total; +} + +size_t pel_size(struct errorlog *elog_data) +{ + return PEL_MIN_SIZE + pel_user_section_size(elog_data); +} + +/* Converts an OPAL errorlog into a PEL formatted log */ +int create_pel_log(struct errorlog *elog_data, char *pel_buffer, + size_t pel_buffer_size) +{ + int pel_offset = 0; + + if (pel_buffer_size < pel_size(elog_data)) { + prerror("PEL buffer too small to create record"); + return 0; + } + + memset(pel_buffer, 0, pel_buffer_size); + + create_private_header_section(elog_data, pel_buffer, &pel_offset); + create_user_header_section(elog_data, pel_buffer, &pel_offset); + create_src_section(elog_data, pel_buffer, &pel_offset); + create_extended_header_section(elog_data, pel_buffer, &pel_offset); + create_mtms_section(elog_data, pel_buffer, &pel_offset); + if (elog_data->user_section_count) + create_user_defined_section(elog_data, pel_buffer, &pel_offset); + + return pel_offset; +} diff --git a/core/test/Makefile.check b/core/test/Makefile.check index 8645001..3fe4530 100644 --- a/core/test/Makefile.check +++ b/core/test/Makefile.check @@ -1,5 +1,5 @@ # -*-Makefile-*- -CORE_TEST := core/test/run-device core/test/run-mem_region core/test/run-malloc core/test/run-malloc-speed core/test/run-mem_region_init core/test/run-mem_region_release_unused core/test/run-mem_region_release_unused_noalloc core/test/run-trace core/test/run-msg +CORE_TEST := core/test/run-device core/test/run-mem_region core/test/run-malloc core/test/run-malloc-speed core/test/run-mem_region_init core/test/run-mem_region_release_unused core/test/run-mem_region_release_unused_noalloc core/test/run-trace core/test/run-msg core/test/run-pel check: $(CORE_TEST:%=%-check) $(CORE_TEST:%=%-gcov-run) @@ -16,7 +16,7 @@ core/test/stubs.o: core/test/stubs.c $(CORE_TEST) : core/test/stubs.o -$(CORE_TEST) : % : %.c +$(CORE_TEST) : % : %.c $(HOSTCC) $(HOSTCFLAGS) -O0 -g -I include -I . -I libfdt -o $@ $< core/test/stubs.o $(CORE_TEST): % : %.d diff --git a/core/test/run-pel.c b/core/test/run-pel.c new file mode 100644 index 0000000..b7a5b26 --- /dev/null +++ b/core/test/run-pel.c @@ -0,0 +1,81 @@ +/* Copyright 2013-2014 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Test for our PEL record generation. Currently this doesn't actually + * test that the records we generate are correct, but it at least lets + * us run valgrind over the generation routines to check for buffer + * overflows, etc. + */ + +#include <skiboot.h> +#include <inttypes.h> +#include <assert.h> +#include <pel.h> +#include <errorlog.h> + +#define TEST_ERROR 0x1234 +#define TEST_SUBSYS 0x5678 + +DEFINE_LOG_ENTRY(TEST_ERROR, OPAL_PLATFORM_ERR_EVT, TEST_SUBSYS, + OPAL_PLATFORM_FIRMWARE, OPAL_INFO, + OPAL_NA, NULL); + +#include "../pel.c" + +struct dt_node *dt_root = NULL; +char dt_prop[] = "DUMMY DT PROP"; +const void *dt_prop_get(const struct dt_node *node __unused, const char *prop __unused) +{ + return dt_prop; +} + +int fsp_rtc_get_cached_tod(uint32_t *year_month_day, + uint64_t *hour_minute_second_millisecond) +{ + *year_month_day = 0; + *hour_minute_second_millisecond = 0; + + return 0; +} + +int main(void) +{ + char *pel_buf; + size_t size; + struct errorlog *elog; + struct opal_err_info *opal_err_info = &err_TEST_ERROR; + + elog = malloc(sizeof(struct errorlog)); + pel_buf = malloc(PEL_MIN_SIZE + 4); + assert(elog); + assert(pel_buf); + + memset(elog, 0, sizeof(struct errorlog)); + + elog->error_event_type = opal_err_info->err_type; + elog->component_id = opal_err_info->cmp_id; + elog->subsystem_id = opal_err_info->subsystem; + elog->event_severity = opal_err_info->sev; + elog->event_subtype = opal_err_info->event_subtype; + elog->reason_code = opal_err_info->reason_code; + elog->elog_origin = ORG_SAPPHIRE; + + size = pel_size(elog); + printf("PEL Size: %ld\n", size); + assert(size == create_pel_log(elog, pel_buf, size)); + + return 0; +} |