blob: d55910283d34d46d3b4506a789713448df1c8958 [file] [log] [blame]
Patrick Williams691668f2023-11-01 08:19:10 -05001/* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
Andrew Jefferyb0c1d202023-11-07 22:08:44 +10302#include <libpldm/base.h>
3#include <libpldm/utils.h>
Carter Chenff78bca2025-06-25 10:33:31 +08004#include "utils.h"
Andrew Jefferyb0c1d202023-11-07 22:08:44 +10305
Andrew Jefferya8b8a812023-04-05 14:32:12 +09306#include <limits.h>
Andrew Jeffery9c766792022-08-10 23:12:49 +09307#include <stdio.h>
8
9/** CRC32 code derived from work by Gary S. Brown.
10 * http://web.mit.edu/freebsd/head/sys/libkern/crc32.c
11 *
12 * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or
13 * code or tables extracted from it, as desired without restriction.
14 *
15 */
16static uint32_t crc32_tab[] = {
Andrew Jeffery37dd6a32023-05-12 16:04:06 +093017 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
18 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
19 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
20 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
21 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
22 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
23 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
24 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
25 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
26 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
27 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
28 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
29 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
30 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
31 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
32 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
33 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
34 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
35 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
36 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
37 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
38 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
39 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
40 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
41 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
42 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
43 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
44 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
45 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
46 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
47 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
48 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
49 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
50 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
51 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
52 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
53 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
54 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
55 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
56 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
57 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
58 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
59 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
60};
Andrew Jeffery9c766792022-08-10 23:12:49 +093061
62/* 0x07(polynomial: x8+x2+x1+1)
63 */
64static const uint8_t crc8_table[] = {
Andrew Jeffery37dd6a32023-05-12 16:04:06 +093065 0x00, 0x07, 0x0e, 0x09, 0x1c, 0x1b, 0x12, 0x15, 0x38, 0x3f, 0x36, 0x31,
66 0x24, 0x23, 0x2a, 0x2d, 0x70, 0x77, 0x7e, 0x79, 0x6c, 0x6b, 0x62, 0x65,
67 0x48, 0x4f, 0x46, 0x41, 0x54, 0x53, 0x5a, 0x5d, 0xe0, 0xe7, 0xee, 0xe9,
68 0xfc, 0xfb, 0xf2, 0xf5, 0xd8, 0xdf, 0xd6, 0xd1, 0xc4, 0xc3, 0xca, 0xcd,
69 0x90, 0x97, 0x9e, 0x99, 0x8c, 0x8b, 0x82, 0x85, 0xa8, 0xaf, 0xa6, 0xa1,
70 0xb4, 0xb3, 0xba, 0xbd, 0xc7, 0xc0, 0xc9, 0xce, 0xdb, 0xdc, 0xd5, 0xd2,
71 0xff, 0xf8, 0xf1, 0xf6, 0xe3, 0xe4, 0xed, 0xea, 0xb7, 0xb0, 0xb9, 0xbe,
72 0xab, 0xac, 0xa5, 0xa2, 0x8f, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9d, 0x9a,
73 0x27, 0x20, 0x29, 0x2e, 0x3b, 0x3c, 0x35, 0x32, 0x1f, 0x18, 0x11, 0x16,
74 0x03, 0x04, 0x0d, 0x0a, 0x57, 0x50, 0x59, 0x5e, 0x4b, 0x4c, 0x45, 0x42,
75 0x6f, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7d, 0x7a, 0x89, 0x8e, 0x87, 0x80,
76 0x95, 0x92, 0x9b, 0x9c, 0xb1, 0xb6, 0xbf, 0xb8, 0xad, 0xaa, 0xa3, 0xa4,
77 0xf9, 0xfe, 0xf7, 0xf0, 0xe5, 0xe2, 0xeb, 0xec, 0xc1, 0xc6, 0xcf, 0xc8,
78 0xdd, 0xda, 0xd3, 0xd4, 0x69, 0x6e, 0x67, 0x60, 0x75, 0x72, 0x7b, 0x7c,
79 0x51, 0x56, 0x5f, 0x58, 0x4d, 0x4a, 0x43, 0x44, 0x19, 0x1e, 0x17, 0x10,
80 0x05, 0x02, 0x0b, 0x0c, 0x21, 0x26, 0x2f, 0x28, 0x3d, 0x3a, 0x33, 0x34,
81 0x4e, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5c, 0x5b, 0x76, 0x71, 0x78, 0x7f,
82 0x6a, 0x6d, 0x64, 0x63, 0x3e, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2c, 0x2b,
83 0x06, 0x01, 0x08, 0x0f, 0x1a, 0x1d, 0x14, 0x13, 0xae, 0xa9, 0xa0, 0xa7,
84 0xb2, 0xb5, 0xbc, 0xbb, 0x96, 0x91, 0x98, 0x9f, 0x8a, 0x8d, 0x84, 0x83,
85 0xde, 0xd9, 0xd0, 0xd7, 0xc2, 0xc5, 0xcc, 0xcb, 0xe6, 0xe1, 0xe8, 0xef,
86 0xfa, 0xfd, 0xf4, 0xf3
87};
Andrew Jeffery9c766792022-08-10 23:12:49 +093088
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +093089LIBPLDM_ABI_STABLE
Andrew Jefferya3863482025-04-05 20:11:02 +103090uint32_t pldm_edac_crc32(const void *data, size_t size)
Andrew Jeffery9c766792022-08-10 23:12:49 +093091{
Kasun Athukoralad7b94242025-06-19 01:02:38 +000092 return pldm_edac_crc32_extend(data, size, 0);
93}
94
95LIBPLDM_ABI_TESTING
96uint32_t pldm_edac_crc32_extend(const void *data, size_t size, uint32_t crc)
97{
Andrew Jeffery9c766792022-08-10 23:12:49 +093098 const uint8_t *p = data;
Kasun Athukoralad7b94242025-06-19 01:02:38 +000099 crc ^= ~0U;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930100 while (size--) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930101 crc = crc32_tab[(crc ^ *p++) & 0xff] ^ (crc >> 8);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930102 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930103 return crc ^ ~0U;
104}
105
Carter Chenff78bca2025-06-25 10:33:31 +0800106int pldm_edac_crc32_validate(uint32_t expected, const void *data, size_t size)
107{
108 if (!data && size) { /* data is NULL but size is not zero */
109 return -EINVAL;
110 }
111 uint32_t actual = pldm_edac_crc32(data, size);
112 return (expected == actual) ? 0 : -EUCLEAN;
113}
114
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930115LIBPLDM_ABI_STABLE
Andrew Jefferyd0c9ae72025-04-05 20:11:02 +1030116uint8_t pldm_edac_crc8(const void *data, size_t size)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930117{
118 const uint8_t *p = data;
119 uint8_t crc = 0x00;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930120 while (size--) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930121 crc = crc8_table[crc ^ *p++];
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930122 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930123 return crc;
124}
125
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930126#define BCD_H(v) (((v) >> 4) & 0xf)
Patrick Williamsc0b5a6e2023-10-20 11:20:16 -0500127#define BCD_L(v) ((v) & 0xf)
Andrew Jefferya8b8a812023-04-05 14:32:12 +0930128#define AS_CHAR(digit) ((digit) + '0')
129#define INSERT_CHAR(c, b, n) \
130 { \
Andrew Jeffery0a05b122023-04-05 14:03:36 +0930131 if ((n) > 1) { \
Andrew Jefferya8b8a812023-04-05 14:32:12 +0930132 *(b)++ = (c); \
133 (n)--; \
134 } \
135 }
136#define INSERT_INT(i, b, n) INSERT_CHAR(AS_CHAR(i), (b), (n))
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930137
138LIBPLDM_ABI_STABLE
Andrew Jefferya8b8a812023-04-05 14:32:12 +0930139ssize_t ver2str(const ver32_t *version, char *buffer, size_t buffer_size)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930140{
Andrew Jefferya8b8a812023-04-05 14:32:12 +0930141 ssize_t remaining;
142 char *cursor;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930143
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930144 if (!version || !buffer) {
Andrew Jefferya8b8a812023-04-05 14:32:12 +0930145 return -1;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930146 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930147
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930148 if (!buffer_size) {
Andrew Jefferya8b8a812023-04-05 14:32:12 +0930149 return -1;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930150 }
Andrew Jefferya8b8a812023-04-05 14:32:12 +0930151
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930152 if (buffer_size > SSIZE_MAX) {
Andrew Jefferya8b8a812023-04-05 14:32:12 +0930153 return -1;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930154 }
Andrew Jefferya8b8a812023-04-05 14:32:12 +0930155
156 cursor = buffer;
157 remaining = (ssize_t)buffer_size;
158
159 if (version->major < 0xf0)
160 INSERT_INT(BCD_H(version->major), cursor, remaining)
161 INSERT_INT(BCD_L(version->major), cursor, remaining);
162 INSERT_CHAR('.', cursor, remaining);
163
164 if (version->minor < 0xf0)
165 INSERT_INT(BCD_H(version->minor), cursor, remaining);
166 INSERT_INT(BCD_L(version->minor), cursor, remaining);
167
168 if (version->update < 0xff) {
169 INSERT_CHAR('.', cursor, remaining);
170 if (version->update < 0xf0)
171 INSERT_INT(BCD_H(version->update), cursor, remaining);
172 INSERT_INT(BCD_L(version->update), cursor, remaining);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930173 }
Andrew Jefferya8b8a812023-04-05 14:32:12 +0930174
175 if (version->alpha)
176 INSERT_CHAR(version->alpha, cursor, remaining);
177
178 *cursor = '\0';
179
180 return (ssize_t)buffer_size - remaining;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930181}
182
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930183LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930184uint8_t bcd2dec8(uint8_t bcd)
185{
Andrew Jeffery3c016182023-04-05 14:23:21 +0930186 return (bcd >> 4) * 10 + (bcd & 0x0f);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930187}
188
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930189LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930190uint8_t dec2bcd8(uint8_t dec)
191{
Andrew Jefferye21df502023-04-05 14:28:47 +0930192 return ((dec / 10) << 4) + (dec % 10);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930193}
194
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930195LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930196uint16_t bcd2dec16(uint16_t bcd)
197{
198 return bcd2dec8(bcd >> 8) * 100 + bcd2dec8(bcd & 0xff);
199}
200
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930201LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930202uint16_t dec2bcd16(uint16_t dec)
203{
Andrew Jeffery3ce64fb2023-04-12 22:21:40 +0930204 return dec2bcd8(dec % 100) | ((uint16_t)(dec2bcd8(dec / 100)) << 8);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930205}
206
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930207LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930208uint32_t bcd2dec32(uint32_t bcd)
209{
210 return bcd2dec16(bcd >> 16) * 10000 + bcd2dec16(bcd & 0xffff);
211}
212
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930213LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930214uint32_t dec2bcd32(uint32_t dec)
215{
Andrew Jeffery3ce64fb2023-04-12 22:21:40 +0930216 return dec2bcd16(dec % 10000) |
217 ((uint32_t)(dec2bcd16(dec / 10000)) << 16);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930218}
219
Andrew Jefferya1809632024-10-04 21:05:54 +0930220static int day_map(uint8_t month)
221{
222 switch (month) {
223 case 1:
224 return 31;
225 case 2:
226 return 28;
227 case 3:
228 return 31;
229 case 4:
230 return 30;
231 case 5:
232 return 31;
233 case 6:
234 return 30;
235 case 7:
236 case 8:
237 return 31;
238 case 9:
239 return 30;
240 case 10:
241 return 31;
242 case 11:
243 return 30;
244 case 12:
245 return 31;
246 default:
247 return 0;
248 }
249}
250
Andrew Jeffery800e1832025-04-05 18:56:14 +1030251LIBPLDM_ABI_DEPRECATED
Andrew Jeffery9c766792022-08-10 23:12:49 +0930252bool is_time_legal(uint8_t seconds, uint8_t minutes, uint8_t hours, uint8_t day,
253 uint8_t month, uint16_t year)
254{
255 if (month < 1 || month > 12) {
256 return false;
257 }
Andrew Jefferya1809632024-10-04 21:05:54 +0930258 int rday = day_map(month);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930259 if (month == 2 &&
260 ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))) {
261 rday += 1;
262 }
263 if (year < 1970 || day < 1 || day > rday || seconds > 59 ||
264 minutes > 59 || hours > 23) {
265 return false;
266 }
267 return true;
268}
269
Andrew Jefferyb7677b72025-04-05 18:56:14 +1030270LIBPLDM_ABI_DEPRECATED
Andrew Jeffery9c766792022-08-10 23:12:49 +0930271bool is_transfer_flag_valid(uint8_t transfer_flag)
272{
273 switch (transfer_flag) {
274 case PLDM_START:
275 case PLDM_MIDDLE:
276 case PLDM_END:
277 case PLDM_START_AND_END:
278 return true;
279
280 default:
281 return false;
282 }
283}