From patchwork Thu Sep 13 08:10:04 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?q?=C5=81ukasz_Majewski?= X-Patchwork-Id: 183546 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id BB3EF2C00AF for ; Thu, 13 Sep 2012 18:11:31 +1000 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 101D128170; Thu, 13 Sep 2012 10:11:14 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 0AZaN-oB33VA; Thu, 13 Sep 2012 10:11:13 +0200 (CEST) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id BC07228176; Thu, 13 Sep 2012 10:11:02 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 49A9328145 for ; Thu, 13 Sep 2012 10:10:57 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id LSdnqfx+6APt for ; Thu, 13 Sep 2012 10:10:56 +0200 (CEST) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from mailout1.samsung.com (mailout1.samsung.com [203.254.224.24]) by theia.denx.de (Postfix) with ESMTP id 1F99C2816D for ; Thu, 13 Sep 2012 10:10:46 +0200 (CEST) Received: from epcpsbgm2.samsung.com (epcpsbgm2 [203.254.230.27]) by mailout1.samsung.com (Oracle Communications Messaging Server 7u4-24.01(7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTP id <0MAA00JKR3ZC2R90@mailout1.samsung.com> for u-boot@lists.denx.de; Thu, 13 Sep 2012 17:10:37 +0900 (KST) X-AuditID: cbfee61b-b7f586d000007adc-2e-505194fddc12 Received: from epmmp1.local.host ( [203.254.227.16]) by epcpsbgm2.samsung.com (EPCPMTA) with SMTP id BA.F9.31452.DF491505; Thu, 13 Sep 2012 17:10:37 +0900 (KST) Received: from mcdsrvbld02.digital.local ([106.116.37.23]) by mmp1.samsung.com (Oracle Communications Messaging Server 7u4-24.01 (7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTPA id <0MAA00LL040VU440@mmp1.samsung.com> for u-boot@lists.denx.de; Thu, 13 Sep 2012 17:10:37 +0900 (KST) From: Lukasz Majewski To: u-boot@lists.denx.de Date: Thu, 13 Sep 2012 10:10:04 +0200 Message-id: <1347523805-17825-7-git-send-email-l.majewski@samsung.com> X-Mailer: git-send-email 1.7.10 In-reply-to: <1347523805-17825-1-git-send-email-l.majewski@samsung.com> References: <1345795995-24656-1-git-send-email-l.majewski@samsung.com> <1347523805-17825-1-git-send-email-l.majewski@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFnrMJMWRmVeSWpSXmKPExsVy+t9jAd2/UwIDDD5+lrF4u7eT3YHR4+yd HYwBjFFcNimpOZllqUX6dglcGVs2PGcsWBdfMefGP9YGxr9eXYycHBICJhK9r6awQNhiEhfu rWfrYuTgEBJYxCixU6KLkQvIXMwksWrtfEaQGjYBPYnPd58ygdgiAhISv/qvMoIUMQtsZ5I4 fuobG0hCWMBKovXTKVYQm0VAVWJT6yZ2EJtXwE2iacElqGXyEk/v94HVcwq4S/zb958FYlsz o8ShXTtYJjDyLmBkWMUomlqQXFCclJ5rpFecmFtcmpeul5yfu4kR7PVn0jsYVzVYHGIU4GBU 4uHNfB4QIMSaWFZcmXuIUYKDWUmEV707MECINyWxsiq1KD++qDQntfgQozQHi5I4r9M5uwAh gfTEktTs1NSC1CKYLBMHp1QDY8DkgpVhpzY8kZ16JvRTw8W3uSc7OR7WXG78ZXQhLsYspOHA sxcrQmxV+T8onJXp6rx0VSrTLVftUHXexn3z7j7ecuj19Inf5CJ+7vyTbT/RvWCXqcS8O5z7 3l8ribjb3WW3R+3dqguOxxX/xhUe2l25uc3Jp2iC/julXO8nO+R/rhSUfnvnSpASS3FGoqEW c1FxIgBiaMok9gEAAA== Cc: Stephen Warren , Kyungmin Park , Tom Warren , Tom Rini Subject: [U-Boot] [PATCH v3 6/7] gpt: Support for new "gpt" command X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.11 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@lists.denx.de New command - "gpt" is supported. It restores the GPT partition table. It looks into the "partitions" environment variable for partitions definition. It can be enabled at target configuration file with CONFIG_CMD_GPT. Simple UUID generator has been implemented. It uses the the gd->start_addr_sp for entrophy pool. Moreover the pool address is used as crc32 seed. Signed-off-by: Lukasz Majewski Signed-off-by: Kyungmin Park --- Changes for v2: - gpt command now accepts device medium and its number (e.g. gpt mmc 0) - UUIDs can be passed via u-boot prompt when used with gpt command - Format of restored GPT has been changed - now key=value pairs are used 'name="PARTS_CSA",size=8MiB;\ ' 'name="PARTS_BOOTLOADER",size=60MiB; \' - guid_gen now accepts "pool" pointer and guid pointer - gd->start_addr_sp is used as a primary source of entrophy - static buffers definitions have been removed - remove memsize_to_blocks function with call to standard ustrtoul - doxygen comments for functions added Changes for v3: - Remove unnecessary braces --- common/Makefile | 1 + common/cmd_gpt.c | 404 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 405 insertions(+), 0 deletions(-) create mode 100644 common/cmd_gpt.c diff --git a/common/Makefile b/common/Makefile index 57da76f..39247c5 100644 --- a/common/Makefile +++ b/common/Makefile @@ -185,6 +185,7 @@ COBJS-$(CONFIG_MODEM_SUPPORT) += modem.o COBJS-$(CONFIG_UPDATE_TFTP) += update.o COBJS-$(CONFIG_USB_KEYBOARD) += usb_kbd.o COBJS-$(CONFIG_CMD_DFU) += cmd_dfu.o +COBJS-$(CONFIG_CMD_GPT) += cmd_gpt.o endif ifdef CONFIG_SPL_BUILD diff --git a/common/cmd_gpt.c b/common/cmd_gpt.c new file mode 100644 index 0000000..2460573 --- /dev/null +++ b/common/cmd_gpt.c @@ -0,0 +1,404 @@ +/* + * cmd_gpt.c -- GPT (GUID Partition Table) handling command + * + * Copyright (C) 2012 Samsung Electronics + * author: Lukasz Majewski + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include + +gpt_entry *gpt_e; +gpt_header *gpt_h; +DECLARE_GLOBAL_DATA_PTR; +static unsigned int gpt_parts; + +#ifdef DEBUG +/** + * guid_dump(): Dump guid content + * + * @param guid - pinter to guid + * @param i - number of bytes to dump + */ +static void guid_dump(u8 *guid, int i) +{ + int k; + + debug("GUID: "); + for (k = 0; k < i; k++, guid++) + debug(" %x ", *guid); + debug("\n"); +} +#else +static void guid_dump(u8 *guid, int i) {} +#endif + +/** + * guid_gen(): Generate UUID + * + * @param pool - pointer to pseudo random data (e.g. SP) + * @param guid - pointer to guid table + * + * @return - generated UUID table + * + * NOTE: The entrophy of this function is small + */ +static void guid_gen(const u32 *pool, u8 *guid) +{ + int k = 0; + u32 *ptr = (u32 *) guid; + + debug("%s: pool: 0x%p guid: 0x%p\n", __func__, pool, guid); + for (k = 0; k < 4; k++) + *(ptr + k) = crc32((u32) pool, (const void *) (pool - k), 512); + + guid_dump(guid, sizeof(efi_guid_t)); +} + +/** + * convert_uuid(); Convert UUID stored as string to bytes + * + * @param uuid - UUID represented as string + * @param dst - GUID buffer + * + * @return + */ +static int convert_uuid(char *uuid, u8 *dst) +{ + efi_guid_t guid; + u16 b, c, d; + char *t; + u64 e; + u32 a; + u8 *p; + + debug("%s: uuid: %s\n", __func__, uuid); + t = strsep(&uuid, "-"); + a = (u32)simple_strtoul(t, NULL, 16); + t = strsep(&uuid, "-"); + b = (u16)simple_strtoul(t, NULL, 16); + t = strsep(&uuid, "-"); + c = (u16)simple_strtoul(t, NULL, 16); + t = strsep(&uuid, "-"); + d = (u16)simple_strtoul(t, NULL, 16); + e = (u64)simple_strtoull(uuid, NULL, 16); + + p = (u8 *) &e; + guid = EFI_GUID(a, b, c, d >> 8, d & 0xFF, + *(p + 5), *(p + 4), *(p + 3), + *(p + 2), *(p + 1) , *p); + + guid_dump(guid.b, sizeof(efi_guid_t)); + memcpy(dst, guid.b, sizeof(efi_guid_t)); + + return 0; +} + +/** + * fill_pte(): Fill the GPT partition table entry + * + * @param dev_desc - block device descriptor + * @param gpt_h - GPT header representation + * @param gpt_e - GPT partition table entries + * @param parts - number of partitions + * @param size - size of each partition + * @param name - name of each partition + */ +static void gpt_fill_pte(block_dev_desc_t *dev_desc, gpt_header *gpt_h, + gpt_entry *gpt_e, int parts, unsigned int *size, + char *name[], char *uuid[]) +{ + u32 offset = (u32) gpt_h->first_usable_lba; + u8 guid[sizeof(efi_guid_t)]; + char p[PARTNAME_SZ]; + int i, k, j; + char *s; + + for (i = 0; i < parts; i++) { + memcpy(gpt_e[i].partition_type_guid.b, + &PARTITION_BASIC_DATA_GUID, 16); + + if (uuid[i]) + convert_uuid(uuid[i], gpt_e[i].unique_partition_guid.b); + else { + guid_gen((((u32 *) gd->start_addr_sp) - i - 1), guid); + memcpy(gpt_e[i].unique_partition_guid.b, guid, + sizeof(efi_guid_t)); + + } + s = name[i]; + + memset(p, 0x00, sizeof(p)); + for (k = 0, j = 0; k < strlen(s); k++, j += 2) { + p[j] = *(s + k); + p[j + 1] = '.'; + } + + memcpy(gpt_e[i].partition_name, + p, strlen(p)); + + gpt_e[i].starting_lba = cpu_to_le32(offset); + + /* allocate remaining memory in last partition */ + if (i != parts - 1) + gpt_e[i].ending_lba = + cpu_to_le64(offset + size[i] - 1); + else + gpt_e[i].ending_lba = gpt_h->last_usable_lba; + + memset(&gpt_e[i].attributes, 0, + sizeof(gpt_entry_attributes)); + + offset += size[i]; + debug("%s: name: %s offset[%d]: 0x%x size[%d]: 0x%x\n", + __func__, name[i], i, offset, i, size[i]); + } +} + +/** + * extract_val(): Extract value from a key=value pair + * + * @param p - pointer to string + * @param tab - table to store extracted value + * @param i - actual tab element to work on + * + * @return - zero on success; otherwise error + */ +static int extract_val(char **p, char *tab[], int i) +{ + char *t, *tok = *p; + + t = strsep(&tok, ","); + strsep(&t, "="); + tab[i] = calloc(strlen(t) + 1, 1); + if (tab[i] == NULL) { + printf("%s: calloc failed!\n", __func__); + return -1; + } + strcpy(tab[i], t); + *p = tok; + + return 0; +} + +/** + * extract_uuid(); Extract UUIDs from a string + * + * @param uuid - string to uuid representation + * @param tab - place to store separated items + * + * @return - zero on success; otherwise error + */ +static int extract_uuid(char *uuid, char *tab[]) +{ + char *tok = uuid; + int i; + + for (i = 0; tok && i < (GPT_PARTS_NUM + 1); i++) { + if (extract_val(&tok, tab, i)) { + for (i--; i >= 0; i--) + free(tab[i]); + return -1; + } + } + + return 0; +} + +/** + * set_gpt_info(): Fill gpt information for GPT header and partition entries + * + * @param dev_desc - block device descriptor + * @param str_uuid - string uuid representation + * + * @return - zero on success; otherwise error + * + * NOTE - uuid table is bigger than GPT_PARTS_NUM to support disk UUID + * + */ +static int set_gpt_info(block_dev_desc_t *dev_desc, char *str_uuid) +{ + char *ps[GPT_PARTS_NUM], *name[GPT_PARTS_NUM]; + char *uuid[GPT_PARTS_NUM + 1]; /* extra space to store disk uuid */ + u8 guid[sizeof(gpt_h->disk_guid.b)]; + unsigned int size[GPT_PARTS_NUM]; + char *tok, *p, *s, *ss; + int i, ret; + + debug("%s: MMC lba num: 0x%x %d\n", __func__, + (unsigned int)dev_desc->lba, (unsigned int)dev_desc->lba); + + for (i = 0; i <= GPT_PARTS_NUM; i++) + uuid[i] = NULL; + + s = getenv("partitions"); + if (s == NULL) { + printf("%s: \"partitions\" env variable not defined!\n", + __func__); + return -1; + } + + if (str_uuid) + extract_uuid(str_uuid, uuid); + + ss = calloc(strlen(s) + 1, 1); + if (ss == NULL) { + printf("%s: calloc failed!\n", __func__); + return -1; + } + memcpy(ss, s, strlen(s) + 1); + + for (i = 0, p = ss; i < GPT_PARTS_NUM; i++) { + tok = strsep(&p, ";"); + if (tok == NULL) + break; + + if (extract_val(&tok, name, i)) { + ret = -1; + goto err; + } + + if (extract_val(&tok, ps, i)) { + ret = -1; + free(name[i]); + goto err; + } + } + + gpt_parts = i; + + printf("found %d partitions\n", gpt_parts); + + for (i = 0; i < gpt_parts; i++) { + p = ps[i]; + size[i] = ustrtoul(p, &p, 0); + size[i] /= dev_desc->blksz; + } + + gpt_h = calloc(sizeof(gpt_header), 1); + gpt_e = calloc(sizeof(gpt_entry), GPT_ENTRY_NUMBERS); + + /* Generate Primary GPT header (LBA1) */ + gpt_h->signature = cpu_to_le64(GPT_HEADER_SIGNATURE); + gpt_h->revision = cpu_to_le32(GPT_HEADER_REVISION_V1); + gpt_h->header_size = cpu_to_le32(sizeof(gpt_header)); + gpt_h->my_lba = cpu_to_le64(1); + gpt_h->alternate_lba = cpu_to_le64(dev_desc->lba - 1); + gpt_h->first_usable_lba = cpu_to_le64(34); + gpt_h->last_usable_lba = cpu_to_le64(dev_desc->lba - 34); + gpt_h->partition_entry_lba = cpu_to_le64(2); + gpt_h->num_partition_entries = cpu_to_le32(GPT_ENTRY_NUMBERS); + gpt_h->sizeof_partition_entry = cpu_to_le32(sizeof(gpt_entry)); + gpt_h->header_crc32 = 0; + gpt_h->partition_entry_array_crc32 = 0; + + if (uuid[0]) + convert_uuid(uuid[0], gpt_h->disk_guid.b); + else { + guid_gen((u32 *)gd->start_addr_sp, guid); + memcpy(gpt_h->disk_guid.b, guid, sizeof(efi_guid_t)); + } + gpt_fill_pte(dev_desc, gpt_h, gpt_e, gpt_parts, size, name, &uuid[1]); + + puts("save the GPT ...\n"); + ret = set_gpt_table(dev_desc, gpt_h, gpt_e); + + free(gpt_e); + free(gpt_h); + + i = gpt_parts; + err: + for (i--; i >= 0; i--) { + free(name[i]); + free(ps[i]); + } + + free(ss); + return ret; +} + +/** + * gpt_mmc_default(): Restore default GPT on a MMC device + * + * @param dev - number of MMC device + * @param str_uuid - string representation of UUIDs + * + * @return zero on success; otherwise error + */ +static int gpt_mmc_default(int dev, char *str_uuid) +{ + struct mmc *mmc = find_mmc_device(dev); + + if (mmc == NULL) { + printf("%s: mmc dev %d NOT available\n", __func__, dev); + return CMD_RET_FAILURE; + } + + puts("Using default GPT UUID\n"); + return set_gpt_info(&mmc->block_dev, str_uuid); +} + +/** + * do_gpt(): Perform GPT operations + * + * @param cmdtp - command name + * @param flag + * @param argc + * @param argv + * + * @return zero on success; otherwise error + */ +static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + int ret = CMD_RET_SUCCESS; + char *str_uuid = NULL; + int dev = 0; + + if (argc < 3) + return CMD_RET_USAGE; + + if (argc == 4) { + str_uuid = strdup(argv[3]); + if (!str_uuid) { + printf("%s: malloc failed!\n", __func__); + return CMD_RET_FAILURE; + } + } + + if (strcmp(argv[1], "mmc") == 0) { + dev = (int)simple_strtoul(argv[2], NULL, 10); + if (gpt_mmc_default(dev, str_uuid)) + return CMD_RET_FAILURE; + } + + if (argc == 4) + free(str_uuid); + + return ret; +} + +U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt, + "GUID Partition Table", + " [uuid1=, uuid2=, ..., uuidN=]\n" + " - GUID partition table restoration\n" + " Restore GPT information on a device connected\n" + " to interface\n" +);