u-boot.lists.denx.de archive mirror
 help / color / mirror / Atom feed
* [U-Boot] [PATCH v5 0/7] gpt: GUID Partition Table (GPT) restoration
@ 2012-12-11 10:09 Piotr Wilczek
  2012-12-11 10:09 ` [U-Boot] [PATCH v5 1/7] vsprintf:fix: Change type returned by ustrtoul Piotr Wilczek
                   ` (7 more replies)
  0 siblings, 8 replies; 9+ messages in thread
From: Piotr Wilczek @ 2012-12-11 10:09 UTC (permalink / raw)
  To: u-boot


This patch series provides a new command - "gpt" for eMMC partition table
(in the GPT format) restoration.

As a pre-work, some cleanup at the part_efi.c file was performed to
remove custom macros and make GPT related structures more readable.

Moreover the part_efi.h file has been moved to ./include directory to
be easily available from other subsystems.

The GPT detailed description has been written to README.gpt file.

Tested at:
        - Exynos4210 rev.1 - TRATS Samsung development board


Chang Hyun Park (1):
  gpt: The leXX_to_int() calls replaced with ones defined at
    <compiler.h>

Lukasz Majewski (5):
  vsprintf:fix: Change type returned by ustrtoul
  part:efi: Move part_efi.h file to ./include
  gpt:doc: GPT (GUID Partition Table) documentation
  gpt: Support for GPT (GUID Partition Table) restoration
  gpt: Enable support for GPT partition table restoration at Samsung's
    Trats

Piotr Wilczek (1):
  gpt: Support for new "gpt" command

 common/Makefile              |    1 +
 common/cmd_gpt.c             |  333 +++++++++++++++++++++++++++++++++++
 disk/part_efi.c              |  394 ++++++++++++++++++++++++++++++++++--------
 doc/README.gpt               |  201 +++++++++++++++++++++
 include/configs/trats.h      |   28 ++-
 include/exports.h            |    2 +-
 include/part.h               |   52 ++++++
 {disk => include}/part_efi.h |   89 +++++-----
 lib/vsprintf.c               |    2 +-
 9 files changed, 982 insertions(+), 120 deletions(-)
 create mode 100644 common/cmd_gpt.c
 create mode 100644 doc/README.gpt
 rename {disk => include}/part_efi.h (66%)

-- 
1.7.9.5

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [U-Boot] [PATCH v5 1/7] vsprintf:fix: Change type returned by ustrtoul
  2012-12-11 10:09 [U-Boot] [PATCH v5 0/7] gpt: GUID Partition Table (GPT) restoration Piotr Wilczek
@ 2012-12-11 10:09 ` Piotr Wilczek
  2012-12-11 10:09 ` [U-Boot] [PATCH v5 2/7] part:efi: Move part_efi.h file to ./include Piotr Wilczek
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Piotr Wilczek @ 2012-12-11 10:09 UTC (permalink / raw)
  To: u-boot

From: Lukasz Majewski <l.majewski@samsung.com>

The ustrtoul shall convert string defined size (e.g. 1GiB) to unsigned
long type (as its name implies).

Up till now it had returned int, which might cause problems with large
numbers (GiB range), when interpreted as U2 signed numbers.

Signed-off-by: Lukasz Majewski <l.majewski@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>

---
Changes in v5:
- changed return type in ustrtoul function decalration

Changes in v4:
- None

Changes in v3:
- None

Changes in v2:
- None

 include/exports.h |    2 +-
 lib/vsprintf.c    |    2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/include/exports.h b/include/exports.h
index 63aa4b2..6cf31aa 100644
--- a/include/exports.h
+++ b/include/exports.h
@@ -23,7 +23,7 @@ char *getenv (const char *name);
 int setenv (const char *varname, const char *varvalue);
 long simple_strtol(const char *cp,char **endp,unsigned int base);
 int strcmp(const char * cs,const char * ct);
-int ustrtoul(const char *cp, char **endp, unsigned int base);
+unsigned long ustrtoul(const char *cp, char **endp, unsigned int base);
 #if defined(CONFIG_CMD_I2C)
 int i2c_write (uchar, uint, int , uchar* , int);
 int i2c_read (uchar, uint, int , uchar* , int);
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index b7a79c0..3c432f8 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -103,7 +103,7 @@ long simple_strtol(const char *cp, char **endp, unsigned int base)
 	return simple_strtoul(cp, endp, base);
 }
 
