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> 10*d718ded0SPrzemyslaw Marczak #include <asm/io.h> 11*d718ded0SPrzemyslaw Marczak #include <part_efi.h> 12*d718ded0SPrzemyslaw 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 17a96a0e61SPrzemyslaw Marczak * specification. Depends on version uuid number base on a time, 18a96a0e61SPrzemyslaw Marczak * host name, MAC address or random data. 19e11938eaSJason Hobbs * 20a96a0e61SPrzemyslaw Marczak * UUID binary format (16 bytes): 21a96a0e61SPrzemyslaw Marczak * 22a96a0e61SPrzemyslaw Marczak * 4B-2B-2B-2B-6B (big endian - network byte order) 23a96a0e61SPrzemyslaw Marczak * 24a96a0e61SPrzemyslaw Marczak * UUID string is 36 length of characters (36 bytes): 25e11938eaSJason Hobbs * 26e11938eaSJason Hobbs * 0 9 14 19 24 27e11938eaSJason Hobbs * xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 28a96a0e61SPrzemyslaw Marczak * be be be be be 29a96a0e61SPrzemyslaw Marczak * 30a96a0e61SPrzemyslaw Marczak * where x is a hexadecimal character. Fields are separated by '-'s. 31a96a0e61SPrzemyslaw Marczak * When converting to a binary UUID, le means the field should be converted 32a96a0e61SPrzemyslaw Marczak * to little endian and be means it should be converted to big endian. 33a96a0e61SPrzemyslaw Marczak * 34a96a0e61SPrzemyslaw Marczak * UUID is also used as GUID (Globally Unique Identifier) with the same binary 35a96a0e61SPrzemyslaw Marczak * format but it differs in string format like below. 36a96a0e61SPrzemyslaw Marczak * 37a96a0e61SPrzemyslaw Marczak * GUID: 38a96a0e61SPrzemyslaw Marczak * 0 9 14 19 24 39a96a0e61SPrzemyslaw Marczak * xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 40e11938eaSJason Hobbs * le le le be be 41a96a0e61SPrzemyslaw Marczak * 42a96a0e61SPrzemyslaw Marczak * GUID is used e.g. in GPT (GUID Partition Table) as a partiions unique id. 43e11938eaSJason Hobbs */ 44e11938eaSJason Hobbs int uuid_str_valid(const char *uuid) 45e11938eaSJason Hobbs { 46e11938eaSJason Hobbs int i, valid; 47e11938eaSJason Hobbs 48e11938eaSJason Hobbs if (uuid == NULL) 49e11938eaSJason Hobbs return 0; 50e11938eaSJason Hobbs 51e11938eaSJason Hobbs for (i = 0, valid = 1; uuid[i] && valid; i++) { 52e11938eaSJason Hobbs switch (i) { 53e11938eaSJason Hobbs case 8: case 13: case 18: case 23: 54e11938eaSJason Hobbs valid = (uuid[i] == '-'); 55e11938eaSJason Hobbs break; 56e11938eaSJason Hobbs default: 57e11938eaSJason Hobbs valid = isxdigit(uuid[i]); 58e11938eaSJason Hobbs break; 59e11938eaSJason Hobbs } 60e11938eaSJason Hobbs } 61e11938eaSJason Hobbs 62*d718ded0SPrzemyslaw Marczak if (i != UUID_STR_LEN || !valid) 63e11938eaSJason Hobbs return 0; 64e11938eaSJason Hobbs 65e11938eaSJason Hobbs return 1; 66e11938eaSJason Hobbs } 67e11938eaSJason Hobbs 68*d718ded0SPrzemyslaw Marczak /* 69*d718ded0SPrzemyslaw Marczak * uuid_str_to_bin() - convert string UUID or GUID to big endian binary data. 70*d718ded0SPrzemyslaw Marczak * 71*d718ded0SPrzemyslaw Marczak * @param uuid_str - pointer to UUID or GUID string [37B] 72*d718ded0SPrzemyslaw Marczak * @param uuid_bin - pointer to allocated array for big endian output [16B] 73*d718ded0SPrzemyslaw Marczak * @str_format - UUID string format: 0 - UUID; 1 - GUID 74*d718ded0SPrzemyslaw Marczak */ 75*d718ded0SPrzemyslaw Marczak int uuid_str_to_bin(char *uuid_str, unsigned char *uuid_bin, int str_format) 76e11938eaSJason Hobbs { 77e11938eaSJason Hobbs uint16_t tmp16; 78e11938eaSJason Hobbs uint32_t tmp32; 79e11938eaSJason Hobbs uint64_t tmp64; 80e11938eaSJason Hobbs 81*d718ded0SPrzemyslaw Marczak if (!uuid_str_valid(uuid_str)) 82a96a0e61SPrzemyslaw Marczak return -EINVAL; 83a96a0e61SPrzemyslaw Marczak 84*d718ded0SPrzemyslaw Marczak if (str_format == UUID_STR_FORMAT_STD) { 85*d718ded0SPrzemyslaw Marczak tmp32 = cpu_to_be32(simple_strtoul(uuid_str, NULL, 16)); 86*d718ded0SPrzemyslaw Marczak memcpy(uuid_bin, &tmp32, 4); 87e11938eaSJason Hobbs 88*d718ded0SPrzemyslaw Marczak tmp16 = cpu_to_be16(simple_strtoul(uuid_str + 9, NULL, 16)); 89*d718ded0SPrzemyslaw Marczak memcpy(uuid_bin + 4, &tmp16, 2); 90e11938eaSJason Hobbs 91*d718ded0SPrzemyslaw Marczak tmp16 = cpu_to_be16(simple_strtoul(uuid_str + 14, NULL, 16)); 92*d718ded0SPrzemyslaw Marczak memcpy(uuid_bin + 6, &tmp16, 2); 93*d718ded0SPrzemyslaw Marczak } else { 94*d718ded0SPrzemyslaw Marczak tmp32 = cpu_to_le32(simple_strtoul(uuid_str, NULL, 16)); 95*d718ded0SPrzemyslaw Marczak memcpy(uuid_bin, &tmp32, 4); 96e11938eaSJason Hobbs 97*d718ded0SPrzemyslaw Marczak tmp16 = cpu_to_le16(simple_strtoul(uuid_str + 9, NULL, 16)); 98*d718ded0SPrzemyslaw Marczak memcpy(uuid_bin + 4, &tmp16, 2); 99e11938eaSJason Hobbs 100*d718ded0SPrzemyslaw Marczak tmp16 = cpu_to_le16(simple_strtoul(uuid_str + 14, NULL, 16)); 101*d718ded0SPrzemyslaw Marczak memcpy(uuid_bin + 6, &tmp16, 2); 102*d718ded0SPrzemyslaw Marczak } 103e11938eaSJason Hobbs 104*d718ded0SPrzemyslaw Marczak tmp16 = cpu_to_be16(simple_strtoul(uuid_str + 19, NULL, 16)); 105*d718ded0SPrzemyslaw Marczak memcpy(uuid_bin + 8, &tmp16, 2); 106*d718ded0SPrzemyslaw Marczak 107*d718ded0SPrzemyslaw Marczak tmp64 = cpu_to_be64(simple_strtoull(uuid_str + 24, NULL, 16)); 108*d718ded0SPrzemyslaw Marczak memcpy(uuid_bin + 10, (char *)&tmp64 + 2, 6); 109a96a0e61SPrzemyslaw Marczak 110a96a0e61SPrzemyslaw Marczak return 0; 111a96a0e61SPrzemyslaw Marczak } 112a96a0e61SPrzemyslaw Marczak 113*d718ded0SPrzemyslaw Marczak /* 114*d718ded0SPrzemyslaw Marczak * uuid_bin_to_str() - convert big endian binary data to string UUID or GUID. 115*d718ded0SPrzemyslaw Marczak * 116*d718ded0SPrzemyslaw Marczak * @param uuid_bin - pointer to binary data of UUID (big endian) [16B] 117*d718ded0SPrzemyslaw Marczak * @param uuid_str - pointer to allocated array for output string [37B] 118*d718ded0SPrzemyslaw Marczak * @str_format - UUID string format: 0 - UUID; 1 - GUID 119*d718ded0SPrzemyslaw Marczak */ 120*d718ded0SPrzemyslaw Marczak void uuid_bin_to_str(unsigned char *uuid_bin, char *uuid_str, int str_format) 121a96a0e61SPrzemyslaw Marczak { 122*d718ded0SPrzemyslaw Marczak const u8 uuid_char_order[UUID_BIN_LEN] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 123*d718ded0SPrzemyslaw Marczak 9, 10, 11, 12, 13, 14, 15}; 124*d718ded0SPrzemyslaw Marczak const u8 guid_char_order[UUID_BIN_LEN] = {3, 2, 1, 0, 5, 4, 7, 6, 8, 125*d718ded0SPrzemyslaw Marczak 9, 10, 11, 12, 13, 14, 15}; 126*d718ded0SPrzemyslaw Marczak const u8 *char_order; 127a96a0e61SPrzemyslaw Marczak int i; 128a96a0e61SPrzemyslaw Marczak 129*d718ded0SPrzemyslaw Marczak /* 130*d718ded0SPrzemyslaw Marczak * UUID and GUID bin data - always in big endian: 131*d718ded0SPrzemyslaw Marczak * 4B-2B-2B-2B-6B 132*d718ded0SPrzemyslaw Marczak * be be be be be 133*d718ded0SPrzemyslaw Marczak */ 134*d718ded0SPrzemyslaw Marczak if (str_format == UUID_STR_FORMAT_STD) 135*d718ded0SPrzemyslaw Marczak char_order = uuid_char_order; 136*d718ded0SPrzemyslaw Marczak else 137*d718ded0SPrzemyslaw Marczak char_order = guid_char_order; 138*d718ded0SPrzemyslaw Marczak 139a96a0e61SPrzemyslaw Marczak for (i = 0; i < 16; i++) { 140*d718ded0SPrzemyslaw Marczak sprintf(uuid_str, "%02x", uuid_bin[char_order[i]]); 141*d718ded0SPrzemyslaw Marczak uuid_str += 2; 142a96a0e61SPrzemyslaw Marczak switch (i) { 143a96a0e61SPrzemyslaw Marczak case 3: 144a96a0e61SPrzemyslaw Marczak case 5: 145a96a0e61SPrzemyslaw Marczak case 7: 146a96a0e61SPrzemyslaw Marczak case 9: 147*d718ded0SPrzemyslaw Marczak *uuid_str++ = '-'; 148a96a0e61SPrzemyslaw Marczak break; 149a96a0e61SPrzemyslaw Marczak } 150a96a0e61SPrzemyslaw Marczak } 151e11938eaSJason Hobbs } 152