LCOV - code coverage report
Current view: top level - core - pel.c (source / functions) Hit Total Coverage
Test: skiboot.info Lines: 155 159 97.5 %
Date: 2024-09-10 18:37:41 Functions: 12 12 100.0 %
Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
       2                 :            : /*
       3                 :            :  * Platform Error Log (PEL) generation
       4                 :            :  *
       5                 :            :  * Copyright 2014-2016 IBM Corp
       6                 :            :  */
       7                 :            : 
       8                 :            : #include <string.h>
       9                 :            : #include <errorlog.h>
      10                 :            : #include <device.h>
      11                 :            : #include <fsp.h>
      12                 :            : #include <pel.h>
      13                 :            : #include <rtc.h>
      14                 :            : 
      15                 :            : /* Create MTMS section for sapphire log */
      16                 :          2 : static void create_mtms_section(struct errorlog *elog_data,
      17                 :            :                                         char *pel_buffer, int *pel_offset)
      18                 :            : {
      19                 :            :         const struct dt_property *p;
      20                 :            : 
      21                 :          2 :         struct opal_mtms_section *mtms = (struct opal_mtms_section *)
      22                 :          2 :                                 (pel_buffer + *pel_offset);
      23                 :            : 
      24                 :          2 :         mtms->v6header.id = cpu_to_be16(ELOG_SID_MACHINE_TYPE);
      25                 :          2 :         mtms->v6header.length = cpu_to_be16(MTMS_SECTION_SIZE);
      26                 :          2 :         mtms->v6header.version = OPAL_EXT_HRD_VER;
      27                 :          2 :         mtms->v6header.subtype = 0;
      28                 :          2 :         mtms->v6header.component_id = cpu_to_be16(elog_data->component_id);
      29                 :            : 
      30                 :          2 :         memset(mtms->model, 0x00, sizeof(mtms->model));
      31                 :          2 :         memcpy(mtms->model, dt_prop_get(dt_root, "model"), OPAL_SYS_MODEL_LEN);
      32                 :            : 
      33                 :          2 :         memset(mtms->serial_no, 0x00, sizeof(mtms->serial_no));
      34                 :          2 :         p = dt_find_property(dt_root, "system-id");
      35                 :          2 :         if (p)
      36                 :          0 :                 memcpy(mtms->serial_no, p->prop, OPAL_SYS_SERIAL_LEN);
      37                 :            :         else
      38                 :          2 :                 memset(mtms->serial_no, 0, OPAL_SYS_SERIAL_LEN);
      39                 :            : 
      40                 :          2 :         *pel_offset += MTMS_SECTION_SIZE;
      41                 :          2 : }
      42                 :            : 
      43                 :            : /* Create extended header section */
      44                 :          2 : static void create_extended_header_section(struct errorlog *elog_data,
      45                 :            :                                         char *pel_buffer, int *pel_offset)
      46                 :            : {
      47                 :          2 :         const char  *opalmodel = NULL;
      48                 :            :         const struct dt_property *p;
      49                 :            :         uint64_t extd_time;
      50                 :            :         uint32_t extd_date;
      51                 :            : 
      52                 :          2 :         struct opal_extended_header_section *extdhdr =
      53                 :            :                         (struct opal_extended_header_section *)
      54                 :          2 :                                         (pel_buffer + *pel_offset);
      55                 :            : 
      56                 :          2 :         extdhdr->v6header.id = cpu_to_be16(ELOG_SID_EXTENDED_HEADER);
      57                 :          2 :         extdhdr->v6header.length = cpu_to_be16(EXTENDED_HEADER_SECTION_SIZE);
      58                 :          2 :         extdhdr->v6header.version = OPAL_EXT_HRD_VER;
      59                 :          2 :         extdhdr->v6header.subtype = 0;
      60                 :          2 :         extdhdr->v6header.component_id = cpu_to_be16(elog_data->component_id);
      61                 :            : 
      62                 :          2 :         memset(extdhdr->model, 0x00, sizeof(extdhdr->model));
      63                 :          2 :         opalmodel = dt_prop_get(dt_root, "model");
      64                 :          2 :         memcpy(extdhdr->model, opalmodel, OPAL_SYS_MODEL_LEN);
      65                 :            : 
      66                 :          2 :         memset(extdhdr->serial_no, 0x00, sizeof(extdhdr->serial_no));
      67                 :          2 :         p = dt_find_property(dt_root, "system-id");
      68                 :          2 :         if (p)
      69                 :          0 :                 memcpy(extdhdr->serial_no, p->prop, OPAL_SYS_SERIAL_LEN);
      70                 :            :         else
      71                 :          2 :                 memset(extdhdr->serial_no, 0, OPAL_SYS_SERIAL_LEN);
      72                 :            : 
      73                 :          2 :         memset(extdhdr->opal_release_version, 0x00,
      74                 :            :                                 sizeof(extdhdr->opal_release_version));
      75                 :          2 :         memset(extdhdr->opal_subsys_version, 0x00,
      76                 :            :                                 sizeof(extdhdr->opal_subsys_version));
      77                 :            : 
      78                 :          2 :         rtc_cache_get_datetime(&extd_date, &extd_time);
      79                 :          2 :         extdhdr->extended_header_date = cpu_to_be32(extd_date);
      80                 :          2 :         extdhdr->extended_header_time = cpu_to_be32(extd_time >> 32);
      81                 :          2 :         extdhdr->opal_symid_len = 0;
      82                 :            : 
      83                 :          2 :         *pel_offset += EXTENDED_HEADER_SECTION_SIZE;
      84                 :          2 : }
      85                 :            : 
      86                 :            : /* set src type */
      87                 :          2 : static void settype(struct opal_src_section *src, uint8_t src_type)
      88                 :            : {
      89                 :            :         char type[4];
      90                 :          2 :         snprintf(type, sizeof(type), "%02X", src_type);
      91                 :          2 :         memcpy(src->srcstring, type, 2);
      92                 :          2 : }
      93                 :            : 
      94                 :            : /* set SRC subsystem type */
      95                 :          2 : static void setsubsys(struct opal_src_section *src, uint8_t src_subsys)
      96                 :            : {
      97                 :            :         char subsys[4];
      98                 :          2 :         snprintf(subsys, sizeof(subsys), "%02X", src_subsys);
      99                 :          2 :         memcpy(src->srcstring+2, subsys, 2);
     100                 :          2 : }
     101                 :            : 
     102                 :            : /* Ser reason code of SRC */
     103                 :          2 : static void setrefcode(struct opal_src_section *src, uint16_t src_refcode)
     104                 :            : {
     105                 :            :         char refcode[8];
     106                 :          2 :         snprintf(refcode, sizeof(refcode), "%04X", src_refcode);
     107                 :          2 :         memcpy(src->srcstring+4, refcode, 4);
     108                 :          2 : }
     109                 :            : 
     110                 :            : /* Create SRC section of OPAL log */
     111                 :          2 : static void create_src_section(struct errorlog *elog_data,
     112                 :            :                                         char *pel_buffer, int *pel_offset)
     113                 :            : {
     114                 :          2 :         struct opal_src_section *src = (struct opal_src_section *)
     115                 :          2 :                                                 (pel_buffer + *pel_offset);
     116                 :            : 
     117                 :          2 :         src->v6header.id = cpu_to_be16(ELOG_SID_PRIMARY_SRC);
     118                 :          2 :         src->v6header.length = cpu_to_be16(SRC_SECTION_SIZE);
     119                 :          2 :         src->v6header.version = OPAL_ELOG_VERSION;
     120                 :          2 :         src->v6header.subtype = OPAL_ELOG_SST;
     121                 :          2 :         src->v6header.component_id = cpu_to_be16(elog_data->component_id);
     122                 :            : 
     123                 :          2 :         src->version = OPAL_SRC_SEC_VER;
     124                 :          2 :         src->flags = 0;
     125                 :          2 :         src->wordcount = OPAL_SRC_MAX_WORD_COUNT;
     126                 :          2 :         src->srclength = cpu_to_be16(SRC_LENGTH);
     127                 :          2 :         settype(src, OPAL_SRC_TYPE_ERROR);
     128                 :          2 :         setsubsys(src, OPAL_FAILING_SUBSYSTEM);
     129                 :          2 :         setrefcode(src, elog_data->reason_code);
     130                 :          2 :         memset(src->hexwords, 0 , (8 * 4));
     131                 :          2 :         src->hexwords[0] = cpu_to_be32(OPAL_SRC_FORMAT);
     132                 :          2 :         src->hexwords[4] = cpu_to_be32(elog_data->additional_info[0]);
     133                 :          2 :         src->hexwords[5] = cpu_to_be32(elog_data->additional_info[1]);
     134                 :          2 :         src->hexwords[6] = cpu_to_be32(elog_data->additional_info[2]);
     135                 :          2 :         src->hexwords[7] = cpu_to_be32(elog_data->additional_info[3]);
     136                 :          2 :         *pel_offset += SRC_SECTION_SIZE;
     137                 :          2 : }
     138                 :            : 
     139                 :            : /* Create user header section */
     140                 :          2 : static void create_user_header_section(struct errorlog *elog_data,
     141                 :            :                                         char *pel_buffer, int *pel_offset)
     142                 :            : {
     143                 :          2 :         struct opal_user_header_section *usrhdr =
     144                 :            :                                 (struct opal_user_header_section *)
     145                 :          2 :                                                 (pel_buffer + *pel_offset);
     146                 :            : 
     147                 :          2 :         usrhdr->v6header.id = cpu_to_be16(ELOG_SID_USER_HEADER);
     148                 :          2 :         usrhdr->v6header.length = cpu_to_be16(USER_HEADER_SECTION_SIZE);
     149                 :          2 :         usrhdr->v6header.version = OPAL_ELOG_VERSION;
     150                 :          2 :         usrhdr->v6header.subtype = OPAL_ELOG_SST;
     151                 :          2 :         usrhdr->v6header.component_id = cpu_to_be16(elog_data->component_id);
     152                 :            : 
     153                 :          2 :         usrhdr->subsystem_id = elog_data->subsystem_id;
     154                 :          2 :         usrhdr->event_scope = 0;
     155                 :          2 :         usrhdr->event_severity = elog_data->event_severity;
     156                 :          2 :         usrhdr->event_type = elog_data->event_subtype;
     157                 :            : 
     158                 :          2 :         if (elog_data->elog_origin == ORG_SAPPHIRE)
     159                 :          2 :                 usrhdr->action_flags = cpu_to_be16(ERRL_ACTION_REPORT);
     160                 :            :         else
     161                 :          0 :                 usrhdr->action_flags = cpu_to_be16(ERRL_ACTION_NONE);
     162                 :            : 
     163                 :          2 :         *pel_offset += USER_HEADER_SECTION_SIZE;
     164                 :          2 : }
     165                 :            : 
     166                 :            : /* Create private header section */
     167                 :          2 : static void create_private_header_section(struct errorlog *elog_data,
     168                 :            :                                         char *pel_buffer, int *pel_offset)
     169                 :            : {
     170                 :            :         uint64_t ctime;
     171                 :            :         uint32_t cdate;
     172                 :          2 :         struct opal_private_header_section *privhdr =
     173                 :            :                                 (struct opal_private_header_section *)
     174                 :            :                                                                 pel_buffer;
     175                 :            : 
     176                 :          2 :         privhdr->v6header.id = cpu_to_be16(ELOG_SID_PRIVATE_HEADER);
     177                 :          2 :         privhdr->v6header.length = cpu_to_be16(PRIVATE_HEADER_SECTION_SIZE);
     178                 :          2 :         privhdr->v6header.version = OPAL_ELOG_VERSION;
     179                 :          2 :         privhdr->v6header.subtype = OPAL_ELOG_SST;
     180                 :          2 :         privhdr->v6header.component_id = cpu_to_be16(elog_data->component_id);
     181                 :          2 :         privhdr->plid = cpu_to_be32(elog_data->plid);
     182                 :            : 
     183                 :          2 :         rtc_cache_get_datetime(&cdate, &ctime);
     184                 :          2 :         privhdr->create_date = cpu_to_be32(cdate);
     185                 :          2 :         privhdr->create_time = cpu_to_be32(ctime >> 32);
     186                 :          2 :         privhdr->section_count = 5;
     187                 :            : 
     188                 :          2 :         privhdr->creator_subid_hi = 0x00;
     189                 :          2 :         privhdr->creator_subid_lo = 0x00;
     190                 :            : 
     191                 :          2 :         if (elog_data->elog_origin == ORG_SAPPHIRE)
     192                 :          2 :                 privhdr->creator_id = OPAL_CID_SAPPHIRE;
     193                 :            :         else
     194                 :          0 :                 privhdr->creator_id = OPAL_CID_POWERNV;
     195                 :            : 
     196                 :          2 :         privhdr->log_entry_id = cpu_to_be32(elog_data->plid); /*entry id is updated by FSP*/
     197                 :            : 
     198                 :          2 :         *pel_offset += PRIVATE_HEADER_SECTION_SIZE;
     199                 :          2 : }
     200                 :            : 
     201                 :          1 : static void create_user_defined_section(struct errorlog *elog_data,
     202                 :            :                                         char *pel_buffer, int *pel_offset)
     203                 :            : {
     204                 :          1 :         char *dump = (char *)pel_buffer + *pel_offset;
     205                 :          1 :         char *opal_buf = (char *)elog_data->user_data_dump;
     206                 :            :         struct opal_user_section *usrhdr;
     207                 :            :         struct elog_user_data_section *opal_usr_data;
     208                 :          1 :         struct opal_private_header_section *privhdr =
     209                 :            :                          (struct opal_private_header_section *)pel_buffer;
     210                 :            :         int i;
     211                 :            : 
     212                 :          2 :         for (i = 0; i < elog_data->user_section_count; i++) {
     213                 :            : 
     214                 :          1 :                 usrhdr = (struct opal_user_section *)dump;
     215                 :          1 :                 opal_usr_data = (struct elog_user_data_section *)opal_buf;
     216                 :            : 
     217                 :          1 :                 usrhdr->v6header.id = cpu_to_be16(ELOG_SID_USER_DEFINED);
     218                 :          2 :                 usrhdr->v6header.length = cpu_to_be16(
     219                 :          1 :                                         sizeof(struct opal_v6_header) +
     220                 :          1 :                                         be16_to_cpu(opal_usr_data->size));
     221                 :          1 :                 usrhdr->v6header.version = OPAL_ELOG_VERSION;
     222                 :          1 :                 usrhdr->v6header.subtype = OPAL_ELOG_SST;
     223                 :          1 :                 usrhdr->v6header.component_id = cpu_to_be16(elog_data->component_id);
     224                 :            : 
     225                 :          1 :                 memcpy(usrhdr->dump, opal_buf, be16_to_cpu(opal_usr_data->size));
     226                 :          1 :                 *pel_offset += be16_to_cpu(usrhdr->v6header.length);
     227                 :          1 :                 dump += be16_to_cpu(usrhdr->v6header.length);
     228                 :          1 :                 opal_buf += be16_to_cpu(opal_usr_data->size);
     229                 :          1 :                 privhdr->section_count++;
     230                 :            :         }
     231                 :          1 : }
     232                 :            : 
     233                 :          6 : static size_t pel_user_section_size(struct errorlog *elog_data)
     234                 :            : {
     235                 :            :         int i;
     236                 :          6 :         size_t total = 0;
     237                 :          6 :         char *opal_buf = (char *)elog_data->user_data_dump;
     238                 :            :         struct elog_user_data_section *opal_usr_data;
     239                 :            : 
     240                 :          8 :         for (i = 0; i < elog_data->user_section_count; i++) {
     241                 :            :                 u16 s;
     242                 :            : 
     243                 :          2 :                 opal_usr_data = (struct elog_user_data_section *)opal_buf;
     244                 :          2 :                 s = be16_to_cpu(opal_usr_data->size);
     245                 :          2 :                 total += sizeof(struct opal_v6_header) + s;
     246                 :          2 :                 opal_buf += s;
     247                 :            :         }
     248                 :            : 
     249                 :          6 :         return total;
     250                 :            : }
     251                 :            : 
     252                 :          6 : size_t pel_size(struct errorlog *elog_data)
     253                 :            : {
     254                 :          6 :         return PEL_MIN_SIZE + pel_user_section_size(elog_data);
     255                 :            : }
     256                 :            : 
     257                 :            : /* Converts an OPAL errorlog into a PEL formatted log */
     258                 :          3 : int create_pel_log(struct errorlog *elog_data, char *pel_buffer,
     259                 :            :                    size_t pel_buffer_size)
     260                 :            : {
     261                 :          3 :         int pel_offset = 0;
     262                 :            : 
     263                 :          3 :         if (pel_buffer_size < pel_size(elog_data)) {
     264                 :          1 :                 prerror("PEL buffer too small to create record\n");
     265                 :          1 :                 return 0;
     266                 :            :         }
     267                 :            : 
     268                 :          2 :         memset(pel_buffer, 0, pel_buffer_size);
     269                 :            : 
     270                 :          2 :         create_private_header_section(elog_data, pel_buffer, &pel_offset);
     271                 :          2 :         create_user_header_section(elog_data, pel_buffer, &pel_offset);
     272                 :          2 :         create_src_section(elog_data, pel_buffer, &pel_offset);
     273                 :          2 :         create_extended_header_section(elog_data, pel_buffer, &pel_offset);
     274                 :          2 :         create_mtms_section(elog_data, pel_buffer, &pel_offset);
     275                 :          2 :         if (elog_data->user_section_count)
     276                 :          1 :                 create_user_defined_section(elog_data, pel_buffer, &pel_offset);
     277                 :            : 
     278                 :          2 :         return pel_offset;
     279                 :            : }

Generated by: LCOV version 1.14