-int ustrtoul(const char *cp, char **endp, unsigned int base)
+unsigned long ustrtoul(const char *cp, char **endp, unsigned int base)
 {
 	unsigned long result = simple_strtoul(cp, endp, base);
 	switch (**endp) {
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [U-Boot] [PATCH v5 2/7] part:efi: Move part_efi.h file to ./include
  2012-12-11 10:09 [U-Boot] [PATCH v5 0/7] gpt: GUID Partition Table (GPT) restoration Piotr Wilczek
  2012-12-11 10:09 ` [U-Boot] [PATCH v5 1/7] vsprintf:fix: Change type returned by ustrtoul Piotr Wilczek
@ 2012-12-11 10:09 ` Piotr Wilczek
  2012-12-11 10:09 ` [U-Boot] [PATCH v5 3/7] gpt:doc: GPT (GUID Partition Table) documentation Piotr Wilczek
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Piotr Wilczek @ 2012-12-11 10:09 UTC (permalink / raw)
  To: u-boot

From: Lukasz Majewski <l.majewski@samsung.com>

This move is necessary to export gpt header and GPT partition entries to be
used with other commands or subsystems.
Additionally the part_efi.h file has been cleaned-up to supress checkpatch's
warnings.

Signed-off-by: Lukasz Majewski <l.majewski@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>

---
Changes in v5:
- None

Changes in v4:
- None

Changes in v3:
- None

Changes in v2:
- None

 {disk => include}/part_efi.h |    0
 1 file changed, 0 insertions(+), 0 deletions(-)
 rename {disk => include}/part_efi.h (100%)

diff --git a/disk/part_efi.h b/include/part_efi.h
similarity index 100%
rename from disk/part_efi.h
rename to include/part_efi.h
-- 
1.7.9.5

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [U-Boot] [PATCH v5 3/7] gpt:doc: GPT (GUID Partition Table) documentation
  2012-12-11 10:09 [U-Boot] [PATCH v5 0/7] gpt: GUID Partition Table (GPT) restoration Piotr Wilczek
  2012-12-11 10:09 ` [U-Boot] [PATCH v5 1/7] vsprintf:fix: Change type returned by ustrtoul Piotr Wilczek
  2012-12-11 10:09 ` [U-Boot] [PATCH v5 2/7] part:efi: Move part_efi.h file to ./include Piotr Wilczek
@ 2012-12-11 10:09 ` Piotr Wilczek
  2012-12-11 10:09 ` [U-Boot] [PATCH v5 4/7] gpt: The leXX_to_int() calls replaced with ones defined at <compiler.h> Piotr Wilczek
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Piotr Wilczek @ 2012-12-11 10:09 UTC (permalink / raw)
  To: u-boot

From: Lukasz Majewski <l.majewski@samsung.com>

Documentation of the GPT format.

Signed-off-by: Lukasz Majewski <l.majewski@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>

---
Changes in v5:
- Updated documentation

Changes in v4:
- Updated documentation

Changes in v3:
- None

Changes in v2:
- Typos correction.
- Adding guidlines about GPT restoration.
- Adding information about GUID generator

 doc/README.gpt |  201 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 201 insertions(+)
 create mode 100644 doc/README.gpt

diff --git a/doc/README.gpt b/doc/README.gpt
new file mode 100644
index 0000000..a9c58b4
--- /dev/null
+++ b/doc/README.gpt
@@ -0,0 +1,201 @@
+#
+#  Copyright (C) 2012 Samsung Electronics
+#
+#  Lukasz Majewski <l.majewski@samsung.com>
+#
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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
+
+
+Glossary:
+========
+- UUID -(Universally Unique Identifier)
+- GUID - (Globally Unique ID)
+- EFI - (Extensible Firmware Interface)
+- UEFI - (Unified EFI) - EFI evolution
+- GPT (GUID Partition Table) - it is the EFI standard part
+- partitions - lists of available partitions (defined at u-boot):
+  ./include/configs/{target}.h
+
+Introduction:
+=============
+This document describes the GPT partition table format and usage of
+the gpt command in u-boot.
+
+
+UUID introduction:
+====================
+
+GPT for marking disks/partitions is using the UUID. It is supposed to be a
+globally unique value. A UUID is a 16-byte (128-bit) number. The number of
+theoretically possible UUIDs is therefore about 3 x 10^38.
+More often UUID is displayed as 32 hexadecimal digits, in 5 groups,
+separated by hyphens, in the form 8-4-4-4-12 for a total of 36 characters
+(32 digits and 4 hyphens)
+
+For instance, GUID of Linux data partition: EBD0A0A2-B9E5-4433-87C0-68B6B72699C7
+
+Historically there are 5 methods to generate this number. The oldest one is
+combining machine's MAC address and timer (epoch) value.
+
+Successive versions are using MD5 hash, random numbers and SHA-1 hash. All major
+OSes and programming languages are providing libraries to compute UUID (e.g.
+uuid command line tool).
+
+GPT brief explanation:
+======================
+
+	Layout:
+	-------
+
+	--------------------------------------------------
+	LBA 0          |Protective MBR                   |
+	----------------------------------------------------------
+	LBA 1          |Primary GPT Header               | Primary
+	-------------------------------------------------- GPT
+	LBA 2          |Entry 1|Entry 2| Entry 3| Entry 4|
+	--------------------------------------------------
+	LBA 3          |Entries 5 - 128                  |
+		       |                                 |
+		       |                                 |
+	----------------------------------------------------------
+	LBA 34         |Partition 1                      |
+		       |                                 |
+		       -----------------------------------
+		       |Partition 2                      |
+		       |                                 |
+		       -----------------------------------
+		       |Partition n                      |
+		       |                                 |
+	----------------------------------------------------------
+	LBA -34        |Entry 1|Entry 2| Entry 3| Entry 4| Secondary
+	-------------------------------------------------- (bkp)
+	LBA -33        |Entries 5 - 128                  | GPT
+		       |                                 |
+		       |                                 |
+	LBA -2         |                                 |
+	--------------------------------------------------
+	LBA -1         |Secondary GPT Header             |
+	----------------------------------------------------------
+
+
+For a legacy reasons, GPT's LBA 0 sector has a MBR structure. It is called
+"protective MBR".
+Its first partition entry ID has 0xEE value, and disk software, which is not
+handling the GPT sees it as a storage device without free space.
+
+It is possible to define 128 linearly placed partition entries.
+
+"LBA -1" means the last addressable block (in the mmc subsystem:
+"dev_desc->lba - 1")
+
+Primary/Secondary GPT header:
+----------------------------
+Offset  Size    Description
+
+0       8 B     Signature ("EFI PART", 45 46 49 20 50 41 52 54)
+8       4 B     Revision (For version 1.0, the value is 00 00 01 00)
+12      4 B     Header size (in bytes, usually 5C 00 00 00 meaning 92 bytes)
+16      4 B     CRC32 of header (0 to header size), with this field zeroed
+		during calculation
+20      4 B     Reserved (ZERO);
+24      8 B     Current LBA (location of this header copy)
+32      8 B     Backup LBA (location of the other header copy)
+40      8 B     First usable LBA for partitions (primary partition table last
+		LBA + 1)
+48      8 B     Last usable LBA (secondary partition table first LBA - 1)
+56      16 B    Disk GUID (also referred as UUID on UNIXes)
+72      8 B     Partition entries starting LBA (always 2 in primary copy)
+80      4 B     Number of partition entries
+84      4 B     Size of a partition entry (usually 128)
+88      4 B     CRC32 of partition array
+92      *       Reserved; must be ZERO (420 bytes for a 512-byte LBA)
+
+TOTAL: 512 B
+
+
+
+IMPORTANT:
+
+GPT headers and partition entries are protected by CRC32 (the POSIX CRC32).
+
+Primary GPT header and Secondary GPT header have swapped values of "Current LBA"
+and "Backup LBA" and therefore different CRC32 check-sum.
+
+CRC32 for GPT headers (field "CRC of header") are calculated up till
+"Header size" (92), NOT 512 bytes.
+
+CRC32 for partition entries (field "CRC32 of partition array") is calculated for
+the whole array entry ( Number_of_partition_entries *
+sizeof(partition_entry_size (usually 128)))
+
+Observe, how Secondary GPT is placed in the memory. It is NOT a mirror reflect
+of the Primary.
+
+
+	   Partition Entry Format:
+	   ----------------------
+	   Offset  Size    Description
+
+	   0       16 B    Partition type GUID
+	   16      16 B    Unique partition GUID
+	   32      8  B    First LBA (Little Endian)
+	   40      8  B    Last LBA (inclusive)
+	   48      8  B    Attribute flags [+]
+	   56      72 B    Partition name (text)
+
+	   Attribute flags:
+	   Bit 0  - System partition
+	   Bit 60 - Read-only
+	   Bit 62 - Hidden
+	   Bit 63 - Not mount
+
+
+Creating GPT partitions in U-Boot:
+==============
+
+To restore GUID partition table one needs to:
+1. Define partition layout in the environment.
+   Format of partitions layout:
+     "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
+	name=kernel,size=60MiB,uuid=...;"
+     or
+     "partitions=uuid_disk=${uuid_gpt_disk};name=${uboot_name},
+	size=${uboot_size},uuid=${uboot_uuid};"
+
+   Fields 'name', 'size' and 'uuid' are mandatory for every partition.
+   The field 'start' is optional.
+
+2. Define 'CONFIG_EFI_PARTITION' and 'CONFIG_CMD_GPT'
+
+2. From u-boot prompt type:
+   gpt write mmc 0 $partitions
+
+
+Useful info:
+============
+
+Two programs, namely: 'fdisk' and 'parted' are recommended to work with GPT
+recovery. Parted is able to handle GUID partitions. Unfortunately the 'fdisk'
+hasn't got such ability.
+Please, pay attention at -l switch for parted.
+
+"uuid" program is recommended to generate UUID string. Moreover it can decode
+(-d switch) passed in UUID string. It can be used to generate partitions UUID
+passed to u-boot environment variables.
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [U-Boot] [PATCH v5 4/7] gpt: The leXX_to_int() calls replaced with ones defined at <compiler.h>
  2012-12-11 10:09 [U-Boot] [PATCH v5 0/7] gpt: GUID Partition Table (GPT) restoration Piotr Wilczek
                   ` (2 preceding siblings ...)
  2012-12-11 10:09 ` [U-Boot] [PATCH v5 3/7] gpt:doc: GPT (GUID Partition Table) documentation Piotr Wilczek
@ 2012-12-11 10:09 ` Piotr Wilczek
  2012-12-11 10:09 ` [U-Boot] [PATCH v5 5/7] gpt: Support for GPT (GUID Partition Table) restoration Piotr Wilczek
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Piotr Wilczek @ 2012-12-11 10:09 UTC (permalink / raw)
  To: u-boot

From: Chang Hyun Park <heartinpiece@outlook.com>

Custom definitions of le_XX_to_int functions have been replaced with
standard ones, defined at <compiler.h>

Replacement of several GPT related structures members with ones
indicating its endianness and proper size.

Signed-off-by: Chang Hyun Park <heartinpiece@outlook.com>
Signed-off-by: Lukasz Majewski <l.majewski@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>

---
Changes in v5:
- removed unncessary casting

Changes in v4:
- None

Changes in v3:
- None

Changes in v2:
- Combining two commits regarding part_efi.{h|c}

 disk/part_efi.c    |  113 +++++++++++++++++++---------------------------------
 include/part_efi.h |   89 +++++++++++++++++++++--------------------
 2 files changed, 88 insertions(+), 114 deletions(-)

diff --git a/disk/part_efi.c b/disk/part_efi.c
index a3873ce..4aa3647 100644
--- a/disk/part_efi.c
+++ b/disk/part_efi.c
@@ -34,7 +34,7 @@
 #include <command.h>
 #include <ide.h>
 #include <malloc.h>
-#include "part_efi.h"
+#include <part_efi.h>
 #include <linux/ctype.h>
 
 #if defined(CONFIG_CMD_IDE) || \
@@ -44,34 +44,6 @@
     defined(CONFIG_MMC) || \
     defined(CONFIG_SYSTEMACE)
 
-/* Convert char[2] in little endian format to the host format integer
- */
-static inline unsigned short le16_to_int(unsigned char *le16)
-{
-	return ((le16[1] << 8) + le16[0]);
-}
-
-/* Convert char[4] in little endian format to the host format integer
- */
-static inline unsigned long le32_to_int(unsigned char *le32)
-{
-	return ((le32[3] << 24) + (le32[2] << 16) + (le32[1] << 8) + le32[0]);
-}
-
-/* Convert char[8] in little endian format to the host format integer
- */
-static inline unsigned long long le64_to_int(unsigned char *le64)
-{
-	return (((unsigned long long)le64[7] << 56) +
-		((unsigned long long)le64[6] << 48) +
-		((unsigned long long)le64[5] << 40) +
-		((unsigned long long)le64[4] << 32) +
-		((unsigned long long)le64[3] << 24) +
-		((unsigned long long)le64[2] << 16) +
-		((unsigned long long)le64[1] << 8) +
-		(unsigned long long)le64[0]);
-}
-
 /**
  * efi_crc32() - EFI version of crc32 function
  * @buf: buffer to calculate crc32 of
@@ -79,7 +51,7 @@ static inline unsigned long long le64_to_int(unsigned char *le64)
  *
  * Description: Returns EFI-style CRC32 value for @buf
  */
-static inline unsigned long efi_crc32(const void *buf, unsigned long len)
+static inline u32 efi_crc32(const void *buf, u32 len)
 {
 	return crc32(0, buf, len);
 }
@@ -171,14 +143,14 @@ void print_part_efi(block_dev_desc_t * dev_desc)
 	printf("\tType UUID\n");
 	printf("\tPartition UUID\n");
 
-	for (i = 0; i < le32_to_int(gpt_head->num_partition_entries); i++) {
+	for (i = 0; i < le32_to_cpu(gpt_head->num_partition_entries); i++) {
 		/* Stop at the first non valid PTE */
 		if (!is_pte_valid(&gpt_pte[i]))
 			break;
 
 		printf("%3d\t0x%08llx\t0x%08llx\t\"%s\"\n", (i + 1),
-			le64_to_int(gpt_pte[i].starting_lba),
-			le64_to_int(gpt_pte[i].ending_lba),
+			le64_to_cpu(gpt_pte[i].starting_lba),
+			le64_to_cpu(gpt_pte[i].ending_lba),
 			print_efiname(&gpt_pte[i]));
 		printf("\tattrs:\t0x%016llx\n", gpt_pte[i].attributes.raw);
 		uuid_string(gpt_pte[i].partition_type_guid.b, uuid);
@@ -211,7 +183,7 @@ int get_partition_info_efi(block_dev_desc_t * dev_desc, int part,
 		return -1;
 	}
 
-	if (part > le32_to_int(gpt_head->num_partition_entries) ||
+	if (part > le32_to_cpu(gpt_head->num_partition_entries) ||
 	    !is_pte_valid(&gpt_pte[part - 1])) {
 		printf("%s: *** ERROR: Invalid partition number %d ***\n",
 			__func__, part);
@@ -219,9 +191,9 @@ int get_partition_info_efi(block_dev_desc_t * dev_desc, int part,
 	}
 
 	/* The ulong casting limits the maximum disk size to 2 TB */
-	info->start = (ulong) le64_to_int(gpt_pte[part - 1].starting_lba);
+	info->start = (u64)le64_to_cpu(gpt_pte[part - 1].starting_lba);
 	/* The ending LBA is inclusive, to calculate size, add 1 to it */
-	info->size = ((ulong)le64_to_int(gpt_pte[part - 1].ending_lba) + 1)
+	info->size = ((u64)le64_to_cpu(gpt_pte[part - 1].ending_lba) + 1)
 		     - info->start;
 	info->blksz = GPT_BLOCK_SIZE;
 
@@ -264,7 +236,7 @@ int test_part_efi(block_dev_desc_t * dev_desc)
 static int pmbr_part_valid(struct partition *part)
 {
 	if (part->sys_ind == EFI_PMBR_OSTYPE_EFI_GPT &&
-		le32_to_int(part->start_sect) == 1UL) {
+		le32_to_cpu(part->start_sect) == 1UL) {
 		return 1;
 	}
 
@@ -283,9 +255,8 @@ static int is_pmbr_valid(legacy_mbr * mbr)
 {
 	int i = 0;
 
-	if (!mbr || le16_to_int(mbr->signature) != MSDOS_MBR_SIGNATURE) {
+	if (!mbr || le16_to_cpu(mbr->signature) != MSDOS_MBR_SIGNATURE)
 		return 0;
-	}
 
 	for (i = 0; i < 4; i++) {
 		if (pmbr_part_valid(&mbr->partition_record[i])) {
@@ -308,8 +279,8 @@ static int is_pmbr_valid(legacy_mbr * mbr)
 static int is_gpt_valid(block_dev_desc_t * dev_desc, unsigned long long lba,
 			gpt_header * pgpt_head, gpt_entry ** pgpt_pte)
 {
-	unsigned char crc32_backup[4] = { 0 };
-	unsigned long calc_crc32;
+	u32 crc32_backup = 0;
+	u32 calc_crc32;
 	unsigned long long lastlba;
 
 	if (!dev_desc || !pgpt_head) {
@@ -324,54 +295,54 @@ static int is_gpt_valid(block_dev_desc_t * dev_desc, unsigned long long lba,
 	}
 
 	/* Check the GPT header signature */
-	if (le64_to_int(pgpt_head->signature) != GPT_HEADER_SIGNATURE) {
+	if (le64_to_cpu(pgpt_head->signature) != GPT_HEADER_SIGNATURE) {
 		printf("GUID Partition Table Header signature is wrong:"
 			"0x%llX != 0x%llX\n",
-			(unsigned long long)le64_to_int(pgpt_head->signature),
-			(unsigned long long)GPT_HEADER_SIGNATURE);
+			le64_to_cpu(pgpt_head->signature),
+			GPT_HEADER_SIGNATURE);
 		return 0;
 	}
 
 	/* Check the GUID Partition Table CRC */
-	memcpy(crc32_backup, pgpt_head->header_crc32, sizeof(crc32_backup));
-	memset(pgpt_head->header_crc32, 0, sizeof(pgpt_head->header_crc32));
+	memcpy(&crc32_backup, &pgpt_head->header_crc32, sizeof(crc32_backup));
+	memset(&pgpt_head->header_crc32, 0, sizeof(pgpt_head->header_crc32));
 
 	calc_crc32 = efi_crc32((const unsigned char *)pgpt_head,
-		le32_to_int(pgpt_head->header_size));
+		le32_to_cpu(pgpt_head->header_size));
 
-	memcpy(pgpt_head->header_crc32, crc32_backup, sizeof(crc32_backup));
+	memcpy(&pgpt_head->header_crc32, &crc32_backup, sizeof(crc32_backup));
 
-	if (calc_crc32 != le32_to_int(crc32_backup)) {
+	if (calc_crc32 != le32_to_cpu(crc32_backup)) {
 		printf("GUID Partition Table Header CRC is wrong:"
-			"0x%08lX != 0x%08lX\n",
-			le32_to_int(crc32_backup), calc_crc32);
+			"0x%x != 0x%x\n",
+		       le32_to_cpu(crc32_backup), calc_crc32);
 		return 0;
 	}
 
 	/* Check that the my_lba entry points to the LBA that contains the GPT */
-	if (le64_to_int(pgpt_head->my_lba) != lba) {
+	if (le64_to_cpu(pgpt_head->my_lba) != lba) {
 		printf("GPT: my_lba incorrect: %llX != %llX\n",
-			(unsigned long long)le64_to_int(pgpt_head->my_lba),
-			(unsigned long long)lba);
+			le64_to_cpu(pgpt_head->my_lba),
+			lba);
 		return 0;
 	}
 
 	/* Check the first_usable_lba and last_usable_lba are within the disk. */
 	lastlba = (unsigned long long)dev_desc->lba;
-	if (le64_to_int(pgpt_head->first_usable_lba) > lastlba) {
+	if (le64_to_cpu(pgpt_head->first_usable_lba) > lastlba) {
 		printf("GPT: first_usable_lba incorrect: %llX > %llX\n",
-			le64_to_int(pgpt_head->first_usable_lba), lastlba);
+			le64_to_cpu(pgpt_head->first_usable_lba), lastlba);
 		return 0;
 	}
-	if (le64_to_int(pgpt_head->last_usable_lba) > lastlba) {
+	if (le64_to_cpu(pgpt_head->last_usable_lba) > lastlba) {
 		printf("GPT: last_usable_lba incorrect: %llX > %llX\n",
-			le64_to_int(pgpt_head->last_usable_lba), lastlba);
+			(u64) le64_to_cpu(pgpt_head->last_usable_lba), lastlba);
 		return 0;
 	}
 
 	debug("GPT: first_usable_lba: %llX last_usable_lba %llX last lba %llX\n",
-		le64_to_int(pgpt_head->first_usable_lba),
-		le64_to_int(pgpt_head->last_usable_lba), lastlba);
+		le64_to_cpu(pgpt_head->first_usable_lba),
+		le64_to_cpu(pgpt_head->last_usable_lba), lastlba);
 
 	/* Read and allocate Partition Table Entries */
 	*pgpt_pte = alloc_read_gpt_entries(dev_desc, pgpt_head);
@@ -382,13 +353,13 @@ static int is_gpt_valid(block_dev_desc_t * dev_desc, unsigned long long lba,
 
 	/* Check the GUID Partition Table Entry Array CRC */
 	calc_crc32 = efi_crc32((const unsigned char *)*pgpt_pte,
-		le32_to_int(pgpt_head->num_partition_entries) *
-		le32_to_int(pgpt_head->sizeof_partition_entry));
+		le32_to_cpu(pgpt_head->num_partition_entries) *
+		le32_to_cpu(pgpt_head->sizeof_partition_entry));
 
-	if (calc_crc32 != le32_to_int(pgpt_head->partition_entry_array_crc32)) {
+	if (calc_crc32 != le32_to_cpu(pgpt_head->partition_entry_array_crc32)) {
 		printf("GUID Partition Table Entry Array CRC is wrong:"
-			"0x%08lX != 0x%08lX\n",
-			le32_to_int(pgpt_head->partition_entry_array_crc32),
+			"0x%x != 0x%x\n",
+			le32_to_cpu(pgpt_head->partition_entry_array_crc32),
 			calc_crc32);
 
 		free(*pgpt_pte);
@@ -419,12 +390,12 @@ static gpt_entry *alloc_read_gpt_entries(block_dev_desc_t * dev_desc,
 		return NULL;
 	}
 
-	count = le32_to_int(pgpt_head->num_partition_entries) *
-		le32_to_int(pgpt_head->sizeof_partition_entry);
+	count = le32_to_cpu(pgpt_head->num_partition_entries) *
+		le32_to_cpu(pgpt_head->sizeof_partition_entry);
 
-	debug("%s: count = %lu * %lu = %zu\n", __func__,
-		le32_to_int(pgpt_head->num_partition_entries),
-		le32_to_int(pgpt_head->sizeof_partition_entry), count);
+	debug("%s: count = %u * %u = %zu\n", __func__,
+	      (u32) le32_to_cpu(pgpt_head->num_partition_entries),
+	      (u32) le32_to_cpu(pgpt_head->sizeof_partition_entry), count);
 
 	/* Allocate memory for PTE, remember to FREE */
 	if (count != 0) {
@@ -440,7 +411,7 @@ static gpt_entry *alloc_read_gpt_entries(block_dev_desc_t * dev_desc,
 
 	/* Read GPT Entries from device */
 	if (dev_desc->block_read (dev_desc->dev,
-		(unsigned long)le64_to_int(pgpt_head->partition_entry_lba),
+		le64_to_cpu(pgpt_head->partition_entry_lba),
 		(lbaint_t) (count / GPT_BLOCK_SIZE), pte)
 		!= (count / GPT_BLOCK_SIZE)) {
 
diff --git a/include/part_efi.h b/include/part_efi.h
index 4e28d1d..6de0a32 100644
--- a/include/part_efi.h
+++ b/include/part_efi.h
@@ -29,6 +29,8 @@
  * http://developer.intel.com/technology/efi/efi.htm
 */
 
+#include <linux/compiler.h>
+
 #ifndef _DISK_PART_EFI_H
 #define _DISK_PART_EFI_H
 
@@ -41,6 +43,8 @@
 #define GPT_HEADER_REVISION_V1 0x00010000
 #define GPT_PRIMARY_PARTITION_TABLE_LBA 1ULL
 #define GPT_ENTRY_NAME "gpt"
+#define GPT_ENTRY_NUMBERS		128
+#define GPT_ENTRY_SIZE			128
 
 #define EFI_GUID(a,b,c,d0,d1,d2,d3,d4,d5,d6,d7) \
 	((efi_guid_t) \
@@ -72,73 +76,72 @@
 		0xa2, 0x3c, 0x23, 0x8f, 0x2a, 0x3d, 0xf9, 0x28)
 
 /* linux/include/efi.h */
-typedef unsigned short efi_char16_t;
+typedef u16 efi_char16_t;
 
 typedef struct {
-	unsigned char b[16];
+	u8 b[16];
 } efi_guid_t;
 
 /* based on linux/include/genhd.h */
 struct partition {
-	unsigned char boot_ind;		/* 0x80 - active */
-	unsigned char head;		/* starting head */
-	unsigned char sector;		/* starting sector */
-	unsigned char cyl;		/* starting cylinder */
-	unsigned char sys_ind;		/* What partition type */
-	unsigned char end_head;		/* end head */
-	unsigned char end_sector;	/* end sector */
-	unsigned char end_cyl;		/* end cylinder */
-	unsigned char start_sect[4];	/* starting sector counting from 0 */
-	unsigned char nr_sects[4];	/* nr of sectors in partition */
-} __attribute__ ((packed));
+	u8 boot_ind;		/* 0x80 - active */
+	u8 head;		/* starting head */
+	u8 sector;		/* starting sector */
+	u8 cyl;			/* starting cylinder */
+	u8 sys_ind;		/* What partition type */
+	u8 end_head;		/* end head */
+	u8 end_sector;		/* end sector */
+	u8 end_cyl;		/* end cylinder */
+	__le32 start_sect;	/* starting sector counting from 0 */
+	__le32 nr_sects;	/* nr of sectors in partition */
+} __packed;
 
 /* based on linux/fs/partitions/efi.h */
 typedef struct _gpt_header {
-	unsigned char signature[8];
-	unsigned char revision[4];
-	unsigned char header_size[4];
-	unsigned char header_crc32[4];
-	unsigned char reserved1[4];
-	unsigned char my_lba[8];
-	unsigned char alternate_lba[8];
-	unsigned char first_usable_lba[8];
-	unsigned char last_usable_lba[8];
+	__le64 signature;
+	__le32 revision;
+	__le32 header_size;
+	__le32 header_crc32;
+	__le32 reserved1;
+	__le64 my_lba;
+	__le64 alternate_lba;
+	__le64 first_usable_lba;
+	__le64 last_usable_lba;
 	efi_guid_t disk_guid;
-	unsigned char partition_entry_lba[8];
-	unsigned char num_partition_entries[4];
-	unsigned char sizeof_partition_entry[4];
-	unsigned char partition_entry_array_crc32[4];
-	unsigned char reserved2[GPT_BLOCK_SIZE - 92];
-} __attribute__ ((packed)) gpt_header;
+	__le64 partition_entry_lba;
+	__le32 num_partition_entries;
+	__le32 sizeof_partition_entry;
+	__le32 partition_entry_array_crc32;
+	u8 reserved2[GPT_BLOCK_SIZE - 92];
+} __packed gpt_header;
 
 typedef union _gpt_entry_attributes {
 	struct {
-		unsigned long long required_to_function:1;
-		unsigned long long no_block_io_protocol:1;
-		unsigned long long legacy_bios_bootable:1;
-		unsigned long long reserved:45;
-		unsigned long long type_guid_specific:16;
+		u64 required_to_function:1;
+		u64 no_block_io_protocol:1;
+		u64 legacy_bios_bootable:1;
+		u64 reserved:45;
+		u64 type_guid_specific:16;
 	} fields;
 	unsigned long long raw;
-} __attribute__ ((packed)) gpt_entry_attributes;
+} __packed gpt_entry_attributes;
 
 #define PARTNAME_SZ	(72 / sizeof(efi_char16_t))
 typedef struct _gpt_entry {
 	efi_guid_t partition_type_guid;
 	efi_guid_t unique_partition_guid;
-	unsigned char starting_lba[8];
-	unsigned char ending_lba[8];
+	__le64 starting_lba;
+	__le64 ending_lba;
 	gpt_entry_attributes attributes;
 	efi_char16_t partition_name[PARTNAME_SZ];
-}
-__attribute__ ((packed)) gpt_entry;
+} __packed gpt_entry;
 
 typedef struct _legacy_mbr {
-	unsigned char boot_code[440];
-	unsigned char unique_mbr_signature[4];
-	unsigned char unknown[2];
+	u8 boot_code[440];
+	__le32 unique_mbr_signature;
+	__le16 unknown;
 	struct partition partition_record[4];
-	unsigned char signature[2];
-} __attribute__ ((packed)) legacy_mbr;
+	__le16 signature;
+} __packed legacy_mbr;
 
 #endif	/* _DISK_PART_EFI_H */
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [U-Boot] [PATCH v5 5/7] gpt: Support for GPT (GUID Partition Table) restoration
  2012-12-11 10:09 [U-Boot] [PATCH v5 0/7] gpt: GUID Partition Table (GPT) restoration Piotr Wilczek
                   ` (3 preceding siblings ...)
  2012-12-11 10:09 ` [U-Boot] [PATCH v5 4/7] gpt: The leXX_to_int() calls replaced with ones defined at <compiler.h> Piotr Wilczek
@ 2012-12-11 10:09 ` Piotr Wilczek
  2012-12-11 10:09 ` [U-Boot] [PATCH v5 6/7] gpt: Support for new "gpt" command Piotr Wilczek
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Piotr Wilczek @ 2012-12-11 10:09 UTC (permalink / raw)
  To: u-boot

From: Lukasz Majewski <l.majewski@samsung.com>

The restoration of GPT table (both primary and secondary) is now possible.
Function 'gpt_restore' presents example of partition restoration process.

Signed-off-by: Lukasz Majewski <l.majewski@samsung.com>
Signed-off-by: Piotr Wilczek <p.wilczek@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>

---
Changes in v5:
- changed function name 'set_gpt_table' to 'write_gpt_table'
- changed function name 'gpt_fill' to 'gpt_restore'
- moved function documentation to header file
- removed guid generation
- fixed partition layout check

Changes in v4:
- Add public functions for fill gpt header and entries
- Add public function for fill and save gpt tables on the basis of
  simple partions list information

Changes in v3:
- Replace printf with puts

Changes in v2:
- Move GPT Header and Page Table Entries generation code to cmd_gpt.c
- Provide clean API to use set_gpt_table function for GPT restoration on
  a block device

 disk/part_efi.c |  281 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 include/part.h  |   52 ++++++++++
 2 files changed, 330 insertions(+), 3 deletions(-)

diff --git a/disk/part_efi.c b/disk/part_efi.c
index 4aa3647..7665017 100644
--- a/disk/part_efi.c
+++ b/disk/part_efi.c
@@ -37,6 +37,8 @@
 #include <part_efi.h>
 #include <linux/ctype.h>
 
+DECLARE_GLOBAL_DATA_PTR;
+
 #if defined(CONFIG_CMD_IDE) || \
     defined(CONFIG_CMD_SATA) || \
     defined(CONFIG_CMD_SCSI) || \
@@ -62,13 +64,10 @@ static inline u32 efi_crc32(const void *buf, u32 len)
 
 static int pmbr_part_valid(struct partition *part);
 static int is_pmbr_valid(legacy_mbr * mbr);
-
 static int is_gpt_valid(block_dev_desc_t * dev_desc, unsigned long long lba,
 				gpt_header * pgpt_head, gpt_entry ** pgpt_pte);
-
 static gpt_entry *alloc_read_gpt_entries(block_dev_desc_t * dev_desc,
 				gpt_header * pgpt_head);
-
 static int is_pte_valid(gpt_entry * pte);
 
 static char *print_efiname(gpt_entry *pte)
@@ -114,6 +113,7 @@ static inline int is_bootable(gpt_entry *p)
 			sizeof(efi_guid_t));
 }
 
+#ifdef CONFIG_EFI_PARTITION
 /*
  * Public Functions (include/part.h)
  */
@@ -225,6 +225,281 @@ int test_part_efi(block_dev_desc_t * dev_desc)
 	return 0;
 }
 
+/**
+ * set_protective_mbr(): Set the EFI protective MBR
+ * @param dev_desc - block device descriptor
+ *
+ * @return - zero on success, otherwise error
+ */
+static int set_protective_mbr(block_dev_desc_t *dev_desc)
+{
+	legacy_mbr *p_mbr;
+
+	/* Setup the Protective MBR */
+	p_mbr = calloc(1, sizeof(p_mbr));
+	if (p_mbr == NULL) {
+		printf("%s: calloc failed!\n", __func__);
+		return -1;
+	}
+	/* Append signature */
+	p_mbr->signature = MSDOS_MBR_SIGNATURE;
+	p_mbr->partition_record[0].sys_ind = EFI_PMBR_OSTYPE_EFI_GPT;
+	p_mbr->partition_record[0].start_sect = 1;
+	p_mbr->partition_record[0].nr_sects = (u32) dev_desc->lba;
+
+	/* Write MBR sector to the MMC device */
+	if (dev_desc->block_write(dev_desc->dev, 0, 1, p_mbr) != 1) {
+		printf("** Can't write to device %d **\n",
+			dev_desc->dev);
+		free(p_mbr);
+		return -1;
+	}
+
+	free(p_mbr);
+	return 0;
+}
+
+/**
+ * string_uuid(); Convert UUID stored as string to bytes
+ *
+ * @param uuid - UUID represented as string
+ * @param dst - GUID buffer
+ *
+ * @return return 0 on successful conversion
+ */
+static int string_uuid(char *uuid, u8 *dst)
+{
+	efi_guid_t guid;
+	u16 b, c, d;
+	u64 e;
+	u32 a;
+	u8 *p;
+	u8 i;
+
+	const u8 uuid_str_len = 36;
+
+	/* The UUID is written in text: */
+	/* 1        9    14   19   24 */
+	/* xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx */
+
+	debug("%s: uuid: %s\n", __func__, uuid);
+
+	if (strlen(uuid) != uuid_str_len)
+		return -1;
+
+	for (i = 0; i < uuid_str_len; i++) {
+		if ((i == 8) || (i == 13) || (i == 18) || (i == 23)) {
+			if (uuid[i] != '-')
+				return -1;
+		} else {
+			if (!isxdigit(uuid[i]))
+				return -1;
+		}
+	}
+
+	a = (u32)simple_strtoul(uuid, NULL, 16);
+	b = (u16)simple_strtoul(uuid + 9, NULL, 16);
+	c = (u16)simple_strtoul(uuid + 14, NULL, 16);
+	d = (u16)simple_strtoul(uuid + 19, NULL, 16);
+	e = (u64)simple_strtoull(uuid + 24, 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);
+
+	memcpy(dst, guid.b, sizeof(efi_guid_t));
+
+	return 0;
+}
+
+int write_gpt_table(block_dev_desc_t *dev_desc,
+		gpt_header *gpt_h, gpt_entry *gpt_e)
+{
+	const int pte_blk_num = (gpt_h->num_partition_entries
+		* sizeof(gpt_entry)) / dev_desc->blksz;
+
+	u32 calc_crc32;
+	u64 val;
+
+	debug("max lba: %x\n", (u32) dev_desc->lba);
+	/* Setup the Protective MBR */
+	if (set_protective_mbr(dev_desc) < 0)
+		goto err;
+
+	/* Generate CRC for the Primary GPT Header */
+	calc_crc32 = efi_crc32((const unsigned char *)gpt_e,
+			      le32_to_cpu(gpt_h->num_partition_entries) *
+			      le32_to_cpu(gpt_h->sizeof_partition_entry));
+	gpt_h->partition_entry_array_crc32 = cpu_to_le32(calc_crc32);
+
+	calc_crc32 = efi_crc32((const unsigned char *)gpt_h,
+			      le32_to_cpu(gpt_h->header_size));
+	gpt_h->header_crc32 = cpu_to_le32(calc_crc32);
+
+	/* Write the First GPT to the block right after the Legacy MBR */
+	if (dev_desc->block_write(dev_desc->dev, 1, 1, gpt_h) != 1)
+		goto err;
+
+	if (dev_desc->block_write(dev_desc->dev, 2, pte_blk_num, gpt_e)
+	    != pte_blk_num)
+		goto err;
+
+	/* recalculate the values for the Second GPT Header */
+	val = le64_to_cpu(gpt_h->my_lba);
+	gpt_h->my_lba = gpt_h->alternate_lba;
+	gpt_h->alternate_lba = cpu_to_le64(val);
+	gpt_h->header_crc32 = 0;
+
+	calc_crc32 = efi_crc32((const unsigned char *)gpt_h,
+			      le32_to_cpu(gpt_h->header_size));
+	gpt_h->header_crc32 = cpu_to_le32(calc_crc32);
+
+	if (dev_desc->block_write(dev_desc->dev,
+				  le32_to_cpu(gpt_h->last_usable_lba + 1),
+				  pte_blk_num, gpt_e) != pte_blk_num)
+		goto err;
+
+	if (dev_desc->block_write(dev_desc->dev,
+				  le32_to_cpu(gpt_h->my_lba), 1, gpt_h) != 1)
+		goto err;
+
+	debug("GPT successfully written to block device!\n");
+	return 0;
+
+ err:
+	printf("** Can't write to device %d **\n", dev_desc->dev);
+	return -1;
+}
+
+int gpt_fill_pte(gpt_header *gpt_h, gpt_entry *gpt_e,
+		disk_partition_t *partitions, int parts)
+{
+	u32 offset = (u32)le32_to_cpu(gpt_h->first_usable_lba);
+	ulong start;
+	int i, k;
+	size_t name_len;
+#ifdef CONFIG_PARTITION_UUIDS
+	char *str_uuid;
+#endif
+
+	for (i = 0; i < parts; i++) {
+		/* partition starting lba */
+		start = partitions[i].start;
+		if (start && (start < offset)) {
+			printf("Partition overlap\n");
+			return -1;
+		}
+		if (start) {
+			gpt_e[i].starting_lba = cpu_to_le64(start);
+			offset = start + partitions[i].size;
+		} else {
+			gpt_e[i].starting_lba = cpu_to_le64(offset);
+			offset += partitions[i].size;
+		}
+		if (offset >= gpt_h->last_usable_lba) {
+			printf("Partitions layout exceds disk size\n");
+			return -1;
+		}
+		/* partition ending lba */
+		if ((i == parts - 1) && (partitions[i].size == 0))
+			/* extend the last partition to maximuim */
+			gpt_e[i].ending_lba = gpt_h->last_usable_lba;
+		else
+			gpt_e[i].ending_lba = cpu_to_le64(offset - 1);
+
+		/* partition type GUID */
+		memcpy(gpt_e[i].partition_type_guid.b,
+			&PARTITION_BASIC_DATA_GUID, 16);
+
+#ifdef CONFIG_PARTITION_UUIDS
+		str_uuid = partitions[i].uuid;
+		if (string_uuid(str_uuid, gpt_e[i].unique_partition_guid.b)) {
+			printf("Partition no. %d: invalid guid: %s\n",
+				i, str_uuid);
+			return -1;
+		}
+#endif
+
+		/* partition attributes */
+		memset(&gpt_e[i].attributes, 0,
+		       sizeof(gpt_entry_attributes));
+
+		/* partition name */
+		name_len = sizeof(gpt_e[i].partition_name)
+			/ sizeof(efi_char16_t);
+		for (k = 0; k < name_len; k++)
+			gpt_e[i].partition_name[k] =
+				(efi_char16_t)(partitions[i].name[k]);
+
+		debug("%s: name: %s offset[%d]: 0x%x size[%d]: 0x%lx\n",
+		      __func__, partitions[i].name, i,
+		      offset, i, partitions[i].size);
+	}
+
+	return 0;
+}
+
+int gpt_fill_header(block_dev_desc_t *dev_desc, gpt_header *gpt_h,
+		char *str_guid, int parts_count)
+{
+	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 (string_uuid(str_guid, gpt_h->disk_guid.b))
+		return -1;
+
+	return 0;
+}
+
+int gpt_restore(block_dev_desc_t *dev_desc, char *str_disk_guid,
+		disk_partition_t *partitions, int parts_count)
+{
+	int ret;
+
+	gpt_header *gpt_h = calloc(1, sizeof(gpt_header));
+	if (gpt_h == NULL) {
+		printf("%s: calloc failed!\n", __func__);
+		return -1;
+	}
+
+	gpt_entry *gpt_e = calloc(GPT_ENTRY_NUMBERS, sizeof(gpt_entry));
+	if (gpt_e == NULL) {
+		printf("%s: calloc failed!\n", __func__);
+		free(gpt_h);
+		return -1;
+	}
+
+	/* Generate Primary GPT header (LBA1) */
+	ret = gpt_fill_header(dev_desc, gpt_h, str_disk_guid, parts_count);
+	if (ret)
+		goto err;
+
+	/* Generate partition entries */
+	ret = gpt_fill_pte(gpt_h, gpt_e, partitions, parts_count);
+	if (ret)
+		goto err;
+
+	/* Write GPT partition table */
+	ret = write_gpt_table(dev_desc, gpt_h, gpt_e);
+
+err:
+	free(gpt_e);
+	free(gpt_h);
+	return ret;
+}
+#endif
+
 /*
  * Private functions
  */
diff --git a/include/part.h b/include/part.h
index 27ea283..c58a734 100644
--- a/include/part.h
+++ b/include/part.h
@@ -176,10 +176,62 @@ int   test_part_amiga (block_dev_desc_t *dev_desc);
 #endif
 
 #ifdef CONFIG_EFI_PARTITION
+#include <part_efi.h>
 /* disk/part_efi.c */
 int get_partition_info_efi (block_dev_desc_t * dev_desc, int part, disk_partition_t *info);
 void print_part_efi (block_dev_desc_t *dev_desc);
 int   test_part_efi (block_dev_desc_t *dev_desc);
+
+/**
+ * write_gpt_table() - Write the GUID Partition Table to disk
+ *
+ * @param dev_desc - block device descriptor
+ * @param gpt_h - pointer to GPT header representation
+ * @param gpt_e - pointer to GPT partition table entries
+ *
+ * @return - zero on success, otherwise error
+ */
+int write_gpt_table(block_dev_desc_t *dev_desc,
+		  gpt_header *gpt_h, gpt_entry *gpt_e);
+
+/**
+ * gpt_fill_pte(): Fill the GPT partition table entry
+ *
+ * @param gpt_h - GPT header representation
+ * @param gpt_e - GPT partition table entries
+ * @param partitions - list of partitions
+ * @param parts - number of partitions
+ *
+ * @return zero on success
+ */
+int gpt_fill_pte(gpt_header *gpt_h, gpt_entry *gpt_e,
+		disk_partition_t *partitions, int parts);
+
+/**
+ * gpt_fill_header(): Fill the GPT header
+ *
+ * @param dev_desc - block device descriptor
+ * @param gpt_h - GPT header representation
+ * @param str_guid - disk guid string representation
+ * @param parts_count - number of partitions
+ *
+ * @return - error on str_guid conversion error
+ */
+int gpt_fill_header(block_dev_desc_t *dev_desc, gpt_header *gpt_h,
+		char *str_guid, int parts_count);
+
+/**
+ * gpt_restore(): Restore GPT partition table
+ *
+ * @param dev_desc - block device descriptor
+ * @param str_disk_guid - disk GUID
+ * @param partitions - list of partitions
+ * @param parts - number of partitions
+ *
+ * @return zero on success
+ */
+int gpt_restore(block_dev_desc_t *dev_desc, char *str_disk_guid,
+		disk_partition_t *partitions, const int parts_count);
 #endif
 
 #endif /* _PART_H */
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [U-Boot] [PATCH v5 6/7] gpt: Support for new "gpt" command
  2012-12-11 10:09 [U-Boot] [PATCH v5 0/7] gpt: GUID Partition Table (GPT) restoration Piotr Wilczek
                   ` (4 preceding siblings ...)
  2012-12-11 10:09 ` [U-Boot] [PATCH v5 5/7] gpt: Support for GPT (GUID Partition Table) restoration Piotr Wilczek
@ 2012-12-11 10:09 ` Piotr Wilczek
  2012-12-11 10:09 ` [U-Boot] [PATCH v5 7/7] gpt: Enable support for GPT partition table restoration at Samsung's Trats Piotr Wilczek
  2012-12-14 16:04 ` [U-Boot] [PATCH v5 0/7] gpt: GUID Partition Table (GPT) restoration Tom Rini
  7 siblings, 0 replies; 9+ messages in thread
From: Piotr Wilczek @ 2012-12-11 10:09 UTC (permalink / raw)
  To: u-boot

New command - "gpt" is supported. It restores the GPT partition table.
It looks into the given environment variable for partitions definition.
It can be enabled at target configuration file with CONFIG_CMD_GPT.

Signed-off-by: Lukasz Majewski <l.majewski@samsung.com>
Signed-off-by: Piotr Wilczek <p.wilczek@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>

---
Changes in v5:
- rewritten 'do_gpt', 'gpt_mmc_default', 'set_gpt_info', 'extract_env',
  and 'extract_val' functions
- 'extract_val' function return value for given key (keys can be in
  any order)
- add 'write' command

Changes in v4:
- partions list can be passed as environment variable or directly as text
- each value in partions list can be passed as environment variable

Changes in v3:
- Remove unnecessary braces

Changes in 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

 common/Makefile  |    1 +
 common/cmd_gpt.c |  333 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 334 insertions(+)
 create mode 100644 common/cmd_gpt.c

diff --git a/common/Makefile b/common/Makefile
index c29a7d8..63b9f50 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -192,6 +192,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..da7705d
--- /dev/null
+++ b/common/cmd_gpt.c
@@ -0,0 +1,333 @@
+/*
+ * cmd_gpt.c -- GPT (GUID Partition Table) handling command
+ *
+ * Copyright (C) 2012 Samsung Electronics
+ * author: Lukasz Majewski <l.majewski@samsung.com>
+ * author: Piotr Wilczek <p.wilczek@samsung.com>
+ *
+ * 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 <common.h>
+#include <malloc.h>
+#include <command.h>
+#include <mmc.h>
+#include <part_efi.h>
+#include <exports.h>
+#include <linux/ctype.h>
+
+#ifndef CONFIG_PARTITION_UUIDS
+#error CONFIG_PARTITION_UUIDS must be enabled for CONFIG_CMD_GPT to be enabled
+#endif
+
+/**
+ * extract_env(): Expand env name from string format '&{env_name}'
+ *                and return pointer to the env (if the env is set)
+ *
+ * @param str - pointer to string
+ * @param env - pointer to pointer to extracted env
+ *
+ * @return - zero on successful expand and env is set
+ */
+static char extract_env(const char *str, char **env)
+{
+	char *e, *s;
+
+	if (!str || strlen(str) < 4)
+		return -1;
+
+	if ((strncmp(str, "${", 2) == 0) && (str[strlen(str) - 1] == '}')) {
+		s = strdup(str);
+		if (s == NULL)
+			return -1;
+		memset(s + strlen(s) - 1, '\0', 1);
+		memmove(s, s + 2, strlen(s) - 1);
+		e = getenv(s);
+		free(s);
+		if (e == NULL) {
+			printf("Environmental '%s' not set\n", str);
+			return -1; /* env not set */
+		}
+		*env = e;
+		return 0;
+	}
+
+	return -1;
+}
+
+/**
+ * extract_val(): Extract value from a key=value pair list (comma separated).
+ *                Only value for the given key is returend.
+ *                Function allocates memory for the value, remember to free!
+ *
+ * @param str - pointer to string with key=values pairs
+ * @param key - pointer to the key to search for
+ *
+ * @return - pointer to allocated string with the value
+ */
+static char *extract_val(const char *str, const char *key)
+{
+	char *v, *k;
+	char *s, *strcopy;
+	char *new = NULL;
+
+	strcopy = strdup(str);
+	if (strcopy == NULL)
+		return NULL;
+
+	s = strcopy;
+	while (s) {
+		v = strsep(&s, ",");
+		if (!v)
+			break;
+		k = strsep(&v, "=");
+		if (!k)
+			break;
+		if  (strcmp(k, key) == 0) {
+			new = strdup(v);
+			break;
+		}
+	}
+
+	free(strcopy);
+
+	return new;
+}
+
+/**
+ * set_gpt_info(): Fill partition information from string
+ *		function allocates memory, remember to free!
+ *
+ * @param dev_desc - pointer block device descriptor
+ * @param str_part - pointer to string with partition information
+ * @param str_disk_guid - pointer to pointer to allocated string with disk guid
+ * @param partitions - pointer to pointer to allocated partitions array
+ * @param parts_count - number of partitions
+ *
+ * @return - zero on success, otherwise error
+ *
+ */
+static int set_gpt_info(block_dev_desc_t *dev_desc,
+			const char *str_part,
+			char **str_disk_guid,
+			disk_partition_t **partitions,
+			u8 *parts_count)
+{
+	char *tok, *str, *s;
+	int i;
+	char *val, *p;
+	int p_count;
+	disk_partition_t *parts;
+	int errno = 0;
+
+	debug("%s: MMC lba num: 0x%x %d\n", __func__,
+	      (unsigned int)dev_desc->lba, (unsigned int)dev_desc->lba);
+
+	if (str_part == NULL)
+		return -1;
+
+	str = strdup(str_part);
+
+	/* extract disk guid */
+	s = str;
+	tok = strsep(&s, ";");
+	val = extract_val(tok, "uuid_disk");
+	if (!val) {
+		free(str);
+		return -2;
+	}
+	if (extract_env(val, &p))
+		p = val;
+	*str_disk_guid = strdup(p);
+	free(val);
+
+	if (strlen(s) == 0)
+		return -3;
+
+	i = strlen(s) - 1;
+	if (s[i] == ';')
+		s[i] = '\0';
+
+	/* calculate expected number of partitions */
+	p_count = 1;
+	p = s;
+	while (*p) {
+		if (*p++ == ';')
+			p_count++;
+	}
+
+	/* allocate memory for partitions */
+	parts = calloc(sizeof(disk_partition_t), p_count);
+
+	/* retrive partions data from string */
+	for (i = 0; i < p_count; i++) {
+		tok = strsep(&s, ";");
+
+		if (tok == NULL)
+			break;
+
+		/* uuid */
+		val = extract_val(tok, "uuid");
+		if (!val) { /* 'uuid' is mandatory */
+			errno = -4;
+			goto err;
+		}
+		if (extract_env(val, &p))
+			p = val;
+		if (strlen(p) >= sizeof(parts[i].uuid)) {
+			printf("Wrong uuid format for partition %d\n", i);
+			errno = -4;
+			goto err;
+		}
+		strcpy((char *)parts[i].uuid, p);
+		free(val);
+
+		/* name */
+		val = extract_val(tok, "name");
+		if (!val) { /* name is mandatory */
+			errno = -4;
+			goto err;
+		}
+		if (extract_env(val, &p))
+			p = val;
+		if (strlen(p) >= sizeof(parts[i].name)) {
+			errno = -4;
+			goto err;
+		}
+		strcpy((char *)parts[i].name, p);
+		free(val);
+
+		/* size */
+		val = extract_val(tok, "size");
+		if (!val) { /* 'size' is mandatory */
+			errno = -4;
+			goto err;
+		}
+		if (extract_env(val, &p))
+			p = val;
+		parts[i].size = ustrtoul(p, &p, 0);
+		parts[i].size /= dev_desc->blksz;
+		free(val);
+
+		/* start address */
+		val = extract_val(tok, "start");
+		if (val) { /* start address is optional */
+			if (extract_env(val, &p))
+				p = val;
+			parts[i].start = ustrtoul(p, &p, 0);
+			parts[i].start /= dev_desc->blksz;
+			free(val);
+		}
+	}
+
+	*parts_count = p_count;
+	*partitions = parts;
+	free(str);
+
+	return 0;
+err:
+	free(str);
+	free(*str_disk_guid);
+	free(parts);
+
+	return errno;
+}
+
+static int gpt_mmc_default(int dev, const char *str_part)
+{
+	int ret;
+	char *str_disk_guid;
+	u8 part_count = 0;
+	disk_partition_t *partitions = NULL;
+
+	struct mmc *mmc = find_mmc_device(dev);
+
+	if (mmc == NULL) {
+		printf("%s: mmc dev %d NOT available\n", __func__, dev);
+		return CMD_RET_FAILURE;
+	}
+
+	if (!str_part)
+		return -1;
+
+	/* fill partitions */
+	ret = set_gpt_info(&mmc->block_dev, str_part,
+			&str_disk_guid, &partitions, &part_count);
+	if (ret) {
+		if (ret == -1)
+			printf("No partition list provided\n");
+		if (ret == -2)
+			printf("Missing disk guid\n");
+		if ((ret == -3) || (ret == -4))
+			printf("Partition list incomplete\n");
+		return -1;
+	}
+
+	/* save partitions layout to disk */
+	gpt_restore(&mmc->block_dev, str_disk_guid, partitions, part_count);
+	free(str_disk_guid);
+	free(partitions);
+
+	return 0;
+}
+
+/**
+ * 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;
+	int dev = 0;
+	char *pstr;
+
+	if (argc < 5)
+		return CMD_RET_USAGE;
+
+	/* command: 'write' */
+	if ((strcmp(argv[1], "write") == 0) && (argc == 5)) {
+		/* device: 'mmc' */
+		if (strcmp(argv[2], "mmc") == 0) {
+			/* check if 'dev' is a number */
+			for (pstr = argv[3]; *pstr != '\0'; pstr++)
+				if (!isdigit(*pstr)) {
+					printf("'%s' is not a number\n",
+						argv[3]);
+					return CMD_RET_USAGE;
+				}
+			dev = (int)simple_strtoul(argv[3], NULL, 10);
+			/* write to mmc */
+			if (gpt_mmc_default(dev, argv[4]))
+				return CMD_RET_FAILURE;
+		}
+	} else {
+		return CMD_RET_USAGE;
+	}
+	return ret;
+}
+
+U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
+	"GUID Partition Table",
+	"<command> <interface> <dev> <partions_list>\n"
+	" - GUID partition table restoration\n"
+	" Restore GPT information on a device connected\n"
+	" to interface\n"
+);
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [U-Boot] [PATCH v5 7/7] gpt: Enable support for GPT partition table restoration at Samsung's Trats
  2012-12-11 10:09 [U-Boot] [PATCH v5 0/7] gpt: GUID Partition Table (GPT) restoration Piotr Wilczek
                   ` (5 preceding siblings ...)
  2012-12-11 10:09 ` [U-Boot] [PATCH v5 6/7] gpt: Support for new "gpt" command Piotr Wilczek
