]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
e11938ea JH |
2 | /* |
3 | * Copyright 2011 Calxeda, Inc. | |
e11938ea JH |
4 | */ |
5 | ||
89c8230d | 6 | #include <common.h> |
09140113 | 7 | #include <command.h> |
3adae642 | 8 | #include <efi_api.h> |
9fb625ce | 9 | #include <env.h> |
90526e9f | 10 | #include <rand.h> |
1045315d | 11 | #include <time.h> |
ba06b3c5 | 12 | #include <uuid.h> |
e11938ea | 13 | #include <linux/ctype.h> |
a96a0e61 PM |
14 | #include <errno.h> |
15 | #include <common.h> | |
d718ded0 PM |
16 | #include <asm/io.h> |
17 | #include <part_efi.h> | |
18 | #include <malloc.h> | |
92fdad28 MB |
19 | #include <dm/uclass.h> |
20 | #include <rng.h> | |
e11938ea JH |
21 | |
22 | /* | |
a96a0e61 PM |
23 | * UUID - Universally Unique IDentifier - 128 bits unique number. |
24 | * There are 5 versions and one variant of UUID defined by RFC4122 | |
4e4815fe PM |
25 | * specification. A UUID contains a set of fields. The set varies |
26 | * depending on the version of the UUID, as shown below: | |
27 | * - time, MAC address(v1), | |
28 | * - user ID(v2), | |
29 | * - MD5 of name or URL(v3), | |
30 | * - random data(v4), | |
31 | * - SHA-1 of name or URL(v5), | |
32 | * | |
33 | * Layout of UUID: | |
34 | * timestamp - 60-bit: time_low, time_mid, time_hi_and_version | |
35 | * version - 4 bit (bit 4 through 7 of the time_hi_and_version) | |
36 | * clock seq - 14 bit: clock_seq_hi_and_reserved, clock_seq_low | |
37 | * variant: - bit 6 and 7 of clock_seq_hi_and_reserved | |
38 | * node - 48 bit | |
39 | * | |
40 | * source: https://www.ietf.org/rfc/rfc4122.txt | |
a96a0e61 PM |
41 | * |
42 | * UUID binary format (16 bytes): | |
43 | * | |
44 | * 4B-2B-2B-2B-6B (big endian - network byte order) | |
45 | * | |
46 | * UUID string is 36 length of characters (36 bytes): | |
47 | * | |
48 | * 0 9 14 19 24 | |
49 | * xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx | |
50 | * be be be be be | |
51 | * | |
52 | * where x is a hexadecimal character. Fields are separated by '-'s. | |
53 | * When converting to a binary UUID, le means the field should be converted | |
54 | * to little endian and be means it should be converted to big endian. | |
e11938ea | 55 | * |
a96a0e61 PM |
56 | * UUID is also used as GUID (Globally Unique Identifier) with the same binary |
57 | * format but it differs in string format like below. | |
e11938ea | 58 | * |
a96a0e61 | 59 | * GUID: |
e11938ea JH |
60 | * 0 9 14 19 24 |
61 | * xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx | |
62 | * le le le be be | |
a96a0e61 PM |
63 | * |
64 | * GUID is used e.g. in GPT (GUID Partition Table) as a partiions unique id. | |
e11938ea | 65 | */ |
e11938ea JH |
66 | int uuid_str_valid(const char *uuid) |
67 | { | |
68 | int i, valid; | |
69 | ||
70 | if (uuid == NULL) | |
71 | return 0; | |
72 | ||
73 | for (i = 0, valid = 1; uuid[i] && valid; i++) { | |
74 | switch (i) { | |
75 | case 8: case 13: case 18: case 23: | |
76 | valid = (uuid[i] == '-'); | |
77 | break; | |
78 | default: | |
79 | valid = isxdigit(uuid[i]); | |
80 | break; | |
81 | } | |
82 | } | |
83 | ||
d718ded0 | 84 | if (i != UUID_STR_LEN || !valid) |
e11938ea JH |
85 | return 0; |
86 | ||
87 | return 1; | |
88 | } | |
89 | ||
bcb41dca PD |
90 | static const struct { |
91 | const char *string; | |
92 | efi_guid_t guid; | |
93 | } list_guid[] = { | |
c1528f32 | 94 | #ifdef CONFIG_PARTITION_TYPE_GUID |
bcb41dca PD |
95 | {"system", PARTITION_SYSTEM_GUID}, |
96 | {"mbr", LEGACY_MBR_PARTITION_GUID}, | |
97 | {"msft", PARTITION_MSFT_RESERVED_GUID}, | |
98 | {"data", PARTITION_BASIC_DATA_GUID}, | |
99 | {"linux", PARTITION_LINUX_FILE_SYSTEM_DATA_GUID}, | |
100 | {"raid", PARTITION_LINUX_RAID_GUID}, | |
101 | {"swap", PARTITION_LINUX_SWAP_GUID}, | |
c0364ce1 RV |
102 | {"lvm", PARTITION_LINUX_LVM_GUID}, |
103 | {"u-boot-env", PARTITION_U_BOOT_ENVIRONMENT}, | |
c1528f32 | 104 | #endif |
3adae642 HS |
105 | #ifdef CONFIG_CMD_EFIDEBUG |
106 | { | |
107 | "Device Path", | |
108 | EFI_DEVICE_PATH_PROTOCOL_GUID, | |
109 | }, | |
110 | { | |
111 | "Device Path To Text", | |
112 | EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID, | |
113 | }, | |
114 | { | |
115 | "Device Path Utilities", | |
116 | EFI_DEVICE_PATH_UTILITIES_PROTOCOL_GUID, | |
117 | }, | |
118 | { | |
119 | "Unicode Collation 2", | |
120 | EFI_UNICODE_COLLATION_PROTOCOL2_GUID, | |
121 | }, | |
122 | { | |
123 | "Driver Binding", | |
124 | EFI_DRIVER_BINDING_PROTOCOL_GUID, | |
125 | }, | |
126 | { | |
127 | "Simple Text Input", | |
128 | EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID, | |
129 | }, | |
130 | { | |
131 | "Simple Text Input Ex", | |
132 | EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID, | |
133 | }, | |
134 | { | |
135 | "Simple Text Output", | |
136 | EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID, | |
137 | }, | |
138 | { | |
139 | "Block IO", | |
140 | EFI_BLOCK_IO_PROTOCOL_GUID, | |
141 | }, | |
142 | { | |
143 | "Simple File System", | |
144 | EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID, | |
145 | }, | |
146 | { | |
147 | "Loaded Image", | |
148 | EFI_LOADED_IMAGE_PROTOCOL_GUID, | |
149 | }, | |
150 | { | |
151 | "Graphics Output", | |
152 | EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID, | |
153 | }, | |
154 | { | |
155 | "HII String", | |
156 | EFI_HII_STRING_PROTOCOL_GUID, | |
157 | }, | |
158 | { | |
159 | "HII Database", | |
160 | EFI_HII_DATABASE_PROTOCOL_GUID, | |
161 | }, | |
162 | { | |
163 | "HII Config Routing", | |
164 | EFI_HII_CONFIG_ROUTING_PROTOCOL_GUID, | |
165 | }, | |
166 | { | |
167 | "Load File2", | |
168 | EFI_LOAD_FILE2_PROTOCOL_GUID, | |
169 | }, | |
170 | { | |
171 | "Random Number Generator", | |
172 | EFI_RNG_PROTOCOL_GUID, | |
173 | }, | |
174 | { | |
175 | "Simple Network", | |
176 | EFI_SIMPLE_NETWORK_PROTOCOL_GUID, | |
177 | }, | |
178 | { | |
179 | "PXE Base Code", | |
180 | EFI_PXE_BASE_CODE_PROTOCOL_GUID, | |
181 | }, | |
182 | { | |
183 | "Device-Tree Fixup", | |
184 | EFI_DT_FIXUP_PROTOCOL_GUID, | |
185 | }, | |
38040a63 HS |
186 | { |
187 | "TCG2", | |
188 | EFI_TCG2_PROTOCOL_GUID, | |
189 | }, | |
3adae642 HS |
190 | { |
191 | "System Partition", | |
192 | PARTITION_SYSTEM_GUID | |
193 | }, | |
194 | { | |
195 | "Firmware Management", | |
196 | EFI_FIRMWARE_MANAGEMENT_PROTOCOL_GUID | |
197 | }, | |
198 | /* Configuration table GUIDs */ | |
199 | { | |
200 | "ACPI table", | |
201 | EFI_ACPI_TABLE_GUID, | |
202 | }, | |
203 | { | |
204 | "EFI System Resource Table", | |
205 | EFI_SYSTEM_RESOURCE_TABLE_GUID, | |
206 | }, | |
207 | { | |
208 | "device tree", | |
209 | EFI_FDT_GUID, | |
210 | }, | |
211 | { | |
212 | "SMBIOS table", | |
213 | SMBIOS_TABLE_GUID, | |
214 | }, | |
215 | { | |
216 | "Runtime properties", | |
217 | EFI_RT_PROPERTIES_TABLE_GUID, | |
218 | }, | |
219 | { | |
220 | "TCG2 Final Events Table", | |
221 | EFI_TCG2_FINAL_EVENTS_TABLE_GUID, | |
222 | }, | |
8d4c4265 HS |
223 | #ifdef CONFIG_EFI_RISCV_BOOT_PROTOCOL |
224 | { | |
225 | "RISC-V Boot", | |
226 | RISCV_EFI_BOOT_PROTOCOL_GUID, | |
227 | }, | |
3adae642 | 228 | #endif |
8d4c4265 | 229 | #endif /* CONFIG_CMD_EFIDEBUG */ |
983a5a2e HS |
230 | #ifdef CONFIG_CMD_NVEDIT_EFI |
231 | /* signature database */ | |
232 | { | |
233 | "EFI_GLOBAL_VARIABLE_GUID", | |
234 | EFI_GLOBAL_VARIABLE_GUID, | |
235 | }, | |
236 | { | |
237 | "EFI_IMAGE_SECURITY_DATABASE_GUID", | |
238 | EFI_IMAGE_SECURITY_DATABASE_GUID, | |
239 | }, | |
240 | /* certificate types */ | |
241 | { | |
242 | "EFI_CERT_SHA256_GUID", | |
243 | EFI_CERT_SHA256_GUID, | |
244 | }, | |
245 | { | |
246 | "EFI_CERT_X509_GUID", | |
247 | EFI_CERT_X509_GUID, | |
248 | }, | |
249 | { | |
250 | "EFI_CERT_TYPE_PKCS7_GUID", | |
251 | EFI_CERT_TYPE_PKCS7_GUID, | |
252 | }, | |
253 | #endif | |
bcb41dca PD |
254 | }; |
255 | ||
256 | /* | |
257 | * uuid_guid_get_bin() - this function get GUID bin for string | |
258 | * | |
259 | * @param guid_str - pointer to partition type string | |
260 | * @param guid_bin - pointer to allocated array for big endian output [16B] | |
261 | */ | |
262 | int uuid_guid_get_bin(const char *guid_str, unsigned char *guid_bin) | |
263 | { | |
264 | int i; | |
265 | ||
266 | for (i = 0; i < ARRAY_SIZE(list_guid); i++) { | |
267 | if (!strcmp(list_guid[i].string, guid_str)) { | |
268 | memcpy(guid_bin, &list_guid[i].guid, 16); | |
269 | return 0; | |
270 | } | |
271 | } | |
272 | return -ENODEV; | |
273 | } | |
274 | ||
275 | /* | |
276 | * uuid_guid_get_str() - this function get string for GUID. | |
277 | * | |
278 | * @param guid_bin - pointer to string with partition type guid [16B] | |
31ce367c RV |
279 | * |
280 | * Returns NULL if the type GUID is not known. | |
bcb41dca | 281 | */ |
31ce367c | 282 | const char *uuid_guid_get_str(const unsigned char *guid_bin) |
bcb41dca PD |
283 | { |
284 | int i; | |
285 | ||
bcb41dca PD |
286 | for (i = 0; i < ARRAY_SIZE(list_guid); i++) { |
287 | if (!memcmp(list_guid[i].guid.b, guid_bin, 16)) { | |
31ce367c | 288 | return list_guid[i].string; |
bcb41dca PD |
289 | } |
290 | } | |
31ce367c | 291 | return NULL; |
bcb41dca | 292 | } |
bcb41dca | 293 | |
d718ded0 PM |
294 | /* |
295 | * uuid_str_to_bin() - convert string UUID or GUID to big endian binary data. | |
296 | * | |
bcb41dca | 297 | * @param uuid_str - pointer to UUID or GUID string [37B] or GUID shorcut |
d718ded0 PM |
298 | * @param uuid_bin - pointer to allocated array for big endian output [16B] |
299 | * @str_format - UUID string format: 0 - UUID; 1 - GUID | |
300 | */ | |
2c2ca207 SG |
301 | int uuid_str_to_bin(const char *uuid_str, unsigned char *uuid_bin, |
302 | int str_format) | |
e11938ea JH |
303 | { |
304 | uint16_t tmp16; | |
305 | uint32_t tmp32; | |
306 | uint64_t tmp64; | |
307 | ||
bcb41dca PD |
308 | if (!uuid_str_valid(uuid_str)) { |
309 | #ifdef CONFIG_PARTITION_TYPE_GUID | |
310 | if (!uuid_guid_get_bin(uuid_str, uuid_bin)) | |
311 | return 0; | |
312 | #endif | |
a96a0e61 | 313 | return -EINVAL; |
bcb41dca | 314 | } |
a96a0e61 | 315 | |
d718ded0 | 316 | if (str_format == UUID_STR_FORMAT_STD) { |
7e5f460e | 317 | tmp32 = cpu_to_be32(hextoul(uuid_str, NULL)); |
d718ded0 | 318 | memcpy(uuid_bin, &tmp32, 4); |
e11938ea | 319 | |
7e5f460e | 320 | tmp16 = cpu_to_be16(hextoul(uuid_str + 9, NULL)); |
d718ded0 | 321 | memcpy(uuid_bin + 4, &tmp16, 2); |
e11938ea | 322 | |
7e5f460e | 323 | tmp16 = cpu_to_be16(hextoul(uuid_str + 14, NULL)); |
d718ded0 PM |
324 | memcpy(uuid_bin + 6, &tmp16, 2); |
325 | } else { | |
7e5f460e | 326 | tmp32 = cpu_to_le32(hextoul(uuid_str, NULL)); |
d718ded0 | 327 | memcpy(uuid_bin, &tmp32, 4); |
e11938ea | 328 | |
7e5f460e | 329 | tmp16 = cpu_to_le16(hextoul(uuid_str + 9, NULL)); |
d718ded0 | 330 | memcpy(uuid_bin + 4, &tmp16, 2); |
e11938ea | 331 | |
7e5f460e | 332 | tmp16 = cpu_to_le16(hextoul(uuid_str + 14, NULL)); |
d718ded0 PM |
333 | memcpy(uuid_bin + 6, &tmp16, 2); |
334 | } | |
335 | ||
7e5f460e | 336 | tmp16 = cpu_to_be16(hextoul(uuid_str + 19, NULL)); |
d718ded0 | 337 | memcpy(uuid_bin + 8, &tmp16, 2); |
e11938ea | 338 | |
d718ded0 PM |
339 | tmp64 = cpu_to_be64(simple_strtoull(uuid_str + 24, NULL, 16)); |
340 | memcpy(uuid_bin + 10, (char *)&tmp64 + 2, 6); | |
a96a0e61 PM |
341 | |
342 | return 0; | |
343 | } | |
344 | ||
d718ded0 PM |
345 | /* |
346 | * uuid_bin_to_str() - convert big endian binary data to string UUID or GUID. | |
347 | * | |
3bad256f HS |
348 | * @param uuid_bin: pointer to binary data of UUID (big endian) [16B] |
349 | * @param uuid_str: pointer to allocated array for output string [37B] | |
350 | * @str_format: bit 0: 0 - UUID; 1 - GUID | |
351 | * bit 1: 0 - lower case; 2 - upper case | |
d718ded0 | 352 | */ |
2c2ca207 SG |
353 | void uuid_bin_to_str(const unsigned char *uuid_bin, char *uuid_str, |
354 | int str_format) | |
a96a0e61 | 355 | { |
d718ded0 PM |
356 | const u8 uuid_char_order[UUID_BIN_LEN] = {0, 1, 2, 3, 4, 5, 6, 7, 8, |
357 | 9, 10, 11, 12, 13, 14, 15}; | |
358 | const u8 guid_char_order[UUID_BIN_LEN] = {3, 2, 1, 0, 5, 4, 7, 6, 8, | |
359 | 9, 10, 11, 12, 13, 14, 15}; | |
360 | const u8 *char_order; | |
3bad256f | 361 | const char *format; |
a96a0e61 PM |
362 | int i; |
363 | ||
d718ded0 PM |
364 | /* |
365 | * UUID and GUID bin data - always in big endian: | |
366 | * 4B-2B-2B-2B-6B | |
367 | * be be be be be | |
368 | */ | |
3bad256f HS |
369 | if (str_format & UUID_STR_FORMAT_GUID) |
370 | char_order = guid_char_order; | |
371 | else | |
d718ded0 | 372 | char_order = uuid_char_order; |
3bad256f HS |
373 | if (str_format & UUID_STR_UPPER_CASE) |
374 | format = "%02X"; | |
d718ded0 | 375 | else |
3bad256f | 376 | format = "%02x"; |
d718ded0 | 377 | |
a96a0e61 | 378 | for (i = 0; i < 16; i++) { |
3bad256f | 379 | sprintf(uuid_str, format, uuid_bin[char_order[i]]); |
d718ded0 | 380 | uuid_str += 2; |
a96a0e61 PM |
381 | switch (i) { |
382 | case 3: | |
383 | case 5: | |
384 | case 7: | |
385 | case 9: | |
d718ded0 | 386 | *uuid_str++ = '-'; |
a96a0e61 PM |
387 | break; |
388 | } | |
389 | } | |
e11938ea | 390 | } |
4e4815fe PM |
391 | |
392 | /* | |
393 | * gen_rand_uuid() - this function generates a random binary UUID version 4. | |
394 | * In this version all fields beside 4 bits of version and | |
395 | * 2 bits of variant are randomly generated. | |
396 | * | |
397 | * @param uuid_bin - pointer to allocated array [16B]. Output is in big endian. | |
398 | */ | |
89c8230d | 399 | #if defined(CONFIG_RANDOM_UUID) || defined(CONFIG_CMD_UUID) |
4e4815fe PM |
400 | void gen_rand_uuid(unsigned char *uuid_bin) |
401 | { | |
a1b633df HS |
402 | u32 ptr[4]; |
403 | struct uuid *uuid = (struct uuid *)ptr; | |
92fdad28 MB |
404 | int i, ret; |
405 | struct udevice *devp; | |
406 | u32 randv = 0; | |
407 | ||
408 | if (IS_ENABLED(CONFIG_DM_RNG)) { | |
409 | ret = uclass_get_device(UCLASS_RNG, 0, &devp); | |
70a9f4d2 | 410 | if (!ret) { |
92fdad28 MB |
411 | ret = dm_rng_read(devp, &randv, sizeof(randv)); |
412 | if (ret < 0) | |
413 | randv = 0; | |
414 | } | |
415 | } | |
416 | if (randv) | |
417 | srand(randv); | |
418 | else | |
419 | srand(get_ticks() + rand()); | |
4ccf678f | 420 | |
4e4815fe | 421 | /* Set all fields randomly */ |
a1b633df HS |
422 | for (i = 0; i < 4; i++) |
423 | ptr[i] = rand(); | |
4e4815fe | 424 | |
a1b633df | 425 | clrsetbits_be16(&uuid->time_hi_and_version, |
4e4815fe PM |
426 | UUID_VERSION_MASK, |
427 | UUID_VERSION << UUID_VERSION_SHIFT); | |
428 | ||
a1b633df | 429 | clrsetbits_8(&uuid->clock_seq_hi_and_reserved, |
4e4815fe PM |
430 | UUID_VARIANT_MASK, |
431 | UUID_VARIANT << UUID_VARIANT_SHIFT); | |
432 | ||
a1b633df | 433 | memcpy(uuid_bin, uuid, 16); |
4e4815fe PM |
434 | } |
435 | ||
436 | /* | |
437 | * gen_rand_uuid_str() - this function generates UUID v4 (random) in two string | |
438 | * formats UUID or GUID. | |
439 | * | |
440 | * @param uuid_str - pointer to allocated array [37B]. | |
441 | * @param - uuid output type: UUID - 0, GUID - 1 | |
442 | */ | |
443 | void gen_rand_uuid_str(char *uuid_str, int str_format) | |
444 | { | |
445 | unsigned char uuid_bin[UUID_BIN_LEN]; | |
446 | ||
447 | /* Generate UUID (big endian) */ | |
448 | gen_rand_uuid(uuid_bin); | |
449 | ||
450 | /* Convert UUID bin to UUID or GUID formated STRING */ | |
451 | uuid_bin_to_str(uuid_bin, uuid_str, str_format); | |
452 | } | |
89c8230d | 453 | |
05f6da3f | 454 | #if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_CMD_UUID) |
09140113 | 455 | int do_uuid(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) |
89c8230d PM |
456 | { |
457 | char uuid[UUID_STR_LEN + 1]; | |
458 | int str_format; | |
459 | ||
460 | if (!strcmp(argv[0], "uuid")) | |
461 | str_format = UUID_STR_FORMAT_STD; | |
462 | else | |
463 | str_format = UUID_STR_FORMAT_GUID; | |
464 | ||
465 | if (argc > 2) | |
466 | return CMD_RET_USAGE; | |
467 | ||
468 | gen_rand_uuid_str(uuid, str_format); | |
469 | ||
470 | if (argc == 1) | |
471 | printf("%s\n", uuid); | |
472 | else | |
382bee57 | 473 | env_set(argv[1], uuid); |
89c8230d PM |
474 | |
475 | return CMD_RET_SUCCESS; | |
476 | } | |
477 | ||
478 | U_BOOT_CMD(uuid, CONFIG_SYS_MAXARGS, 1, do_uuid, | |
479 | "UUID - generate random Universally Unique Identifier", | |
480 | "[<varname>]\n" | |
481 | "Argument:\n" | |
482 | "varname: for set result in a environment variable\n" | |
483 | "e.g. uuid uuid_env" | |
484 | ); | |
485 | ||
486 | U_BOOT_CMD(guid, CONFIG_SYS_MAXARGS, 1, do_uuid, | |
487 | "GUID - generate Globally Unique Identifier based on random UUID", | |
488 | "[<varname>]\n" | |
489 | "Argument:\n" | |
490 | "varname: for set result in a environment variable\n" | |
491 | "e.g. guid guid_env" | |
492 | ); | |
39206382 PM |
493 | #endif /* CONFIG_CMD_UUID */ |
494 | #endif /* CONFIG_RANDOM_UUID || CONFIG_CMD_UUID */ |