From patchwork Thu Apr 4 09:46:24 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?b?5p2O5Zu9?= X-Patchwork-Id: 1077023 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=lists.openwrt.org (client-ip=2607:7c80:54:e::133; helo=bombadil.infradead.org; envelope-from=openwrt-devel-bounces+incoming=patchwork.ozlabs.org@lists.openwrt.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="JM2HV+23"; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="XLGvh0tV"; dkim-atps=neutral Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:e::133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 44ZdQC5gDVz9ryj for ; Thu, 4 Apr 2019 20:46:59 +1100 (AEDT) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:Subject:MIME-Version:Message-Id:Date:To :From:Reply-To:Cc:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References: List-Owner; bh=6fUlixy9o58k5CjCYVZiwSXF0NXIjJgWQ5hgLmomDl8=; b=JM2HV+23AXarBU 47LaD51Obg1BhcP+GYge1pB3etwTgOTOQAtkFa7gVrsFKoqlfR3/BJ1ZnvHY97tPdAyl06EIGpi0+ Gbok++bWOJmmQRsLHsDYcT7reGDDkOcOOdgzsJ5ZiBBHAtVtvY5GGVs2bAFjrMLTG7Xz+25JBRpi2 aj66k+X41LOxTRCJDAKqB6s2PIUfnPFWLUMNnIiC9Ims+xKcwc83TLHcNnoRBSsSKFn2gmJ+ENSCV iaq3jXWUy23BQEG8bVw4YFhaKIOT41QZYGrXo7EtZiWm66A8chMPoXp5tsPkQ0xJMKSg5E9J78+5f t/5XzfQ6URWUiqxas0Ww==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1hByxD-0000Lq-E6; Thu, 04 Apr 2019 09:46:39 +0000 Received: from mail-pl1-x641.google.com ([2607:f8b0:4864:20::641]) by bombadil.infradead.org with esmtps (Exim 4.90_1 #2 (Red Hat Linux)) id 1hByx9-0000KQ-Pd for openwrt-devel@lists.openwrt.org; Thu, 04 Apr 2019 09:46:37 +0000 Received: by mail-pl1-x641.google.com with SMTP id y6so886428pll.13 for ; Thu, 04 Apr 2019 02:46:35 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:mime-version :content-transfer-encoding; bh=dg/r5+cHRNmp4465MtDKWLZ20ZqqwD0qssTfc0weImw=; b=XLGvh0tVZA5xKQTWWcrK8Q9VDt8ECLfqa2g/e/25W13SfAyxv66v01MYyBFmhcJ2Vq M0aRCEw24zP2yOOHE29c2LJjUzaI18ZF8UoWaH8cOlHL+6djLV4cYIXLo/FtiLhy1kPi gImMMlC+elRWuLXXtgGshAom/MLHlbkvwuKRRpGQTqN+Y0XdK0jdqEvEmwHpkGSzTXcz J7q/HarBqLkQXge21+XNyybrwjYY9gBjDzqoX/QBZDSjVkQD2G+NQWBAROhOOgXwAVaI 2Y/SLqm3AtYROs04jzmYUSg61jCWTZsmCoMDjGUHwxOC3AFadZzvi+ZgYI5kni6mz9gB 4Bvw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:mime-version :content-transfer-encoding; bh=dg/r5+cHRNmp4465MtDKWLZ20ZqqwD0qssTfc0weImw=; b=GZ075cDuoDKtvpCbi4pYMkz7MRl0VmXZiZbcPL631Uk/WPAMYAw0xbpL6xX2LDDX0F Cujw937wRhevvkgxTcWWCXbkH5q9QRZMW9KQav0Xt6JIIQfTiNHBQ2bTs5cF7rFKAplu iCPoAEWre8Web/8W4VszGJihk0Sr1RArxkeFzRa9uIDLD/8BqvZX4bUkWo9TMSVkNco0 jFIauhtbll7TEwh9zTa56BRwGCsVlZwAQCd1MEcdn9j03ShGhpCszA54ZTgDYetBxun6 Ikd1wShMojro/39SSOR1phPN90ayz2NFjSkNCttVozowse4ge6LmRlVAxPC2Sihycdux yrWg== X-Gm-Message-State: APjAAAUGuRXG7uBUtzZJlC+DOTfziCoToysTJ4jJT8I2BQa0TIwOY2pn 2GfY68qFa2z2auKWN/NPQmlQI0g5 X-Google-Smtp-Source: APXvYqzw7/+ABlCzJBCJEc8QHaKxhKuhvaq/Q2HRJT/rf9FhJfQ0Apsox+7Q8CNhlz4UgfEPPMCq0Q== X-Received: by 2002:a17:902:820e:: with SMTP id x14mr5329550pln.207.1554371194481; Thu, 04 Apr 2019 02:46:34 -0700 (PDT) Received: from www3.ntcmd.org ([104.128.68.178]) by smtp.gmail.com with ESMTPSA id q86sm45325714pfi.171.2019.04.04.02.46.33 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 04 Apr 2019 02:46:33 -0700 (PDT) From: =?utf-8?b?5p2O5Zu9?= To: openwrt-devel@lists.openwrt.org Date: Thu, 4 Apr 2019 17:46:24 +0800 Message-Id: <1554371186-25036-1-git-send-email-uxgood.org@gmail.com> X-Mailer: git-send-email 1.8.3.1 MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20190404_024635_858151_D902C415 X-CRM114-Status: GOOD ( 19.95 ) X-Spam-Score: -0.2 (/) X-Spam-Report: SpamAssassin version 3.4.2 on bombadil.infradead.org summary: Content analysis details: (-0.2 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [2607:f8b0:4864:20:0:0:0:641 listed in] [list.dnswl.org] 0.0 FREEMAIL_FROM Sender email is commonly abused enduser mail provider (uxgood.org[at]gmail.com) -0.0 SPF_PASS SPF: sender matches SPF record 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain Subject: [OpenWrt-Devel] [PATCH 1/3] firmware-utils: ptgen: add GPT support X-BeenThere: openwrt-devel@lists.openwrt.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "openwrt-devel" Errors-To: openwrt-devel-bounces+incoming=patchwork.ozlabs.org@lists.openwrt.org Add GPT support to ptgen, so we can generate EFI bootable images. Introduced two options: -g generate GPT partition table -G GUID use GUID for disk and increase last bit for all partitions We drop The alternate partition table to reduce size, This may cause problems when generate vmdk images or vdi images. We must pad enough sectors when generate these images. Signed-off-by: 李国 --- tools/firmware-utils/Makefile | 2 +- tools/firmware-utils/src/ptgen.c | 279 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 274 insertions(+), 7 deletions(-) diff --git a/tools/firmware-utils/Makefile b/tools/firmware-utils/Makefile index 864a3df..5686dcc 100644 --- a/tools/firmware-utils/Makefile +++ b/tools/firmware-utils/Makefile @@ -25,7 +25,7 @@ define Host/Compile $(call cc,dgfirmware) $(call cc,mksenaofw md5) $(call cc,trx2usr) - $(call cc,ptgen) + $(call cc,ptgen cyg_crc32) $(call cc,srec2bin) $(call cc,mkmylofw) $(call cc,mkcsysimg) diff --git a/tools/firmware-utils/src/ptgen.c b/tools/firmware-utils/src/ptgen.c index 0192bb6..7f7c74e 100644 --- a/tools/firmware-utils/src/ptgen.c +++ b/tools/firmware-utils/src/ptgen.c @@ -31,15 +31,50 @@ #include #include #include +#include +#include "cyg_crc.h" #if __BYTE_ORDER == __BIG_ENDIAN +#define cpu_to_le16(x) bswap_16(x) #define cpu_to_le32(x) bswap_32(x) +#define cpu_to_le64(x) bswap_64(x) #elif __BYTE_ORDER == __LITTLE_ENDIAN +#define cpu_to_le16(x) (x) #define cpu_to_le32(x) (x) +#define cpu_to_le64(x) (x) #else #error unknown endianness! #endif +#define swap(a, b) \ + do { typeof(a) __tmp = (a); (a) = (b); (b) = __tmp; } while (0) + +#ifndef GUID_INIT +typedef uuid_le guid_t; +#define GUID_INIT(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7) \ + UUID_LE(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7) +#endif + +#define GPT_SIGNATURE 0x5452415020494645ULL +#define GPT_REVISION 0x00010000 + +#define GUID_PARTITION_SYSTEM \ + GUID_INIT( 0xC12A7328, 0xF81F, 0x11d2, \ + 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B) + +#define GUID_PARTITION_BASIC_DATA \ + GUID_INIT( 0xEBD0A0A2, 0xB9E5, 0x4433, \ + 0x87, 0xC0, 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7) + +#define GUID_PARTITION_BIOS_BOOT \ + GUID_INIT( 0x21686148, 0x6449, 0x6E6F, \ + 0x74, 0x4E, 0x65, 0x65, 0x64, 0x45, 0x46, 0x49) + +#define GPT_HEADER_SIZE 92 +#define GPT_ENTRY_SIZE 128 +#define GPT_ENTRY_MAX 128 + + /* Partition table entry */ struct pte { uint8_t active; @@ -55,13 +90,43 @@ struct partinfo { int type; }; +/* GPT Partition table header */ +struct gpth { + uint64_t signature; + uint32_t revision; + uint32_t size; + uint32_t crc32; + uint32_t reserved; + uint64_t self; + uint64_t alternate; + uint64_t first_usable; + uint64_t last_usable; + guid_t disk_guid; + uint64_t first_entry; + uint32_t entry_num; + uint32_t entry_size; + uint32_t entry_crc32; +} __attribute__((packed)); + +/* GPT Partition table entry */ +struct gpte { + guid_t type; + guid_t guid; + uint64_t start; + uint64_t end; + uint64_t attr; + uint16_t name[72 / sizeof(uint16_t)]; +} __attribute__((packed)); + + int verbose = 0; int active = 1; int heads = -1; int sectors = -1; int kb_align = 0; bool ignore_null_sized_partition = false; -struct partinfo parts[4]; +bool use_guid_partition_table = false; +struct partinfo parts[GPT_ENTRY_MAX]; char *filename = NULL; @@ -132,6 +197,57 @@ static inline unsigned long round_to_kb(long sect) { return ((sect - 1) / kb_align + 1) * kb_align; } +/* Compute a CRC for guid partition table */ +static inline unsigned long gpt_crc32(void *buf, unsigned long len) +{ + return cyg_crc32_accumulate(~0L, buf, len) ^ ~0L; +} + +/* Parse a guid string to guid_t struct */ +static inline int guid_parse(char *buf, guid_t *guid) +{ + char b[4] = {0}; + char *p = buf; + int i = 0; + if (strnlen(buf, 36) != 36) + return -1; + for (i = 0; i < 16; i++) { + if (*p == '-') + p ++; + if (*p == '\0') + return -1; + memcpy(b, p, 2); + guid->b[i] = strtol(b, 0, 16); + p += 2; + } + swap(guid->b[0], guid->b[3]); + swap(guid->b[1], guid->b[2]); + swap(guid->b[4], guid->b[5]); + swap(guid->b[6], guid->b[7]); + return 0; +} + +/* init an utf-16 string from utf-8 string */ +static inline void init_utf16(char *str, uint16_t *buf, int bufsize) +{ + int i, n = 0; + for (i = 0; i < bufsize; i++) { + if (str[n] == 0x00) { + buf[i] = 0x00; + return ; + } else if((str[n] & 0x80) == 0x00) {//0xxxxxxx + buf[i] = cpu_to_le16(str[n++]); + } else if((str[n] & 0xE0) == 0xC0) {//110xxxxx + buf[i] = cpu_to_le16((str[n++] & 0x1F) << 6 | str[n++] & 0x3F); + } else if((str[n] & 0xF0) == 0xE0) {//1110xxxx + buf[i] = cpu_to_le16((str[n++] & 0x0F) << 12 | (str[n++] & 0x3F) << 6 | str[n++] & 0x3F); + } else { + buf[i] = cpu_to_le16('?'); + n ++; + } + } +} + /* check the partition sizes and write the partition table */ static int gen_ptable(uint32_t signature, int nr) { @@ -198,20 +314,158 @@ fail: return ret; } +/* check the partition sizes and write the guid partition table */ +static int gen_gptable(uint32_t signature, guid_t guid, int nr) +{ + struct pte pte; + struct gpth gpth = { + .signature = cpu_to_le64(GPT_SIGNATURE), + .revision = cpu_to_le32(GPT_REVISION), + .size = cpu_to_le32(GPT_HEADER_SIZE), + .self = cpu_to_le64(1), + .first_usable = cpu_to_le64(GPT_ENTRY_SIZE * GPT_ENTRY_MAX / 512 + 2), + .first_entry = cpu_to_le64(2), + .disk_guid = guid, + .entry_num = cpu_to_le32(GPT_ENTRY_MAX), + .entry_size = cpu_to_le32(GPT_ENTRY_SIZE), + }; + struct gpte gpte[GPT_ENTRY_MAX]; + unsigned long long start, end, sect = 0; + int i, fd, ret = -1; + + memset(gpte, 0, GPT_ENTRY_SIZE * GPT_ENTRY_MAX); + for (i = 0; i < nr; i++) { + if (!parts[i].size) { + if (ignore_null_sized_partition) + continue; + fprintf(stderr, "Invalid size in partition %d!\n", i); + return -1; + } + start = sect + sectors; + if (kb_align != 0) + start = round_to_kb(start); + gpte[i].start = cpu_to_le64(start); + + sect = start + parts[i].size * 2; + if (kb_align == 0) + sect = round_to_cyl(sect); + gpte[i].end = cpu_to_le64(sect -1); + gpte[i].guid = guid; + gpte[i].guid.b[15] += i + 1; + if (parts[i].type == 0xEF || (i + 1) == active) { + gpte[i].type = GUID_PARTITION_SYSTEM; + init_utf16("EFI System Partition", gpte[i].name, 36) ; + } else { + gpte[i].type = GUID_PARTITION_BASIC_DATA; + } + + if (verbose) + fprintf(stderr, "Partition %d: start=%lld, end=%lld, size=%lld\n", i, start * 512, sect * 512, (sect - start) * 512); + printf("%lld\n", start * 512); + printf("%lld\n", (sect - start) * 512); + } + + gpte[GPT_ENTRY_MAX - 1].start = cpu_to_le64(GPT_ENTRY_SIZE * GPT_ENTRY_MAX / 512 + 2); + gpte[GPT_ENTRY_MAX - 1].end = cpu_to_le64((kb_align ? round_to_kb(sectors) : sectors) - 1); + gpte[GPT_ENTRY_MAX - 1].type = GUID_PARTITION_BIOS_BOOT; + gpte[GPT_ENTRY_MAX - 1].guid = guid; + gpte[GPT_ENTRY_MAX - 1].guid.b[15] += GPT_ENTRY_MAX; + + end = sect + sectors - 1; + + pte.type = 0xEE; + pte.start = cpu_to_le32(1); + pte.length = cpu_to_le32(end); + to_chs(1, pte.chs_start); + to_chs(end, pte.chs_end); + + gpth.last_usable = cpu_to_le64(end - GPT_ENTRY_SIZE * GPT_ENTRY_MAX / 512 - 1); + gpth.alternate = cpu_to_le64(end); + gpth.entry_crc32 = cpu_to_le32(gpt_crc32(gpte, GPT_ENTRY_SIZE * GPT_ENTRY_MAX)); + gpth.crc32 = cpu_to_le32(gpt_crc32((char *)&gpth, GPT_HEADER_SIZE)); + + if ((fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0644)) < 0) { + fprintf(stderr, "Can't open output file '%s'\n",filename); + return -1; + } + + lseek(fd, 440, SEEK_SET); + if (write(fd, &signature, sizeof(signature)) != sizeof(signature)) { + fprintf(stderr, "write failed.\n"); + goto fail; + } + + lseek(fd, 446, SEEK_SET); + if (write(fd, &pte, sizeof(struct pte)) != sizeof(struct pte)) { + fprintf(stderr, "write failed.\n"); + goto fail; + } + + lseek(fd, 510, SEEK_SET); + if (write(fd, "\x55\xaa", 2) != 2) { + fprintf(stderr, "write failed.\n"); + goto fail; + } + + lseek(fd, 512, SEEK_SET); + if (write(fd, &gpth, GPT_HEADER_SIZE) != GPT_HEADER_SIZE) { + fprintf(stderr, "write failed.\n"); + goto fail; + } + + lseek(fd, 1024, SEEK_SET); + if (write(fd, &gpte, GPT_ENTRY_SIZE * GPT_ENTRY_MAX) != GPT_ENTRY_SIZE * GPT_ENTRY_MAX) { + fprintf(stderr, "write failed.\n"); + goto fail; + } + +#if 0 + /* The alternate partition table (We omit it) */ + swap(gpth.self, gpth.alternate); + gpth.first_entry = cpu_to_le64(end - GPT_ENTRY_SIZE * GPT_ENTRY_MAX / 512), + gpth.crc32 = 0; + gpth.crc32 = cpu_to_le32(gpt_crc32(&gpth, GPT_HEADER_SIZE)); + + lseek(fd, end * 512 - GPT_ENTRY_SIZE * GPT_ENTRY_MAX, SEEK_SET); + if (write(fd, &gpte, GPT_ENTRY_SIZE * GPT_ENTRY_MAX) != GPT_ENTRY_SIZE * GPT_ENTRY_MAX) { + fprintf(stderr, "write failed.\n"); + goto fail; + } + + lseek(fd, end * 512, SEEK_SET); + if (write(fd, &gpth, GPT_HEADER_SIZE) != GPT_HEADER_SIZE) { + fprintf(stderr, "write failed.\n"); + goto fail; + } + lseek(fd, end * 512 + 511, SEEK_SET); + if (write(fd, "\x00", 1) != 1) { + fprintf(stderr, "write failed.\n"); + goto fail; + } +#endif + + ret = 0; +fail: + close(fd); + return ret; +} + static void usage(char *prog) { - fprintf(stderr, "Usage: %s [-v] [-n] -h -s -o [-a 0..4] [-l ] [[-t ] -p ...] \n", prog); + fprintf(stderr, "Usage: %s [-v] [-n] [-g] -h -s -o [-a 0..4] [-l ] [-G ] [[-t ] -p ...] \n", prog); exit(EXIT_FAILURE); } int main (int argc, char **argv) { - char type = 0x83; + unsigned char type = 0x83; int ch; int part = 0; uint32_t signature = 0x5452574F; /* 'OWRT' */ + guid_t guid = GUID_INIT( signature, 0x2211, 0x4433, \ + 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0x00); - while ((ch = getopt(argc, argv, "h:s:p:a:t:o:vnl:S:")) != -1) { + while ((ch = getopt(argc, argv, "h:s:p:a:t:o:vngl:S:G:")) != -1) { switch (ch) { case 'o': filename = optarg; @@ -222,6 +476,9 @@ int main (int argc, char **argv) case 'n': ignore_null_sized_partition = true; break; + case 'g': + use_guid_partition_table = 1; + break; case 'h': heads = (int)strtoul(optarg, NULL, 0); break; @@ -229,7 +486,7 @@ int main (int argc, char **argv) sectors = (int)strtoul(optarg, NULL, 0); break; case 'p': - if (part > 3) { + if (part > GPT_ENTRY_MAX - 1 || (use_guid_partition_table == false && part > 3)) { fprintf(stderr, "Too many partitions\n"); exit(EXIT_FAILURE); } @@ -250,6 +507,12 @@ int main (int argc, char **argv) case 'S': signature = strtoul(optarg, NULL, 0); break; + case 'G': + if (guid_parse(optarg, &guid)) { + fprintf(stderr, "Invalid guid string\n"); + exit(EXIT_FAILURE); + } + break; case '?': default: usage(argv[0]); @@ -259,5 +522,9 @@ int main (int argc, char **argv) if (argc || (heads <= 0) || (sectors <= 0) || !filename) usage(argv[0]); - return gen_ptable(signature, part) ? EXIT_FAILURE : EXIT_SUCCESS; + if (use_guid_partition_table) { + return gen_gptable(signature, guid, part) ? EXIT_FAILURE : EXIT_SUCCESS; + } else { + return gen_ptable(signature, part) ? EXIT_FAILURE : EXIT_SUCCESS; + } }