@ 2012-12-11 10:09 ` Piotr Wilczek
  2012-12-14 16:04 ` [U-Boot] [PATCH v5 0/7] gpt: GUID Partition Table (GPT) restoration Tom Rini
  7 siblings, 0 replies; 9+ messages in thread
From: Piotr Wilczek @ 2012-12-11 10:09 UTC (permalink / raw)
  To: u-boot

From: Lukasz Majewski <l.majewski@samsung.com>

Enable support for GPT partition table restoration at Samsung's Trats
development board.

Signed-off-by: Lukasz Majewski <l.majewski@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
CC: Minkyu Kang <mk7.kang@samsung.com>

---
Changes in v5:
- Modified partitions list format

Changes in v4:
- Modified default partitions list

Changes in v3:
- None

Changes in v2:
- New format for default GPT partitions (key=value pairs)
- replace size definitions with more readable description(1GiB instead of 1G)

 include/configs/trats.h |   28 +++++++++++++++++++++++++++-
 1 file changed, 27 insertions(+), 1 deletion(-)

diff --git a/include/configs/trats.h b/include/configs/trats.h
index 355029e..94ba55e 100644
--- a/include/configs/trats.h
+++ b/include/configs/trats.h
@@ -98,6 +98,7 @@
 #undef CONFIG_CMD_MTDPARTS
 #define CONFIG_CMD_MMC
 #define CONFIG_CMD_DFU
