xref: /openbmc/libpldm/src/utils.c (revision b0c1d20a)
1691668feSPatrick Williams /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
2*b0c1d20aSAndrew Jeffery #include <libpldm/base.h>
3*b0c1d20aSAndrew Jeffery #include <libpldm/utils.h>
4*b0c1d20aSAndrew Jeffery 
5a8b8a810SAndrew Jeffery #include <limits.h>
69c766792SAndrew Jeffery #include <stdio.h>
79c766792SAndrew Jeffery 
89c766792SAndrew Jeffery /** CRC32 code derived from work by Gary S. Brown.
99c766792SAndrew Jeffery  *  http://web.mit.edu/freebsd/head/sys/libkern/crc32.c
109c766792SAndrew Jeffery  *
119c766792SAndrew Jeffery  *  COPYRIGHT (C) 1986 Gary S. Brown.  You may use this program, or
129c766792SAndrew Jeffery  *  code or tables extracted from it, as desired without restriction.
139c766792SAndrew Jeffery  *
149c766792SAndrew Jeffery  */
159c766792SAndrew Jeffery static uint32_t crc32_tab[] = {
169c766792SAndrew Jeffery 	0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
179c766792SAndrew Jeffery 	0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
189c766792SAndrew Jeffery 	0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
199c766792SAndrew Jeffery 	0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
209c766792SAndrew Jeffery 	0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
219c766792SAndrew Jeffery 	0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
229c766792SAndrew Jeffery 	0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
239c766792SAndrew Jeffery 	0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
249c766792SAndrew Jeffery 	0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
259c766792SAndrew Jeffery 	0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
269c766792SAndrew Jeffery 	0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
279c766792SAndrew Jeffery 	0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
289c766792SAndrew Jeffery 	0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
299c766792SAndrew Jeffery 	0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
309c766792SAndrew Jeffery 	0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
319c766792SAndrew Jeffery 	0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
329c766792SAndrew Jeffery 	0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
339c766792SAndrew Jeffery 	0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
349c766792SAndrew Jeffery 	0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
359c766792SAndrew Jeffery 	0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
369c766792SAndrew Jeffery 	0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
379c766792SAndrew Jeffery 	0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
389c766792SAndrew Jeffery 	0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
399c766792SAndrew Jeffery 	0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
409c766792SAndrew Jeffery 	0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
419c766792SAndrew Jeffery 	0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
429c766792SAndrew Jeffery 	0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
439c766792SAndrew Jeffery 	0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
449c766792SAndrew Jeffery 	0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
459c766792SAndrew Jeffery 	0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
469c766792SAndrew Jeffery 	0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
479c766792SAndrew Jeffery 	0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
489c766792SAndrew Jeffery 	0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
499c766792SAndrew Jeffery 	0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
509c766792SAndrew Jeffery 	0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
519c766792SAndrew Jeffery 	0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
529c766792SAndrew Jeffery 	0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
539c766792SAndrew Jeffery 	0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
549c766792SAndrew Jeffery 	0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
559c766792SAndrew Jeffery 	0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
569c766792SAndrew Jeffery 	0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
579c766792SAndrew Jeffery 	0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
5837dd6a3dSAndrew Jeffery 	0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
5937dd6a3dSAndrew Jeffery };
609c766792SAndrew Jeffery 
619c766792SAndrew Jeffery /* 0x07(polynomial: x8+x2+x1+1)
629c766792SAndrew Jeffery  */
639c766792SAndrew Jeffery static const uint8_t crc8_table[] = {
649c766792SAndrew Jeffery 	0x00, 0x07, 0x0e, 0x09, 0x1c, 0x1b, 0x12, 0x15, 0x38, 0x3f, 0x36, 0x31,
659c766792SAndrew Jeffery 	0x24, 0x23, 0x2a, 0x2d, 0x70, 0x77, 0x7e, 0x79, 0x6c, 0x6b, 0x62, 0x65,
669c766792SAndrew Jeffery 	0x48, 0x4f, 0x46, 0x41, 0x54, 0x53, 0x5a, 0x5d, 0xe0, 0xe7, 0xee, 0xe9,
679c766792SAndrew Jeffery 	0xfc, 0xfb, 0xf2, 0xf5, 0xd8, 0xdf, 0xd6, 0xd1, 0xc4, 0xc3, 0xca, 0xcd,
689c766792SAndrew Jeffery 	0x90, 0x97, 0x9e, 0x99, 0x8c, 0x8b, 0x82, 0x85, 0xa8, 0xaf, 0xa6, 0xa1,
699c766792SAndrew Jeffery 	0xb4, 0xb3, 0xba, 0xbd, 0xc7, 0xc0, 0xc9, 0xce, 0xdb, 0xdc, 0xd5, 0xd2,
709c766792SAndrew Jeffery 	0xff, 0xf8, 0xf1, 0xf6, 0xe3, 0xe4, 0xed, 0xea, 0xb7, 0xb0, 0xb9, 0xbe,
719c766792SAndrew Jeffery 	0xab, 0xac, 0xa5, 0xa2, 0x8f, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9d, 0x9a,
729c766792SAndrew Jeffery 	0x27, 0x20, 0x29, 0x2e, 0x3b, 0x3c, 0x35, 0x32, 0x1f, 0x18, 0x11, 0x16,
739c766792SAndrew Jeffery 	0x03, 0x04, 0x0d, 0x0a, 0x57, 0x50, 0x59, 0x5e, 0x4b, 0x4c, 0x45, 0x42,
749c766792SAndrew Jeffery 	0x6f, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7d, 0x7a, 0x89, 0x8e, 0x87, 0x80,
759c766792SAndrew Jeffery 	0x95, 0x92, 0x9b, 0x9c, 0xb1, 0xb6, 0xbf, 0xb8, 0xad, 0xaa, 0xa3, 0xa4,
769c766792SAndrew Jeffery 	0xf9, 0xfe, 0xf7, 0xf0, 0xe5, 0xe2, 0xeb, 0xec, 0xc1, 0xc6, 0xcf, 0xc8,
779c766792SAndrew Jeffery 	0xdd, 0xda, 0xd3, 0xd4, 0x69, 0x6e, 0x67, 0x60, 0x75, 0x72, 0x7b, 0x7c,
789c766792SAndrew Jeffery 	0x51, 0x56, 0x5f, 0x58, 0x4d, 0x4a, 0x43, 0x44, 0x19, 0x1e, 0x17, 0x10,
799c766792SAndrew Jeffery 	0x05, 0x02, 0x0b, 0x0c, 0x21, 0x26, 0x2f, 0x28, 0x3d, 0x3a, 0x33, 0x34,
809c766792SAndrew Jeffery 	0x4e, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5c, 0x5b, 0x76, 0x71, 0x78, 0x7f,
819c766792SAndrew Jeffery 	0x6a, 0x6d, 0x64, 0x63, 0x3e, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2c, 0x2b,
829c766792SAndrew Jeffery 	0x06, 0x01, 0x08, 0x0f, 0x1a, 0x1d, 0x14, 0x13, 0xae, 0xa9, 0xa0, 0xa7,
839c766792SAndrew Jeffery 	0xb2, 0xb5, 0xbc, 0xbb, 0x96, 0x91, 0x98, 0x9f, 0x8a, 0x8d, 0x84, 0x83,
849c766792SAndrew Jeffery 	0xde, 0xd9, 0xd0, 0xd7, 0xc2, 0xc5, 0xcc, 0xcb, 0xe6, 0xe1, 0xe8, 0xef,
8537dd6a3dSAndrew Jeffery 	0xfa, 0xfd, 0xf4, 0xf3
8637dd6a3dSAndrew Jeffery };
879c766792SAndrew Jeffery 
889d2a1c6aSAndrew Jeffery LIBPLDM_ABI_STABLE
crc32(const void * data,size_t size)899c766792SAndrew Jeffery uint32_t crc32(const void *data, size_t size)
909c766792SAndrew Jeffery {
919c766792SAndrew Jeffery 	const uint8_t *p = data;
929c766792SAndrew Jeffery 	uint32_t crc = ~0U;
93d2c64cbdSAndrew Jeffery 	while (size--) {
949c766792SAndrew Jeffery 		crc = crc32_tab[(crc ^ *p++) & 0xff] ^ (crc >> 8);
95d2c64cbdSAndrew Jeffery 	}
969c766792SAndrew Jeffery 	return crc ^ ~0U;
979c766792SAndrew Jeffery }
989c766792SAndrew Jeffery 
999d2a1c6aSAndrew Jeffery LIBPLDM_ABI_STABLE
crc8(const void * data,size_t size)1009c766792SAndrew Jeffery uint8_t crc8(const void *data, size_t size)
1019c766792SAndrew Jeffery {
1029c766792SAndrew Jeffery 	const uint8_t *p = data;
1039c766792SAndrew Jeffery 	uint8_t crc = 0x00;
104d2c64cbdSAndrew Jeffery 	while (size--) {
1059c766792SAndrew Jeffery 		crc = crc8_table[crc ^ *p++];
106d2c64cbdSAndrew Jeffery 	}
1079c766792SAndrew Jeffery 	return crc;
1089c766792SAndrew Jeffery }
1099c766792SAndrew Jeffery 
110a8b8a810SAndrew Jeffery #define BCD_H(v)       (((v) >> 4) & 0xf)
111a8b8a810SAndrew Jeffery #define BCD_L(v)       ((v) & 0xf)
112a8b8a810SAndrew Jeffery #define AS_CHAR(digit) ((digit) + '0')
113a8b8a810SAndrew Jeffery #define INSERT_CHAR(c, b, n)                                                   \
114a8b8a810SAndrew Jeffery 	{                                                                      \
1150a05b128SAndrew Jeffery 		if ((n) > 1) {                                                 \
116a8b8a810SAndrew Jeffery 			*(b)++ = (c);                                          \
117a8b8a810SAndrew Jeffery 			(n)--;                                                 \
118a8b8a810SAndrew Jeffery 		}                                                              \
1199c766792SAndrew Jeffery 	}
120a8b8a810SAndrew Jeffery #define INSERT_INT(i, b, n) INSERT_CHAR(AS_CHAR(i), (b), (n))
1219d2a1c6aSAndrew Jeffery 
1229d2a1c6aSAndrew Jeffery LIBPLDM_ABI_STABLE
ver2str(const ver32_t * version,char * buffer,size_t buffer_size)123a8b8a810SAndrew Jeffery ssize_t ver2str(const ver32_t *version, char *buffer, size_t buffer_size)
124a8b8a810SAndrew Jeffery {
125a8b8a810SAndrew Jeffery 	ssize_t remaining;
126a8b8a810SAndrew Jeffery 	char *cursor;
127a8b8a810SAndrew Jeffery 
128d2c64cbdSAndrew Jeffery 	if (!version || !buffer) {
129a8b8a810SAndrew Jeffery 		return -1;
130d2c64cbdSAndrew Jeffery 	}
131a8b8a810SAndrew Jeffery 
132d2c64cbdSAndrew Jeffery 	if (!buffer_size) {
133a8b8a810SAndrew Jeffery 		return -1;
134d2c64cbdSAndrew Jeffery 	}
135a8b8a810SAndrew Jeffery 
136d2c64cbdSAndrew Jeffery 	if (buffer_size > SSIZE_MAX) {
137a8b8a810SAndrew Jeffery 		return -1;
138d2c64cbdSAndrew Jeffery 	}
139a8b8a810SAndrew Jeffery 
140a8b8a810SAndrew Jeffery 	cursor = buffer;
141a8b8a810SAndrew Jeffery 	remaining = (ssize_t)buffer_size;
142a8b8a810SAndrew Jeffery 
143a8b8a810SAndrew Jeffery 	if (version->major < 0xf0)
144a8b8a810SAndrew Jeffery 		INSERT_INT(BCD_H(version->major), cursor, remaining)
145a8b8a810SAndrew Jeffery 	INSERT_INT(BCD_L(version->major), cursor, remaining);
146a8b8a810SAndrew Jeffery 	INSERT_CHAR('.', cursor, remaining);
147a8b8a810SAndrew Jeffery 
148a8b8a810SAndrew Jeffery 	if (version->minor < 0xf0)
149a8b8a810SAndrew Jeffery 		INSERT_INT(BCD_H(version->minor), cursor, remaining);
150a8b8a810SAndrew Jeffery 	INSERT_INT(BCD_L(version->minor), cursor, remaining);
151a8b8a810SAndrew Jeffery 
152a8b8a810SAndrew Jeffery 	if (version->update < 0xff) {
153a8b8a810SAndrew Jeffery 		INSERT_CHAR('.', cursor, remaining);
154a8b8a810SAndrew Jeffery 		if (version->update < 0xf0)
155a8b8a810SAndrew Jeffery 			INSERT_INT(BCD_H(version->update), cursor, remaining);
156a8b8a810SAndrew Jeffery 		INSERT_INT(BCD_L(version->update), cursor, remaining);
1579c766792SAndrew Jeffery 	}
1589c766792SAndrew Jeffery 
159a8b8a810SAndrew Jeffery 	if (version->alpha)
160a8b8a810SAndrew Jeffery 		INSERT_CHAR(version->alpha, cursor, remaining);
1619c766792SAndrew Jeffery 
162a8b8a810SAndrew Jeffery 	*cursor = '\0';
163a8b8a810SAndrew Jeffery 
164a8b8a810SAndrew Jeffery 	return (ssize_t)buffer_size - remaining;
1659c766792SAndrew Jeffery }
1669c766792SAndrew Jeffery 
1679d2a1c6aSAndrew Jeffery LIBPLDM_ABI_STABLE
bcd2dec8(uint8_t bcd)1689c766792SAndrew Jeffery uint8_t bcd2dec8(uint8_t bcd)
1699c766792SAndrew Jeffery {
1703c016185SAndrew Jeffery 	return (bcd >> 4) * 10 + (bcd & 0x0f);
1719c766792SAndrew Jeffery }
1729c766792SAndrew Jeffery 
1739d2a1c6aSAndrew Jeffery LIBPLDM_ABI_STABLE
dec2bcd8(uint8_t dec)1749c766792SAndrew Jeffery uint8_t dec2bcd8(uint8_t dec)
1759c766792SAndrew Jeffery {
176e21df505SAndrew Jeffery 	return ((dec / 10) << 4) + (dec % 10);
1779c766792SAndrew Jeffery }
1789c766792SAndrew Jeffery 
1799d2a1c6aSAndrew Jeffery LIBPLDM_ABI_STABLE
bcd2dec16(uint16_t bcd)1809c766792SAndrew Jeffery uint16_t bcd2dec16(uint16_t bcd)
1819c766792SAndrew Jeffery {
1829c766792SAndrew Jeffery 	return bcd2dec8(bcd >> 8) * 100 + bcd2dec8(bcd & 0xff);
1839c766792SAndrew Jeffery }
1849c766792SAndrew Jeffery 
1859d2a1c6aSAndrew Jeffery LIBPLDM_ABI_STABLE
dec2bcd16(uint16_t dec)1869c766792SAndrew Jeffery uint16_t dec2bcd16(uint16_t dec)
1879c766792SAndrew Jeffery {
1883ce64fb4SAndrew Jeffery 	return dec2bcd8(dec % 100) | ((uint16_t)(dec2bcd8(dec / 100)) << 8);
1899c766792SAndrew Jeffery }
1909c766792SAndrew Jeffery 
1919d2a1c6aSAndrew Jeffery LIBPLDM_ABI_STABLE
bcd2dec32(uint32_t bcd)1929c766792SAndrew Jeffery uint32_t bcd2dec32(uint32_t bcd)
1939c766792SAndrew Jeffery {
1949c766792SAndrew Jeffery 	return bcd2dec16(bcd >> 16) * 10000 + bcd2dec16(bcd & 0xffff);
1959c766792SAndrew Jeffery }
1969c766792SAndrew Jeffery 
1979d2a1c6aSAndrew Jeffery LIBPLDM_ABI_STABLE
dec2bcd32(uint32_t dec)1989c766792SAndrew Jeffery uint32_t dec2bcd32(uint32_t dec)
1999c766792SAndrew Jeffery {
2003ce64fb4SAndrew Jeffery 	return dec2bcd16(dec % 10000) |
2013ce64fb4SAndrew Jeffery 	       ((uint32_t)(dec2bcd16(dec / 10000)) << 16);
2029c766792SAndrew Jeffery }
2039c766792SAndrew Jeffery 
2049d2a1c6aSAndrew Jeffery LIBPLDM_ABI_STABLE
is_time_legal(uint8_t seconds,uint8_t minutes,uint8_t hours,uint8_t day,uint8_t month,uint16_t year)2059c766792SAndrew Jeffery bool is_time_legal(uint8_t seconds, uint8_t minutes, uint8_t hours, uint8_t day,
2069c766792SAndrew Jeffery 		   uint8_t month, uint16_t year)
2079c766792SAndrew Jeffery {
2089c766792SAndrew Jeffery 	if (month < 1 || month > 12) {
2099c766792SAndrew Jeffery 		return false;
2109c766792SAndrew Jeffery 	}
2119c766792SAndrew Jeffery 	static const int days[13] = { 0,  31, 28, 31, 30, 31, 30,
2129c766792SAndrew Jeffery 				      31, 31, 30, 31, 30, 31 };
2139c766792SAndrew Jeffery 	int rday = days[month];
2149c766792SAndrew Jeffery 	if (month == 2 &&
2159c766792SAndrew Jeffery 	    ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))) {
2169c766792SAndrew Jeffery 		rday += 1;
2179c766792SAndrew Jeffery 	}
2189c766792SAndrew Jeffery 	if (year < 1970 || day < 1 || day > rday || seconds > 59 ||
2199c766792SAndrew Jeffery 	    minutes > 59 || hours > 23) {
2209c766792SAndrew Jeffery 		return false;
2219c766792SAndrew Jeffery 	}
2229c766792SAndrew Jeffery 	return true;
2239c766792SAndrew Jeffery }
2249c766792SAndrew Jeffery 
2259d2a1c6aSAndrew Jeffery LIBPLDM_ABI_STABLE
is_transfer_flag_valid(uint8_t transfer_flag)2269c766792SAndrew Jeffery bool is_transfer_flag_valid(uint8_t transfer_flag)
2279c766792SAndrew Jeffery {
2289c766792SAndrew Jeffery 	switch (transfer_flag) {
2299c766792SAndrew Jeffery 	case PLDM_START:
2309c766792SAndrew Jeffery 	case PLDM_MIDDLE:
2319c766792SAndrew Jeffery 	case PLDM_END:
2329c766792SAndrew Jeffery 	case PLDM_START_AND_END:
2339c766792SAndrew Jeffery 		return true;
2349c766792SAndrew Jeffery 
2359c766792SAndrew Jeffery 	default:
2369c766792SAndrew Jeffery 		return false;
2379c766792SAndrew Jeffery 	}
2389c766792SAndrew Jeffery }
239