LCOV - code coverage report
Current view: top level - core - vpd.c (source / functions) Coverage Total Hit
Test: skiboot.info Lines: 88.1 % 59 52
Test Date: 2025-01-15 20:37:39 Functions: 100.0 % 4 4
Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : // SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
       2                 :             : /*
       3                 :             :  * Parse Vital Product Data (VPD)
       4                 :             :  *
       5                 :             :  * Copyright 2013-2019 IBM Corp.
       6                 :             :  */
       7                 :             : 
       8                 :             : #include <skiboot.h>
       9                 :             : #include <vpd.h>
      10                 :             : #include <string.h>
      11                 :             : #include <device.h>
      12                 :             : 
      13                 :             : #define CHECK_SPACE(_p, _n, _e) (((_e) - (_p)) >= (_n))
      14                 :             : 
      15                 :             : /* Low level keyword search in a record. Can be used when we
      16                 :             :  * need to find the next keyword of a given type, for example
      17                 :             :  * when having multiple MF/SM keyword pairs
      18                 :             :  */
      19                 :         336 : const void *vpd_find_keyword(const void *rec, size_t rec_sz,
      20                 :             :                              const char *kw, uint8_t *kw_size)
      21                 :             : {
      22                 :         336 :         const uint8_t *p = rec, *end = rec + rec_sz;
      23                 :             : 
      24                 :        1114 :         while (CHECK_SPACE(p, 3, end)) {
      25                 :        1102 :                 uint8_t k1 = *(p++);
      26                 :        1102 :                 uint8_t k2 = *(p++);
      27                 :        1102 :                 uint8_t sz = *(p++);
      28                 :             : 
      29                 :        1102 :                 if (k1 == kw[0] && k2 == kw[1]) {
      30                 :         324 :                         if (kw_size)
      31                 :         323 :                                 *kw_size = sz;
      32                 :         324 :                         return p;
      33                 :             :                 }
      34                 :         778 :                 p += sz;
      35                 :             :         }
      36                 :          12 :         return NULL;
      37                 :             : }
      38                 :             : 
      39                 :             : /* vpd_valid - does some basic sanity checks to ensure a VPD blob is
      40                 :             :  *             actually a VPD blob
      41                 :             :  */
      42                 :          13 : bool vpd_valid(const void *vvpd, size_t vpd_size)
      43                 :             : {
      44                 :          13 :         const uint8_t *vpd = vvpd;
      45                 :          13 :         int size, i = 0;
      46                 :             : 
      47                 :             :         /* find the record start byte */
      48                 :          13 :         while (i < vpd_size)
      49                 :          13 :                 if (vpd[i++] == 0x84)
      50                 :          13 :                         break;
      51                 :             : 
      52                 :          13 :         if (i >= vpd_size)
      53                 :           0 :                 return false;
      54                 :             : 
      55                 :             :         /* next two bytes are the record length, little endian */
      56                 :          13 :         size  = 2;
      57                 :          13 :         size += vpd[i];
      58                 :          13 :         size += vpd[i + 1] << 8;
      59                 :             : 
      60                 :          13 :         i += size; /* skip to the end marker */
      61                 :             : 
      62                 :          13 :         if (i >= vpd_size || vpd[i] != 0x78)
      63                 :           0 :                 return false;
      64                 :             : 
      65                 :          13 :         return true;
      66                 :             : }
      67                 :             : 
      68                 :             : /* Locate  a record in a VPD blob
      69                 :             :  *
      70                 :             :  * Note: This works with VPD LIDs. It will scan until it finds
      71                 :             :  * the first 0x84, so it will skip all those 0's that the VPD
      72                 :             :  * LIDs seem to contain
      73                 :             :  */
      74                 :         128 : const void *vpd_find_record(const void *vpd, size_t vpd_size,
      75                 :             :                             const char *record, size_t *sz)
      76                 :             : {
      77                 :         128 :         const uint8_t *p = vpd, *end = vpd + vpd_size;
      78                 :         128 :         bool first_start = true;
      79                 :             :         size_t rec_sz;
      80                 :         128 :         uint8_t namesz = 0;
      81                 :             :         const char *rec_name;
      82                 :             : 
      83                 :         128 :         if (!vpd)
      84                 :           0 :                 return NULL;
      85                 :             : 
      86                 :         366 :         while (CHECK_SPACE(p, 4, end)) {
      87                 :             :                 /* Get header byte */
      88                 :         362 :                 if (*(p++) != 0x84) {
      89                 :             :                         /* Skip initial crap in VPD LIDs */
      90                 :         129 :                         if (first_start)
      91                 :         110 :                                 continue;
      92                 :          19 :                         break;
      93                 :             :                 }
      94                 :         233 :                 first_start = false;
      95                 :         233 :                 rec_sz = *(p++);
      96                 :         233 :                 rec_sz |= *(p++) << 8;
      97                 :         233 :                 if (!CHECK_SPACE(p, rec_sz, end)) {
      98                 :           0 :                         prerror("VPD: Malformed or truncated VPD,"
      99                 :             :                                 " record size doesn't fit\n");
     100                 :           0 :                         return NULL;
     101                 :             :                 }
     102                 :             : 
     103                 :             :                 /* Find record name */
     104                 :         233 :                 rec_name = vpd_find_keyword(p, rec_sz, "RT", &namesz);
     105                 :         233 :                 if (rec_name && strncmp(record, rec_name, namesz) == 0) {
     106                 :         105 :                         if (sz)
     107                 :         103 :                                 *sz = rec_sz;
     108                 :         105 :                         return p;
     109                 :             :                 }
     110                 :             : 
     111                 :         128 :                 p += rec_sz;
     112                 :         128 :                 if (*(p++) != 0x78) {
     113                 :           0 :                         prerror("VPD: Malformed or truncated VPD,"
     114                 :             :                                 " missing final 0x78 in record %.4s\n",
     115                 :             :                                 rec_name ? rec_name : "????");
     116                 :           0 :                         return NULL;
     117                 :             :                 }
     118                 :             :         }
     119                 :          23 :         return NULL;
     120                 :             : }
     121                 :             : 
     122                 :             : /* Locate a keyword in a record in a VPD blob
     123                 :             :  *
     124                 :             :  * Note: This works with VPD LIDs. It will scan until it finds
     125                 :             :  * the first 0x84, so it will skip all those 0's that the VPD
     126                 :             :  * LIDs seem to contain
     127                 :             :  */
     128                 :         103 : const void *vpd_find(const void *vpd, size_t vpd_size,
     129                 :             :                      const char *record, const char *keyword,
     130                 :             :                      uint8_t *sz)
     131                 :             : {
     132                 :             :         size_t rec_sz;
     133                 :             :         const uint8_t *p;
     134                 :             : 
     135                 :         103 :         p = vpd_find_record(vpd, vpd_size, record, &rec_sz);
     136                 :         103 :         if (p)
     137                 :         103 :                 p = vpd_find_keyword(p, rec_sz, keyword, sz);
     138                 :         103 :         return p;
     139                 :             : }
        

Generated by: LCOV version 2.0-1