+#define CONFIG_CMD_GPT
 
 /* FAT */
 #define CONFIG_CMD_FAT
@@ -122,6 +123,26 @@
 #define CONFIG_BOOTBLOCK		"10"
 #define CONFIG_ENV_COMMON_BOOT		"${console} ${meminfo}"
 
+/* Tizen - partitions definitions */
+#define PARTS_CSA		"csa-mmc"
+#define PARTS_BOOTLOADER	"u-boot"
+#define PARTS_BOOT		"boot"
+#define PARTS_ROOT		"platform"
+#define PARTS_DATA		"data"
+#define PARTS_CSC		"csc"
+#define PARTS_UMS		"ums"
+
+#define PARTS_DEFAULT \
+	"uuid_disk=${uuid_gpt_disk};" \
+	"name="PARTS_CSA",size=8MiB,uuid=${uuid_gpt_"PARTS_CSA"};" \
+	"name="PARTS_BOOTLOADER",size=60MiB," \
+		"uuid=${uuid_gpt_"PARTS_BOOTLOADER"};" \
+	"name="PARTS_BOOT",size=100MiB,uuid=${uuid_gpt_"PARTS_BOOT"};" \
+	"name="PARTS_ROOT",size=1GiB,uuid=${uuid_gpt_"PARTS_ROOT"};" \
+	"name="PARTS_DATA",size=3GiB,uuid=${uuid_gpt_"PARTS_DATA"};" \
+	"name="PARTS_CSC",size=150MiB,uuid=${uuid_gpt_"PARTS_CSC"};" \
+	"name="PARTS_UMS",size=-,uuid=${uuid_gpt_"PARTS_UMS"}\0" \
+
 #define CONFIG_DFU_ALT \
 	"dfu_alt_info=" \
 	"u-boot mmc 80 400;" \
