xref: /rk3399_rockchip-uboot/lib/uuid.c (revision 4e4815feae4d37032a7afce18a4c26074c51f159)
1e11938eaSJason Hobbs /*
2e11938eaSJason Hobbs  * Copyright 2011 Calxeda, Inc.
3e11938eaSJason Hobbs  *
41a459660SWolfgang Denk  * SPDX-License-Identifier:	GPL-2.0+
5e11938eaSJason Hobbs  */
6e11938eaSJason Hobbs 
7e11938eaSJason Hobbs #include <linux/ctype.h>
8a96a0e61SPrzemyslaw Marczak #include <errno.h>
9a96a0e61SPrzemyslaw Marczak #include <common.h>
10d718ded0SPrzemyslaw Marczak #include <asm/io.h>
11d718ded0SPrzemyslaw Marczak #include <part_efi.h>
12d718ded0SPrzemyslaw Marczak #include <malloc.h>
13e11938eaSJason Hobbs 
14e11938eaSJason Hobbs /*
15a96a0e61SPrzemyslaw Marczak  * UUID - Universally Unique IDentifier - 128 bits unique number.
16a96a0e61SPrzemyslaw Marczak  *        There are 5 versions and one variant of UUID defined by RFC4122
17*4e4815feSPrzemyslaw Marczak  *        specification. A UUID contains a set of fields. The set varies
18*4e4815feSPrzemyslaw Marczak  *        depending on the version of the UUID, as shown below:
19*4e4815feSPrzemyslaw Marczak  *        - time, MAC address(v1),
20*4e4815feSPrzemyslaw Marczak  *        - user ID(v2),
21*4e4815feSPrzemyslaw Marczak  *        - MD5 of name or URL(v3),
22*4e4815feSPrzemyslaw Marczak  *        - random data(v4),
23*4e4815feSPrzemyslaw Marczak  *        - SHA-1 of name or URL(v5),
24*4e4815feSPrzemyslaw Marczak  *
25*4e4815feSPrzemyslaw Marczak  * Layout of UUID:
26*4e4815feSPrzemyslaw Marczak  * timestamp - 60-bit: time_low, time_mid, time_hi_and_version
27*4e4815feSPrzemyslaw Marczak  * version   - 4 bit (bit 4 through 7 of the time_hi_and_version)
28*4e4815feSPrzemyslaw Marczak  * clock seq - 14 bit: clock_seq_hi_and_reserved, clock_seq_low
29*4e4815feSPrzemyslaw Marczak  * variant:  - bit 6 and 7 of clock_seq_hi_and_reserved
30*4e4815feSPrzemyslaw Marczak  * node      - 48 bit
31*4e4815feSPrzemyslaw Marczak  *
32*4e4815feSPrzemyslaw Marczak  * source: https://www.ietf.org/rfc/rfc4122.txt
33e11938eaSJason Hobbs  *
34a96a0e61SPrzemyslaw Marczak  * UUID binary format (16 bytes):
35a96a0e61SPrzemyslaw Marczak  *
36a96a0e61SPrzemyslaw Marczak  * 4B-2B-2B-2B-6B (big endian - network byte order)
37a96a0e61SPrzemyslaw Marczak  *
38a96a0e61SPrzemyslaw Marczak  * UUID string is 36 length of characters (36 bytes):
39e11938eaSJason Hobbs  *
40e11938eaSJason Hobbs  * 0        9    14   19   24
41e11938eaSJason Hobbs  * xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
42a96a0e61SPrzemyslaw Marczak  *    be     be   be   be       be
43a96a0e61SPrzemyslaw Marczak  *
44a96a0e61SPrzemyslaw Marczak  * where x is a hexadecimal character. Fields are separated by '-'s.
45a96a0e61SPrzemyslaw Marczak  * When converting to a binary UUID, le means the field should be converted
46a96a0e61SPrzemyslaw Marczak  * to little endian and be means it should be converted to big endian.
47a96a0e61SPrzemyslaw Marczak  *
48a96a0e61SPrzemyslaw Marczak  * UUID is also used as GUID (Globally Unique Identifier) with the same binary
49a96a0e61SPrzemyslaw Marczak  * format but it differs in string format like below.
50a96a0e61SPrzemyslaw Marczak  *
51a96a0e61SPrzemyslaw Marczak  * GUID:
52a96a0e61SPrzemyslaw Marczak  * 0        9    14   19   24
53a96a0e61SPrzemyslaw Marczak  * xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
54e11938eaSJason Hobbs  *    le     le   le   be       be
55a96a0e61SPrzemyslaw Marczak  *
56a96a0e61SPrzemyslaw Marczak  * GUID is used e.g. in GPT (GUID Partition Table) as a partiions unique id.
57e11938eaSJason Hobbs  */
58e11938eaSJason Hobbs int uuid_str_valid(const char *uuid)
59e11938eaSJason Hobbs {
60e11938eaSJason Hobbs 	int i, valid;
61e11938eaSJason Hobbs 
62e11938eaSJason Hobbs 	if (uuid == NULL)
63e11938eaSJason Hobbs 		return 0;
64e11938eaSJason Hobbs 
65e11938eaSJason Hobbs 	for (i = 0, valid = 1; uuid[i] && valid; i++) {
66e11938eaSJason Hobbs 		switch (i) {
67e11938eaSJason Hobbs 		case 8: case 13: case 18: case 23:
68e11938eaSJason Hobbs 			valid = (uuid[i] == '-');
69e11938eaSJason Hobbs 			break;
70e11938eaSJason Hobbs 		default:
71e11938eaSJason Hobbs 			valid = isxdigit(uuid[i]);
72e11938eaSJason Hobbs 			break;
73e11938eaSJason Hobbs 		}
74e11938eaSJason Hobbs 	}
75e11938eaSJason Hobbs 
76d718ded0SPrzemyslaw Marczak 	if (i != UUID_STR_LEN || !valid)
77e11938eaSJason Hobbs 		return 0;
78e11938eaSJason Hobbs 
79e11938eaSJason Hobbs 	return 1;
80e11938eaSJason Hobbs }
81e11938eaSJason Hobbs 
82d718ded0SPrzemyslaw Marczak /*
83d718ded0SPrzemyslaw Marczak  * uuid_str_to_bin() - convert string UUID or GUID to big endian binary data.
84d718ded0SPrzemyslaw Marczak  *
85d718ded0SPrzemyslaw Marczak  * @param uuid_str - pointer to UUID or GUID string [37B]
86d718ded0SPrzemyslaw Marczak  * @param uuid_bin - pointer to allocated array for big endian output [16B]
87d718ded0SPrzemyslaw Marczak  * @str_format     - UUID string format: 0 - UUID; 1 - GUID
88d718ded0SPrzemyslaw Marczak  */
89d718ded0SPrzemyslaw Marczak int uuid_str_to_bin(char *uuid_str, unsigned char *uuid_bin, int str_format)
90e11938eaSJason Hobbs {
91e11938eaSJason Hobbs 	uint16_t tmp16;
92e11938eaSJason Hobbs 	uint32_t tmp32;
93e11938eaSJason Hobbs 	uint64_t tmp64;
94e11938eaSJason Hobbs 
95d718ded0SPrzemyslaw Marczak 	if (!uuid_str_valid(uuid_str))
96a96a0e61SPrzemyslaw Marczak 		return -EINVAL;
97a96a0e61SPrzemyslaw Marczak 
98d718ded0SPrzemyslaw Marczak 	if (str_format == UUID_STR_FORMAT_STD) {
99d718ded0SPrzemyslaw Marczak 		tmp32 = cpu_to_be32(simple_strtoul(uuid_str, NULL, 16));
100d718ded0SPrzemyslaw Marczak 		memcpy(uuid_bin, &tmp32, 4);
101e11938eaSJason Hobbs 
102d718ded0SPrzemyslaw Marczak 		tmp16 = cpu_to_be16(simple_strtoul(uuid_str + 9, NULL, 16));
103d718ded0SPrzemyslaw Marczak 		memcpy(uuid_bin + 4, &tmp16, 2);
104e11938eaSJason Hobbs 
105d718ded0SPrzemyslaw Marczak 		tmp16 = cpu_to_be16(simple_strtoul(uuid_str + 14, NULL, 16));
106d718ded0SPrzemyslaw Marczak 		memcpy(uuid_bin + 6, &tmp16, 2);
107d718ded0SPrzemyslaw Marczak 	} else {
108d718ded0SPrzemyslaw Marczak 		tmp32 = cpu_to_le32(simple_strtoul(uuid_str, NULL, 16));
109d718ded0SPrzemyslaw Marczak 		memcpy(uuid_bin, &tmp32, 4);
110e11938eaSJason Hobbs 
111d718ded0SPrzemyslaw Marczak 		tmp16 = cpu_to_le16(simple_strtoul(uuid_str + 9, NULL, 16));
112d718ded0SPrzemyslaw Marczak 		memcpy(uuid_bin + 4, &tmp16, 2);
113e11938eaSJason Hobbs 
114d718ded0SPrzemyslaw Marczak 		tmp16 = cpu_to_le16(simple_strtoul(uuid_str + 14, NULL, 16));
115d718ded0SPrzemyslaw Marczak 		memcpy(uuid_bin + 6, &tmp16, 2);
116d718ded0SPrzemyslaw Marczak 	}
117e11938eaSJason Hobbs 
118d718ded0SPrzemyslaw Marczak 	tmp16 = cpu_to_be16(simple_strtoul(uuid_str + 19, NULL, 16));
119d718ded0SPrzemyslaw Marczak 	memcpy(uuid_bin + 8, &tmp16, 2);
120d718ded0SPrzemyslaw Marczak 
121d718ded0SPrzemyslaw Marczak 	tmp64 = cpu_to_be64(simple_strtoull(uuid_str + 24, NULL, 16));
122d718ded0SPrzemyslaw Marczak 	memcpy(uuid_bin + 10, (char *)&tmp64 + 2, 6);
123a96a0e61SPrzemyslaw Marczak 
124a96a0e61SPrzemyslaw Marczak 	return 0;
125a96a0e61SPrzemyslaw Marczak }
126a96a0e61SPrzemyslaw Marczak 
127d718ded0SPrzemyslaw Marczak /*
128d718ded0SPrzemyslaw Marczak  * uuid_bin_to_str() - convert big endian binary data to string UUID or GUID.
129d718ded0SPrzemyslaw Marczak  *
130d718ded0SPrzemyslaw Marczak  * @param uuid_bin - pointer to binary data of UUID (big endian) [16B]
131d718ded0SPrzemyslaw Marczak  * @param uuid_str - pointer to allocated array for output string [37B]
132d718ded0SPrzemyslaw Marczak  * @str_format     - UUID string format: 0 - UUID; 1 - GUID
133d718ded0SPrzemyslaw Marczak  */
134d718ded0SPrzemyslaw Marczak void uuid_bin_to_str(unsigned char *uuid_bin, char *uuid_str, int str_format)
135a96a0e61SPrzemyslaw Marczak {
136d718ded0SPrzemyslaw Marczak 	const u8 uuid_char_order[UUID_BIN_LEN] = {0, 1, 2, 3, 4, 5, 6, 7, 8,
137d718ded0SPrzemyslaw Marczak 						  9, 10, 11, 12, 13, 14, 15};
138d718ded0SPrzemyslaw Marczak 	const u8 guid_char_order[UUID_BIN_LEN] = {3, 2, 1, 0, 5, 4, 7, 6, 8,
139d718ded0SPrzemyslaw Marczak 						  9, 10, 11, 12, 13, 14, 15};
140d718ded0SPrzemyslaw Marczak 	const u8 *char_order;
141a96a0e61SPrzemyslaw Marczak 	int i;
142a96a0e61SPrzemyslaw Marczak 
143d718ded0SPrzemyslaw Marczak 	/*
144d718ded0SPrzemyslaw Marczak 	 * UUID and GUID bin data - always in big endian:
145d718ded0SPrzemyslaw Marczak 	 * 4B-2B-2B-2B-6B
146d718ded0SPrzemyslaw Marczak 	 * be be be be be
147d718ded0SPrzemyslaw Marczak 	 */
148d718ded0SPrzemyslaw Marczak 	if (str_format == UUID_STR_FORMAT_STD)
149d718ded0SPrzemyslaw Marczak 		char_order = uuid_char_order;
150d718ded0SPrzemyslaw Marczak 	else
151d718ded0SPrzemyslaw Marczak 		char_order = guid_char_order;
152d718ded0SPrzemyslaw Marczak 
153a96a0e61SPrzemyslaw Marczak 	for (i = 0; i < 16; i++) {
154d718ded0SPrzemyslaw Marczak 		sprintf(uuid_str, "%02x", uuid_bin[char_order[i]]);
155d718ded0SPrzemyslaw Marczak 		uuid_str += 2;
156a96a0e61SPrzemyslaw Marczak 		switch (i) {
157a96a0e61SPrzemyslaw Marczak 		case 3:
158a96a0e61SPrzemyslaw Marczak 		case 5:
159a96a0e61SPrzemyslaw Marczak 		case 7:
160a96a0e61SPrzemyslaw Marczak 		case 9:
161d718ded0SPrzemyslaw Marczak 			*uuid_str++ = '-';
162a96a0e61SPrzemyslaw Marczak 			break;
163a96a0e61SPrzemyslaw Marczak 		}
164a96a0e61SPrzemyslaw Marczak 	}
165e11938eaSJason Hobbs }
166*4e4815feSPrzemyslaw Marczak 
167*4e4815feSPrzemyslaw Marczak /*
168*4e4815feSPrzemyslaw Marczak  * gen_rand_uuid() - this function generates a random binary UUID version 4.
169*4e4815feSPrzemyslaw Marczak  *                   In this version all fields beside 4 bits of version and
170*4e4815feSPrzemyslaw Marczak  *                   2 bits of variant are randomly generated.
171*4e4815feSPrzemyslaw Marczak  *
172*4e4815feSPrzemyslaw Marczak  * @param uuid_bin - pointer to allocated array [16B]. Output is in big endian.
173*4e4815feSPrzemyslaw Marczak */
174*4e4815feSPrzemyslaw Marczak #ifdef CONFIG_RANDOM_UUID
175*4e4815feSPrzemyslaw Marczak void gen_rand_uuid(unsigned char *uuid_bin)
176*4e4815feSPrzemyslaw Marczak {
177*4e4815feSPrzemyslaw Marczak 	struct uuid uuid;
178*4e4815feSPrzemyslaw Marczak 	unsigned int *ptr = (unsigned int *)&uuid;
179*4e4815feSPrzemyslaw Marczak 	int i;
180*4e4815feSPrzemyslaw Marczak 
181*4e4815feSPrzemyslaw Marczak 	/* Set all fields randomly */
182*4e4815feSPrzemyslaw Marczak 	for (i = 0; i < sizeof(struct uuid) / sizeof(*ptr); i++)
183*4e4815feSPrzemyslaw Marczak 		*(ptr + i) = cpu_to_be32(rand());
184*4e4815feSPrzemyslaw Marczak 
185*4e4815feSPrzemyslaw Marczak 	clrsetbits_be16(&uuid.time_hi_and_version,
186*4e4815feSPrzemyslaw Marczak 			UUID_VERSION_MASK,
187*4e4815feSPrzemyslaw Marczak 			UUID_VERSION << UUID_VERSION_SHIFT);
188*4e4815feSPrzemyslaw Marczak 
189*4e4815feSPrzemyslaw Marczak 	clrsetbits_8(&uuid.clock_seq_hi_and_reserved,
190*4e4815feSPrzemyslaw Marczak 		     UUID_VARIANT_MASK,
191*4e4815feSPrzemyslaw Marczak 		     UUID_VARIANT << UUID_VARIANT_SHIFT);
192*4e4815feSPrzemyslaw Marczak 
193*4e4815feSPrzemyslaw Marczak 	memcpy(uuid_bin, &uuid, sizeof(struct uuid));
194*4e4815feSPrzemyslaw Marczak }
195*4e4815feSPrzemyslaw Marczak 
196*4e4815feSPrzemyslaw Marczak /*
197*4e4815feSPrzemyslaw Marczak  * gen_rand_uuid_str() - this function generates UUID v4 (random) in two string
198*4e4815feSPrzemyslaw Marczak  *                       formats UUID or GUID.
199*4e4815feSPrzemyslaw Marczak  *
200*4e4815feSPrzemyslaw Marczak  * @param uuid_str - pointer to allocated array [37B].
201*4e4815feSPrzemyslaw Marczak  * @param          - uuid output type: UUID - 0, GUID - 1
202*4e4815feSPrzemyslaw Marczak  */
203*4e4815feSPrzemyslaw Marczak void gen_rand_uuid_str(char *uuid_str, int str_format)
204*4e4815feSPrzemyslaw Marczak {
205*4e4815feSPrzemyslaw Marczak 	unsigned char uuid_bin[UUID_BIN_LEN];
206*4e4815feSPrzemyslaw Marczak 
207*4e4815feSPrzemyslaw Marczak 	/* Generate UUID (big endian) */
208*4e4815feSPrzemyslaw Marczak 	gen_rand_uuid(uuid_bin);
209*4e4815feSPrzemyslaw Marczak 
210*4e4815feSPrzemyslaw Marczak 	/* Convert UUID bin to UUID or GUID formated STRING  */
211*4e4815feSPrzemyslaw Marczak 	uuid_bin_to_str(uuid_bin, uuid_str, str_format);
212*4e4815feSPrzemyslaw Marczak }
213*4e4815feSPrzemyslaw Marczak #endif
214