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 : : }
|