@@ -171,7 +192,8 @@
 	"mmcbootpart=2\0" \
 	"mmcrootpart=3\0" \
 	"opts=always_resume=1\0" \
-	CONFIG_DFU_ALT
+	"partitions=" PARTS_DEFAULT \
+	CONFIG_DFU_ALT \
 
 /* Miscellaneous configurable options */
 #define CONFIG_SYS_LONGHELP		/* undef to save memory */
@@ -208,6 +230,10 @@
 
 #define CONFIG_DOS_PARTITION
 
+/* GPT */
+#define CONFIG_EFI_PARTITION
+#define CONFIG_PARTITION_UUIDS
+
 #define CONFIG_SYS_INIT_SP_ADDR	(CONFIG_SYS_LOAD_ADDR - GENERATED_GBL_DATA_SIZE)
 #define CONFIG_SYS_CACHELINE_SIZE       32
 
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [U-Boot] [PATCH v5 0/7] gpt: GUID Partition Table (GPT) restoration
  2012-12-11 10:09 [U-Boot] [PATCH v5 0/7] gpt: GUID Partition Table (GPT) restoration Piotr Wilczek
                   ` (6 preceding siblings ...)
  2012-12-11 10:09 ` [U-Boot] [PATCH v5 7/7] gpt: Enable support for GPT partition table restoration at Samsung's Trats Piotr Wilczek
