xref: /rk3399_rockchip-uboot/lib/uuid.c (revision 89c8230dec063d894aec1a7b5c58f1dcadced738)
1e11938eaSJason Hobbs /*
2e11938eaSJason Hobbs  * Copyright 2011 Calxeda, Inc.
3e11938eaSJason Hobbs  *
41a459660SWolfgang Denk  * SPDX-License-Identifier:	GPL-2.0+
5e11938eaSJason Hobbs  */
6e11938eaSJason Hobbs 
7*89c8230dSPrzemyslaw Marczak #include <common.h>
8e11938eaSJason Hobbs #include <linux/ctype.h>
9a96a0e61SPrzemyslaw Marczak #include <errno.h>
10a96a0e61SPrzemyslaw Marczak #include <common.h>
11d718ded0SPrzemyslaw Marczak #include <asm/io.h>
12d718ded0SPrzemyslaw Marczak #include <part_efi.h>
13d718ded0SPrzemyslaw Marczak #include <malloc.h>
14e11938eaSJason Hobbs 
15e11938eaSJason Hobbs /*
16a96a0e61SPrzemyslaw Marczak  * UUID - Universally Unique IDentifier - 128 bits unique number.
17a96a0e61SPrzemyslaw Marczak  *        There are 5 versions and one variant of UUID defined by RFC4122
184e4815feSPrzemyslaw Marczak  *        specification. A UUID contains a set of fields. The set varies
194e4815feSPrzemyslaw Marczak  *        depending on the version of the UUID, as shown below:
204e4815feSPrzemyslaw Marczak  *        - time, MAC address(v1),
214e4815feSPrzemyslaw Marczak  *        - user ID(v2),
224e4815feSPrzemyslaw Marczak  *        - MD5 of name or URL(v3),
234e4815feSPrzemyslaw Marczak  *        - random data(v4),
244e4815feSPrzemyslaw Marczak  *        - SHA-1 of name or URL(v5),
254e4815feSPrzemyslaw Marczak  *
264e4815feSPrzemyslaw Marczak  * Layout of UUID:
274e4815feSPrzemyslaw Marczak  * timestamp - 60-bit: time_low, time_mid, time_hi_and_version
284e4815feSPrzemyslaw Marczak  * version   - 4 bit (bit 4 through 7 of the time_hi_and_version)
294e4815feSPrzemyslaw Marczak  * clock seq - 14 bit: clock_seq_hi_and_reserved, clock_seq_low
304e4815feSPrzemyslaw Marczak  * variant:  - bit 6 and 7 of clock_seq_hi_and_reserved
314e4815feSPrzemyslaw Marczak  * node      - 48 bit
324e4815feSPrzemyslaw Marczak  *
334e4815feSPrzemyslaw Marczak  * source: https://www.ietf.org/rfc/rfc4122.txt
34e11938eaSJason Hobbs  *
35a96a0e61SPrzemyslaw Marczak  * UUID binary format (16 bytes):
36a96a0e61SPrzemyslaw Marczak  *
37a96a0e61SPrzemyslaw Marczak  * 4B-2B-2B-2B-6B (big endian - network byte order)
38a96a0e61SPrzemyslaw Marczak  *
39a96a0e61SPrzemyslaw Marczak  * UUID string is 36 length of characters (36 bytes):
40e11938eaSJason Hobbs  *
41e11938eaSJason Hobbs  * 0        9    14   19   24
42e11938eaSJason Hobbs  * xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
43a96a0e61SPrzemyslaw Marczak  *    be     be   be   be       be
44a96a0e61SPrzemyslaw Marczak  *
45a96a0e61SPrzemyslaw Marczak  * where x is a hexadecimal character. Fields are separated by '-'s.
46a96a0e61SPrzemyslaw Marczak  * When converting to a binary UUID, le means the field should be converted
47a96a0e61SPrzemyslaw Marczak  * to little endian and be means it should be converted to big endian.
48a96a0e61SPrzemyslaw Marczak  *
49a96a0e61SPrzemyslaw Marczak  * UUID is also used as GUID (Globally Unique Identifier) with the same binary
50a96a0e61SPrzemyslaw Marczak  * format but it differs in string format like below.
51a96a0e61SPrzemyslaw Marczak  *
52a96a0e61SPrzemyslaw Marczak  * GUID:
53a96a0e61SPrzemyslaw Marczak  * 0        9    14   19   24
54a96a0e61SPrzemyslaw Marczak  * xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
55e11938eaSJason Hobbs  *    le     le   le   be       be
56a96a0e61SPrzemyslaw Marczak  *
57a96a0e61SPrzemyslaw Marczak  * GUID is used e.g. in GPT (GUID Partition Table) as a partiions unique id.
58e11938eaSJason Hobbs  */
59e11938eaSJason Hobbs int uuid_str_valid(const char *uuid)
60e11938eaSJason Hobbs {
61e11938eaSJason Hobbs 	int i, valid;
62e11938eaSJason Hobbs 
63e11938eaSJason Hobbs 	if (uuid == NULL)
64e11938eaSJason Hobbs 		return 0;
65e11938eaSJason Hobbs 
66e11938eaSJason Hobbs 	for (i = 0, valid = 1; uuid[i] && valid; i++) {
67e11938eaSJason Hobbs 		switch (i) {
68e11938eaSJason Hobbs 		case 8: case 13: case 18: case 23:
69e11938eaSJason Hobbs 			valid = (uuid[i] == '-');
70e11938eaSJason Hobbs 			break;
71e11938eaSJason Hobbs 		default:
72e11938eaSJason Hobbs 			valid = isxdigit(uuid[i]);
73e11938eaSJason Hobbs 			break;
74e11938eaSJason Hobbs 		}
75e11938eaSJason Hobbs 	}
76e11938eaSJason Hobbs 
77d718ded0SPrzemyslaw Marczak 	if (i != UUID_STR_LEN || !valid)
78e11938eaSJason Hobbs 		return 0;
79e11938eaSJason Hobbs 
80e11938eaSJason Hobbs 	return 1;
81e11938eaSJason Hobbs }
82e11938eaSJason Hobbs 
83d718ded0SPrzemyslaw Marczak /*
84d718ded0SPrzemyslaw Marczak  * uuid_str_to_bin() - convert string UUID or GUID to big endian binary data.
85d718ded0SPrzemyslaw Marczak  *
86d718ded0SPrzemyslaw Marczak  * @param uuid_str - pointer to UUID or GUID string [37B]
87d718ded0SPrzemyslaw Marczak  * @param uuid_bin - pointer to allocated array for big endian output [16B]
88d718ded0SPrzemyslaw Marczak  * @str_format     - UUID string format: 0 - UUID; 1 - GUID
89d718ded0SPrzemyslaw Marczak  */
90d718ded0SPrzemyslaw Marczak int uuid_str_to_bin(char *uuid_str, unsigned char *uuid_bin, int str_format)
91e11938eaSJason Hobbs {
92e11938eaSJason Hobbs 	uint16_t tmp16;
93e11938eaSJason Hobbs 	uint32_t tmp32;
94e11938eaSJason Hobbs 	uint64_t tmp64;
95e11938eaSJason Hobbs 
96d718ded0SPrzemyslaw Marczak 	if (!uuid_str_valid(uuid_str))
97a96a0e61SPrzemyslaw Marczak 		return -EINVAL;
98a96a0e61SPrzemyslaw Marczak 
99d718ded0SPrzemyslaw Marczak 	if (str_format == UUID_STR_FORMAT_STD) {
100d718ded0SPrzemyslaw Marczak 		tmp32 = cpu_to_be32(simple_strtoul(uuid_str, NULL, 16));
101d718ded0SPrzemyslaw Marczak 		memcpy(uuid_bin, &tmp32, 4);
102e11938eaSJason Hobbs 
103d718ded0SPrzemyslaw Marczak 		tmp16 = cpu_to_be16(simple_strtoul(uuid_str + 9, NULL, 16));
104d718ded0SPrzemyslaw Marczak 		memcpy(uuid_bin + 4, &tmp16, 2);
105e11938eaSJason Hobbs 
106d718ded0SPrzemyslaw Marczak 		tmp16 = cpu_to_be16(simple_strtoul(uuid_str + 14, NULL, 16));
107d718ded0SPrzemyslaw Marczak 		memcpy(uuid_bin + 6, &tmp16, 2);
108d718ded0SPrzemyslaw Marczak 	} else {
109d718ded0SPrzemyslaw Marczak 		tmp32 = cpu_to_le32(simple_strtoul(uuid_str, NULL, 16));
110d718ded0SPrzemyslaw Marczak 		memcpy(uuid_bin, &tmp32, 4);
111e11938eaSJason Hobbs 
112d718ded0SPrzemyslaw Marczak 		tmp16 = cpu_to_le16(simple_strtoul(uuid_str + 9, NULL, 16));
113d718ded0SPrzemyslaw Marczak 		memcpy(uuid_bin + 4, &tmp16, 2);
114e11938eaSJason Hobbs 
115d718ded0SPrzemyslaw Marczak 		tmp16 = cpu_to_le16(simple_strtoul(uuid_str + 14, NULL, 16));
116d718ded0SPrzemyslaw Marczak 		memcpy(uuid_bin + 6, &tmp16, 2);
117d718ded0SPrzemyslaw Marczak 	}
118e11938eaSJason Hobbs 
119d718ded0SPrzemyslaw Marczak 	tmp16 = cpu_to_be16(simple_strtoul(uuid_str + 19, NULL, 16));
120d718ded0SPrzemyslaw Marczak 	memcpy(uuid_bin + 8, &tmp16, 2);
121d718ded0SPrzemyslaw Marczak 
122d718ded0SPrzemyslaw Marczak 	tmp64 = cpu_to_be64(simple_strtoull(uuid_str + 24, NULL, 16));
123d718ded0SPrzemyslaw Marczak 	memcpy(uuid_bin + 10, (char *)&tmp64 + 2, 6);
124a96a0e61SPrzemyslaw Marczak 
125a96a0e61SPrzemyslaw Marczak 	return 0;
126a96a0e61SPrzemyslaw Marczak }
127a96a0e61SPrzemyslaw Marczak 
128d718ded0SPrzemyslaw Marczak /*
129d718ded0SPrzemyslaw Marczak  * uuid_bin_to_str() - convert big endian binary data to string UUID or GUID.
130d718ded0SPrzemyslaw Marczak  *
131d718ded0SPrzemyslaw Marczak  * @param uuid_bin - pointer to binary data of UUID (big endian) [16B]
132d718ded0SPrzemyslaw Marczak  * @param uuid_str - pointer to allocated array for output string [37B]
133d718ded0SPrzemyslaw Marczak  * @str_format     - UUID string format: 0 - UUID; 1 - GUID
134d718ded0SPrzemyslaw Marczak  */
135d718ded0SPrzemyslaw Marczak void uuid_bin_to_str(unsigned char *uuid_bin, char *uuid_str, int str_format)
136a96a0e61SPrzemyslaw Marczak {
137d718ded0SPrzemyslaw Marczak 	const u8 uuid_char_order[UUID_BIN_LEN] = {0, 1, 2, 3, 4, 5, 6, 7, 8,
138d718ded0SPrzemyslaw Marczak 						  9, 10, 11, 12, 13, 14, 15};
139d718ded0SPrzemyslaw Marczak 	const u8 guid_char_order[UUID_BIN_LEN] = {3, 2, 1, 0, 5, 4, 7, 6, 8,
140d718ded0SPrzemyslaw Marczak 						  9, 10, 11, 12, 13, 14, 15};
141d718ded0SPrzemyslaw Marczak 	const u8 *char_order;
142a96a0e61SPrzemyslaw Marczak 	int i;
143a96a0e61SPrzemyslaw Marczak 
144d718ded0SPrzemyslaw Marczak 	/*
145d718ded0SPrzemyslaw Marczak 	 * UUID and GUID bin data - always in big endian:
146d718ded0SPrzemyslaw Marczak 	 * 4B-2B-2B-2B-6B
147d718ded0SPrzemyslaw Marczak 	 * be be be be be
148d718ded0SPrzemyslaw Marczak 	 */
149d718ded0SPrzemyslaw Marczak 	if (str_format == UUID_STR_FORMAT_STD)
150d718ded0SPrzemyslaw Marczak 		char_order = uuid_char_order;
151d718ded0SPrzemyslaw Marczak 	else
152d718ded0SPrzemyslaw Marczak 		char_order = guid_char_order;
153d718ded0SPrzemyslaw Marczak 
154a96a0e61SPrzemyslaw Marczak 	for (i = 0; i < 16; i++) {
155d718ded0SPrzemyslaw Marczak 		sprintf(uuid_str, "%02x", uuid_bin[char_order[i]]);
156d718ded0SPrzemyslaw Marczak 		uuid_str += 2;
157a96a0e61SPrzemyslaw Marczak 		switch (i) {
158a96a0e61SPrzemyslaw Marczak 		case 3:
159a96a0e61SPrzemyslaw Marczak 		case 5:
160a96a0e61SPrzemyslaw Marczak 		case 7:
161a96a0e61SPrzemyslaw Marczak 		case 9:
162d718ded0SPrzemyslaw Marczak 			*uuid_str++ = '-';
163a96a0e61SPrzemyslaw Marczak 			break;
164a96a0e61SPrzemyslaw Marczak 		}
165a96a0e61SPrzemyslaw Marczak 	}
166e11938eaSJason Hobbs }
1674e4815feSPrzemyslaw Marczak 
1684e4815feSPrzemyslaw Marczak /*
1694e4815feSPrzemyslaw Marczak  * gen_rand_uuid() - this function generates a random binary UUID version 4.
1704e4815feSPrzemyslaw Marczak  *                   In this version all fields beside 4 bits of version and
1714e4815feSPrzemyslaw Marczak  *                   2 bits of variant are randomly generated.
1724e4815feSPrzemyslaw Marczak  *
1734e4815feSPrzemyslaw Marczak  * @param uuid_bin - pointer to allocated array [16B]. Output is in big endian.
1744e4815feSPrzemyslaw Marczak */
175*89c8230dSPrzemyslaw Marczak #if defined(CONFIG_RANDOM_UUID) || defined(CONFIG_CMD_UUID)
1764e4815feSPrzemyslaw Marczak void gen_rand_uuid(unsigned char *uuid_bin)
1774e4815feSPrzemyslaw Marczak {
1784e4815feSPrzemyslaw Marczak 	struct uuid uuid;
1794e4815feSPrzemyslaw Marczak 	unsigned int *ptr = (unsigned int *)&uuid;
1804e4815feSPrzemyslaw Marczak 	int i;
1814e4815feSPrzemyslaw Marczak 
1824e4815feSPrzemyslaw Marczak 	/* Set all fields randomly */
1834e4815feSPrzemyslaw Marczak 	for (i = 0; i < sizeof(struct uuid) / sizeof(*ptr); i++)
1844e4815feSPrzemyslaw Marczak 		*(ptr + i) = cpu_to_be32(rand());
1854e4815feSPrzemyslaw Marczak 
1864e4815feSPrzemyslaw Marczak 	clrsetbits_be16(&uuid.time_hi_and_version,
1874e4815feSPrzemyslaw Marczak 			UUID_VERSION_MASK,
1884e4815feSPrzemyslaw Marczak 			UUID_VERSION << UUID_VERSION_SHIFT);
1894e4815feSPrzemyslaw Marczak 
1904e4815feSPrzemyslaw Marczak 	clrsetbits_8(&uuid.clock_seq_hi_and_reserved,
1914e4815feSPrzemyslaw Marczak 		     UUID_VARIANT_MASK,
1924e4815feSPrzemyslaw Marczak 		     UUID_VARIANT << UUID_VARIANT_SHIFT);
1934e4815feSPrzemyslaw Marczak 
1944e4815feSPrzemyslaw Marczak 	memcpy(uuid_bin, &uuid, sizeof(struct uuid));
1954e4815feSPrzemyslaw Marczak }
1964e4815feSPrzemyslaw Marczak 
1974e4815feSPrzemyslaw Marczak /*
1984e4815feSPrzemyslaw Marczak  * gen_rand_uuid_str() - this function generates UUID v4 (random) in two string
1994e4815feSPrzemyslaw Marczak  *                       formats UUID or GUID.
2004e4815feSPrzemyslaw Marczak  *
2014e4815feSPrzemyslaw Marczak  * @param uuid_str - pointer to allocated array [37B].
2024e4815feSPrzemyslaw Marczak  * @param          - uuid output type: UUID - 0, GUID - 1
2034e4815feSPrzemyslaw Marczak  */
2044e4815feSPrzemyslaw Marczak void gen_rand_uuid_str(char *uuid_str, int str_format)
2054e4815feSPrzemyslaw Marczak {
2064e4815feSPrzemyslaw Marczak 	unsigned char uuid_bin[UUID_BIN_LEN];
2074e4815feSPrzemyslaw Marczak 
2084e4815feSPrzemyslaw Marczak 	/* Generate UUID (big endian) */
2094e4815feSPrzemyslaw Marczak 	gen_rand_uuid(uuid_bin);
2104e4815feSPrzemyslaw Marczak 
2114e4815feSPrzemyslaw Marczak 	/* Convert UUID bin to UUID or GUID formated STRING  */
2124e4815feSPrzemyslaw Marczak 	uuid_bin_to_str(uuid_bin, uuid_str, str_format);
2134e4815feSPrzemyslaw Marczak }
214*89c8230dSPrzemyslaw Marczak 
215*89c8230dSPrzemyslaw Marczak #ifdef CONFIG_CMD_UUID
216*89c8230dSPrzemyslaw Marczak int do_uuid(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
217*89c8230dSPrzemyslaw Marczak {
218*89c8230dSPrzemyslaw Marczak 	char uuid[UUID_STR_LEN + 1];
219*89c8230dSPrzemyslaw Marczak 	int str_format;
220*89c8230dSPrzemyslaw Marczak 
221*89c8230dSPrzemyslaw Marczak 	if (!strcmp(argv[0], "uuid"))
222*89c8230dSPrzemyslaw Marczak 		str_format = UUID_STR_FORMAT_STD;
223*89c8230dSPrzemyslaw Marczak 	else
224*89c8230dSPrzemyslaw Marczak 		str_format = UUID_STR_FORMAT_GUID;
225*89c8230dSPrzemyslaw Marczak 
226*89c8230dSPrzemyslaw Marczak 	if (argc > 2)
227*89c8230dSPrzemyslaw Marczak 		return CMD_RET_USAGE;
228*89c8230dSPrzemyslaw Marczak 
229*89c8230dSPrzemyslaw Marczak 	gen_rand_uuid_str(uuid, str_format);
230*89c8230dSPrzemyslaw Marczak 
231*89c8230dSPrzemyslaw Marczak 	if (argc == 1)
232*89c8230dSPrzemyslaw Marczak 		printf("%s\n", uuid);
233*89c8230dSPrzemyslaw Marczak 	else
234*89c8230dSPrzemyslaw Marczak 		setenv(argv[1], uuid);
235*89c8230dSPrzemyslaw Marczak 
236*89c8230dSPrzemyslaw Marczak 	return CMD_RET_SUCCESS;
237*89c8230dSPrzemyslaw Marczak }
238*89c8230dSPrzemyslaw Marczak 
239*89c8230dSPrzemyslaw Marczak U_BOOT_CMD(uuid, CONFIG_SYS_MAXARGS, 1, do_uuid,
240*89c8230dSPrzemyslaw Marczak 	   "UUID - generate random Universally Unique Identifier",
241*89c8230dSPrzemyslaw Marczak 	   "[<varname>]\n"
242*89c8230dSPrzemyslaw Marczak 	   "Argument:\n"
243*89c8230dSPrzemyslaw Marczak 	   "varname: for set result in a environment variable\n"
244*89c8230dSPrzemyslaw Marczak 	   "e.g. uuid uuid_env"
245*89c8230dSPrzemyslaw Marczak );
246*89c8230dSPrzemyslaw Marczak 
247*89c8230dSPrzemyslaw Marczak U_BOOT_CMD(guid, CONFIG_SYS_MAXARGS, 1, do_uuid,
248*89c8230dSPrzemyslaw Marczak 	   "GUID - generate Globally Unique Identifier based on random UUID",
249*89c8230dSPrzemyslaw Marczak 	   "[<varname>]\n"
250*89c8230dSPrzemyslaw Marczak 	   "Argument:\n"
251*89c8230dSPrzemyslaw Marczak 	   "varname: for set result in a environment variable\n"
252*89c8230dSPrzemyslaw Marczak 	   "e.g. guid guid_env"
253*89c8230dSPrzemyslaw Marczak );
254*89c8230dSPrzemyslaw Marczak #endif
2554e4815feSPrzemyslaw Marczak #endif
256