@ 2012-12-14 16:04 ` Tom Rini
  7 siblings, 0 replies; 9+ messages in thread
From: Tom Rini @ 2012-12-14 16:04 UTC (permalink / raw)
  To: u-boot

On Tue, Dec 11, 2012 at 11:09:41AM +0100, Piotr Wilczek wrote:

> This patch series provides a new command - "gpt" for eMMC partition table
> (in the GPT format) restoration.
> 
> As a pre-work, some cleanup at the part_efi.c file was performed to
> remove custom macros and make GPT related structures more readable.
> 
> Moreover the part_efi.h file has been moved to ./include directory to
> be easily available from other subsystems.
> 
> The GPT detailed description has been written to README.gpt file.
> 
> Tested at:
>         - Exynos4210 rev.1 - TRATS Samsung development board
> 
> 
> Chang Hyun Park (1):
>   gpt: The leXX_to_int() calls replaced with ones defined at
>     <compiler.h>
> 
> Lukasz Majewski (5):
>   vsprintf:fix: Change type returned by ustrtoul
>   part:efi: Move part_efi.h file to ./include
>   gpt:doc: GPT (GUID Partition Table) documentation
>   gpt: Support for GPT (GUID Partition Table) restoration
>   gpt: Enable support for GPT partition table restoration at Samsung's
>     Trats
> 
> Piotr Wilczek (1):
>   gpt: Support for new "gpt" command
> 
>  common/Makefile              |    1 +
>  common/cmd_gpt.c             |  333 +++++++++++++++++++++++++++++++++++
>  disk/part_efi.c              |  394 ++++++++++++++++++++++++++++++++++--------
>  doc/README.gpt               |  201 +++++++++++++++++++++
>  include/configs/trats.h      |   28 ++-
>  include/exports.h            |    2 +-
>  include/part.h               |   52 ++++++
>  {disk => include}/part_efi.h |   89 +++++-----
>  lib/vsprintf.c               |    2 +-
>  9 files changed, 982 insertions(+), 120 deletions(-)
>  create mode 100644 common/cmd_gpt.c
>  create mode 100644 doc/README.gpt
>  rename {disk => include}/part_efi.h (66%)

Applied to u-boot/master, thanks!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20121214/ce960373/attachment.pgp>

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2012-12-14 16:04 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-12-11 10:09 [U-Boot] [PATCH v5 0/7] gpt: GUID Partition Table (GPT) restoration Piotr Wilczek
2012-12-11 10:09 ` [U-Boot] [PATCH v5 1/7] vsprintf:fix: Change type returned by ustrtoul Piotr Wilczek
2012-12-11 10:09 ` [U-Boot] [PATCH v5 2/7] part:efi: Move part_efi.h file to ./include Piotr Wilczek
2012-12-11 10:09 ` [U-Boot] [PATCH v5 3/7] gpt:doc: GPT (GUID Partition Table) documentation Piotr Wilczek
2012-12-11 10:09 ` [U-Boot] [PATCH v5 4/7] gpt: The leXX_to_int() calls replaced with ones defined at <compiler.h> Piotr Wilczek
2012-12-11 10:09 ` [U-Boot] [PATCH v5 5/7] gpt: Support for GPT (GUID Partition Table) restoration Piotr Wilczek
2012-12-11 10:09 ` [U-Boot] [PATCH v5 6/7] gpt: Support for new "gpt" command Piotr Wilczek
2012-12-11 10:09 ` [U-Boot] [PATCH v5 7/7] gpt: Enable support for GPT partition table restoration at Samsung's Trats Piotr Wilczek
2012-12-14 16:04 ` [U-Boot] [PATCH v5 0/7] gpt: GUID Partition Table (GPT) restoration Tom Rini

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).