[U-Boot] [PATCH v6 07/18] disk: part: add support of GPT partitioning over MTD
Patrick Delaunay
patrick.delaunay at st.com
Thu May 11 07:51:57 UTC 2017
Signed-off-by: Patrick Delaunay <patrick.delaunay at st.com>
Reviewed-by: Christophe KERELLO <christophe.kerello at st.com>
---
Changes in v6:
- invalid offset my_lba in is_secondary_gpt_valid_mtd()
the secondary GPT header wasn't detected
- add comment for functions
Changes in v5:
- solve warning and error
(dont' include linux/mtd/mtd.h in part.h)
Changes in v4: None
Changes in v3: None
Changes in v2: None
disk/Kconfig | 17 ++
disk/Makefile | 1 +
disk/part_efi_mtd.c | 456 ++++++++++++++++++++++++++++++++++++++++++++++++++++
doc/README.gpt.mtd | 187 +++++++++++++++++++++
include/part.h | 42 ++++-
5 files changed, 701 insertions(+), 2 deletions(-)
create mode 100644 disk/part_efi_mtd.c
create mode 100644 doc/README.gpt.mtd
diff --git a/disk/Kconfig b/disk/Kconfig
index 9396562..886a089 100644
--- a/disk/Kconfig
+++ b/disk/Kconfig
@@ -96,6 +96,23 @@ config SPL_EFI_PARTITION
depends on SPL && PARTITIONS
default y if EFI_PARTITION
+config EFI_PARTITION_MTD
+ bool "Support EFI GPT over MTD"
+ depends on EFI_PARTITION
+ help
+ The GPT partition is normally defined only for block device with
+ built-in controller which manage flash translation layer
+ This option activate the GPT partition support over RAW device
+ using the MTD framework
+ - manage partition over MTD devices (as flash: NOR and NAND)
+ - extract MTD information
+ - update command gpt, mtdparts and part
+
+config SPL_EFI_PARTITION_MTD
+ bool "Enable EFI GPT over MTD for SPL"
+ depends on SPL_EFI_PARTITION
+ default y if EFI_PARTITION_MTD
+
config PARTITION_UUIDS
bool "Enable support of UUID for partition"
depends on PARTITIONS
diff --git a/disk/Makefile b/disk/Makefile
index 12c0531..0d01160 100644
--- a/disk/Makefile
+++ b/disk/Makefile
@@ -13,3 +13,4 @@ obj-$(CONFIG_$(SPL_)DOS_PARTITION) += part_dos.o
obj-$(CONFIG_$(SPL_)ISO_PARTITION) += part_iso.o
obj-$(CONFIG_$(SPL_)AMIGA_PARTITION) += part_amiga.o
obj-$(CONFIG_$(SPL_)EFI_PARTITION) += part_efi.o
+obj-$(CONFIG_$(SPL_)EFI_PARTITION_MTD) += part_efi_mtd.o
diff --git a/disk/part_efi_mtd.c b/disk/part_efi_mtd.c
new file mode 100644
index 0000000..0c83f34
--- /dev/null
+++ b/disk/part_efi_mtd.c
@@ -0,0 +1,456 @@
+/*
+ * Copyright (C) 2016 STMicroelectronics .
+ * Patrick Delaunay <patrick.delaunay at st.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <asm/unaligned.h>
+#include <common.h>
+#include <command.h>
+#include <ide.h>
+#include <inttypes.h>
+#include <malloc.h>
+#include <memalign.h>
+#include <part_efi.h>
+#include <linux/ctype.h>
+#include <linux/mtd/mtd.h>
+#include "part_efi_int.h"
+
+static int is_primary_gpt_valid_mtd(struct mtd_info *mtd,
+ lbaint_t lba,
+ void **buf,
+ gpt_header **pgpt_head,
+ gpt_entry **pgpt_pte)
+{
+ gpt_header *gpt_h;
+ gpt_entry *gpt_e;
+ uint32_t size;
+ uint64_t offset;
+ int ret;
+ size_t retlen;
+ lbaint_t my_lba;
+ u32 gpt_e_size = PAD_SIZE(GPT_ENTRY_NUMBERS * sizeof(gpt_entry),
+ MTD_LBA_SIZE);
+
+ size = gpt_e_size + 2 * MTD_LBA_SIZE;
+ /* skip bad block */
+ offset = 0;
+ while (mtd_block_isbad(mtd, offset)) {
+ printf("bad block at 0x%llx\n", offset);
+ offset += mtd->erasesize;
+ if (offset >= mtd->size) {
+ printf("*** ERROR: too many bad block ***\n");
+ return -1;
+ }
+ }
+
+ debug("primary offset = 0x%llx\n", offset);
+ /* Read primary GPT from device */
+ ret = mtd_read(mtd, offset, size, &retlen, *buf);
+ if (ret || (retlen != size)) {
+ printf("*** ERROR: Can't read primary GPT ***\n");
+ return -1;
+ }
+
+ /* determine start of GPT Header & Entries in the buffer */
+ gpt_h = *buf + (1 * MTD_LBA_SIZE);
+ gpt_e = *buf + (2 * MTD_LBA_SIZE);
+ my_lba = lldiv(offset, MTD_LBA_SIZE) + GPT_PRIMARY_PARTITION_TABLE_LBA;
+
+ if (!validate_gpt_header(gpt_h, my_lba, lba) &&
+ !validate_gpt_entries(gpt_h, gpt_e)) {
+ *pgpt_head = gpt_h;
+ *pgpt_pte = gpt_e;
+ return 0;
+ }
+
+ return -1;
+}
+
+static int is_secondary_gpt_valid_mtd(struct mtd_info *mtd,
+ lbaint_t lba,
+ void **buf,
+ gpt_header **pgpt_head,
+ gpt_entry **pgpt_pte)
+{
+ gpt_header *gpt_h;
+ gpt_entry *gpt_e;
+ uint32_t size;
+ uint64_t offset;
+ int ret;
+ size_t retlen;
+ lbaint_t my_lba;
+ u32 gpt_e_size = PAD_SIZE(GPT_ENTRY_NUMBERS * sizeof(gpt_entry),
+ MTD_LBA_SIZE);
+
+ size = gpt_e_size + 2 * MTD_LBA_SIZE;
+ /* skip bad block */
+ offset = mtd->size;
+ while (mtd_block_isbad(mtd, offset - mtd->erasesize)) {
+ offset -= mtd->erasesize;
+ printf("bad block at 0x%llx\n", offset);
+ if (offset <= mtd->erasesize) {
+ printf("*** ERROR: too many bad block ***\n");
+ return -1;
+ }
+ }
+
+ /* Read backup GPT from device : end of the last valid block */
+ size = gpt_e_size + MTD_LBA_SIZE;
+
+ debug("backup offset = 0x%llx\n", offset - size);
+ ret = mtd_read(mtd, offset - size, size, &retlen, *buf);
+ if (ret || (retlen != size)) {
+ printf("*** ERROR: Can't read backup GPT ***\n");
+ return -1;
+ }
+
+ /* determine start of GPT Header & Entries in the buffer */
+ gpt_h = *buf + gpt_e_size;
+ gpt_e = *buf;
+ my_lba = lldiv(offset, MTD_LBA_SIZE) - 1;
+
+ if (!validate_gpt_header(gpt_h, my_lba, lba) &&
+ !validate_gpt_entries(gpt_h, gpt_e)) {
+ *pgpt_head = gpt_h;
+ *pgpt_pte = gpt_e;
+ return 0;
+ }
+
+ return -1;
+}
+
+static int is_gpt_valid_mtd(struct mtd_info *mtd,
+ void **buf,
+ gpt_header **pgpt_head,
+ gpt_entry **pgpt_pte)
+{
+ u32 gpt_e_size = PAD_SIZE(GPT_ENTRY_NUMBERS * sizeof(gpt_entry),
+ MTD_LBA_SIZE);
+ lbaint_t lba;
+
+ if (!mtd || !pgpt_head || !pgpt_pte) {
+ printf("%s: Invalid Argument(s)\n", __func__);
+ return 0;
+ }
+
+ *pgpt_head = NULL;
+ *pgpt_pte = NULL;
+ *buf = malloc(gpt_e_size + 2 * MTD_LBA_SIZE);
+ if (!buf)
+ return -ENOMEM;
+
+ lba = lldiv(mtd->size, MTD_LBA_SIZE);
+ if (!is_primary_gpt_valid_mtd(mtd, lba, buf, pgpt_head, pgpt_pte))
+ return 1;
+
+ printf("%s: *** ERROR: Invalid GPT ***\n", __func__);
+
+ if (!is_secondary_gpt_valid_mtd(mtd, lba, buf, pgpt_head, pgpt_pte)) {
+ printf("%s: *** Using Backup GPT ***\n", __func__);
+ return 1;
+ }
+ printf("%s: *** ERROR: Invalid Backup GPT ***\n", __func__);
+
+ free(*buf);
+
+ return 0;
+}
+
+static int gpt_fill_header_mtd(struct mtd_info *mtd, gpt_header *gpt_h,
+ char *str_guid, int parts_count)
+{
+ uint32_t erasesize;
+ uint64_t offset_p_gpt, offset_s_gpt;
+ __le64 my_lba;
+ __le64 alternate_lba;
+ u32 gpt_e_size = PAD_SIZE(GPT_ENTRY_NUMBERS * sizeof(gpt_entry),
+ MTD_LBA_SIZE);
+
+ /* one mtd block is not enought for MBR and GPT */
+ if ((gpt_e_size + 2 * MTD_LBA_SIZE) > mtd->erasesize)
+ return -1;
+
+ erasesize = lldiv(mtd->erasesize, MTD_LBA_SIZE);
+
+ /* GPT location : skip bad block */
+ offset_p_gpt = 0;
+ while (mtd_block_isbad(mtd, offset_p_gpt)) {
+ printf("bad block at 0x%llx\n", offset_p_gpt);
+ offset_p_gpt += mtd->erasesize;
+ if (offset_p_gpt >= mtd->size)
+ return -1;
+ }
+ /* primary GPT : 17 first LBA of last good block */
+ my_lba = lldiv(offset_p_gpt, MTD_LBA_SIZE) + 1;
+
+ offset_s_gpt = mtd->size;
+ while (mtd_block_isbad(mtd, offset_s_gpt - mtd->erasesize)) {
+ offset_s_gpt -= mtd->erasesize;
+ printf("bad block at 0x%llx\n", offset_s_gpt);
+ if (offset_s_gpt <= mtd->erasesize)
+ return -1;
+ }
+ /* secondary GPT : 16 LBA of last good block */
+ alternate_lba = lldiv(offset_s_gpt, MTD_LBA_SIZE) - 1;
+
+ /* only one good block (primary and secondary on same block) */
+ if (offset_p_gpt == ((offset_s_gpt - mtd->erasesize)))
+ return -1;
+
+ 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(my_lba);
+ gpt_h->alternate_lba = cpu_to_le64(alternate_lba);
+ gpt_h->first_usable_lba = cpu_to_le64(my_lba - 1 + erasesize);
+ gpt_h->last_usable_lba = cpu_to_le64(alternate_lba - erasesize);
+ gpt_h->partition_entry_lba = cpu_to_le64(my_lba + 1);
+ 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_str_to_bin(str_guid, gpt_h->disk_guid.b, UUID_STR_FORMAT_GUID))
+ return -1;
+
+ return 0;
+}
+
+static int mtd_erase_write_block(struct mtd_info *mtd,
+ uint64_t offset,
+ void *buf,
+ size_t len)
+{
+ struct erase_info erase;
+ int ret;
+ size_t retlen;
+ u_char *verify_buf;
+
+ erase.mtd = mtd;
+ erase.len = mtd->erasesize;
+ erase.addr = offset & ~(mtd->erasesize - 1); /* aligned erase offset */
+ erase.callback = NULL;
+
+ debug(" erase at 0x%llx\n", erase.addr);
+ ret = mtd_erase(mtd, &erase);
+ if (ret != 0) {
+ printf("** mark bad block 0x%llx on MTD device %s **\n",
+ erase.addr, mtd->name);
+ ret = mtd_block_markbad(mtd, erase.addr);
+ if (ret)
+ error("cannot mark bad at offset 0x%llx, error %d",
+ offset, ret);
+ return -1;
+ }
+
+ /* mtd write */
+ ret = mtd_write(mtd, offset, len, &retlen, buf);
+ if (ret != 0) {
+ error("Write error %d\n", ret);
+ return ret;
+ }
+
+ verify_buf = malloc(len);
+ if (!verify_buf)
+ return -ENOMEM;
+
+ ret = mtd_read(mtd, offset, len, &retlen, verify_buf);
+ if (ret) {
+ error("Read failed 0x%x, %d\n", (u32)offset, ret);
+ free(verify_buf);
+ return ret;
+ }
+
+ if (memcmp(buf, verify_buf, len)) {
+ error("Verify failed at 0x%x\n", (u32)offset);
+ return -EIO;
+ }
+
+ free(verify_buf);
+
+ return 0;
+}
+
+static void prepare_mbr_gpt_header_mtd(void *buf,
+ struct mtd_info *mtd,
+ gpt_header *gpt_h,
+ gpt_entry *gpt_e)
+{
+ legacy_mbr *p_mbr = buf;
+ u32 calc_crc32;
+
+ /* 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);
+
+ /* Setup the Protective MBR */
+ 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) lldiv(mtd->size,
+ MTD_LBA_SIZE) - 1;
+}
+
+static int write_gpt_table_mtd(struct mtd_info *mtd,
+ gpt_header *gpt_h,
+ gpt_entry *gpt_e)
+{
+ const int pte_blk_cnt = PAD_COUNT((gpt_h->num_partition_entries
+ * sizeof(gpt_entry)), MTD_LBA_SIZE);
+ uint64_t offset;
+ void *buf;
+ u32 gpt_e_size = PAD_SIZE(GPT_ENTRY_NUMBERS * sizeof(gpt_entry),
+ MTD_LBA_SIZE);
+ u32 buf_size, p_size, s_size;
+
+ p_size = gpt_e_size + 2 * MTD_LBA_SIZE;
+ s_size = roundup(gpt_e_size + MTD_LBA_SIZE, mtd->writesize);
+ buf_size = max(p_size, s_size);
+ buf = malloc(buf_size);
+ if (!buf)
+ return -ENOMEM;
+
+ memset(buf, 0x0, p_size);
+
+ prepare_mbr_gpt_header_mtd(buf, mtd, gpt_h, gpt_e);
+
+ /* GPT Header (1 block) */
+ memcpy(buf + (GPT_PRIMARY_PARTITION_TABLE_LBA * MTD_LBA_SIZE),
+ gpt_h, sizeof(*gpt_h));
+ memcpy(buf + ((GPT_PRIMARY_PARTITION_TABLE_LBA + 1) * MTD_LBA_SIZE),
+ gpt_e, sizeof(gpt_entry) * pte_blk_cnt);
+
+ offset = ALIGN(le64_to_cpu(gpt_h->my_lba -
+ GPT_PRIMARY_PARTITION_TABLE_LBA)
+ * MTD_LBA_SIZE,
+ mtd->erasesize);
+
+ debug("primary offset = 0x%llx\n", offset);
+
+ if (mtd_erase_write_block(mtd, offset, buf, p_size))
+ goto err;
+
+ prepare_backup_gpt_header(gpt_h, pte_blk_cnt);
+
+ memset(buf, 0x0, s_size);
+
+ offset = (le64_to_cpu(gpt_h->my_lba) + 1) * MTD_LBA_SIZE - s_size;
+ memcpy(buf + s_size - MTD_LBA_SIZE, gpt_h, sizeof(*gpt_h));
+ memcpy(buf + s_size - MTD_LBA_SIZE - gpt_e_size,
+ gpt_e, sizeof(gpt_entry) * pte_blk_cnt);
+
+ debug("backup offset = 0x%llx\n", offset);
+
+ if (mtd_erase_write_block(mtd, offset, buf, s_size))
+ goto err;
+
+ free(buf);
+ debug("GPT successfully written to MTD device!\n");
+
+ return 0;
+
+ err:
+ free(buf);
+ printf("** Can't write to MTD device %s **\n", mtd->name);
+
+ return -EIO;
+}
+
+/*
+ * Public Functions (include/part.h)
+ */
+int gpt_restore_mtd(struct mtd_info *mtd, char *str_disk_guid,
+ disk_partition_t *partitions, const int parts_count)
+{
+ int ret;
+ gpt_header *gpt_h = calloc(1, PAD_SIZE(sizeof(gpt_header),
+ MTD_LBA_SIZE));
+ gpt_entry *gpt_e;
+
+ if (gpt_h == NULL) {
+ printf("%s: calloc failed!\n", __func__);
+ return -ENOMEM;
+ }
+
+ gpt_e = calloc(1, PAD_SIZE(GPT_ENTRY_NUMBERS
+ * sizeof(gpt_entry),
+ MTD_LBA_SIZE));
+ if (gpt_e == NULL) {
+ printf("%s: calloc failed!\n", __func__);
+ free(gpt_h);
+ return -ENOMEM;
+ }
+
+ /* Generate Primary GPT header (LBA1) */
+ ret = gpt_fill_header_mtd(mtd, 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_mtd(mtd, gpt_h, gpt_e);
+
+err:
+ free(gpt_e);
+ free(gpt_h);
+
+ return ret;
+}
+
+void part_print_efi_mtd(struct mtd_info *mtd)
+{
+ void *buf;
+ gpt_header *gpt_head;
+ gpt_entry *gpt_pte;
+
+ if (!is_gpt_valid_mtd(mtd, &buf, &gpt_head, &gpt_pte))
+ return;
+
+ part_print_gpt(gpt_head, gpt_pte);
+
+ /* Remember to free buffer */
+ free(buf);
+}
+
+int part_get_info_efi_mtd(struct mtd_info *mtd, int part,
+ disk_partition_t *info)
+{
+ void *buf;
+ gpt_header *gpt_head;
+ gpt_entry *gpt_pte;
+
+ if (!mtd || !info || part < 1) {
+ printf("%s: Invalid Argument(s)\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!is_gpt_valid_mtd(mtd, &buf, &gpt_head, &gpt_pte))
+ return -1;
+
+ if (part > le32_to_cpu(gpt_head->num_partition_entries) ||
+ !is_pte_valid(&gpt_pte[part - 1])) {
+ debug("%s: *** ERROR: Invalid partition number %d ***\n",
+ __func__, part);
+ free(buf);
+ return -EINVAL;
+ }
+
+ part_get_disk_info(part, MTD_LBA_SIZE, gpt_pte, info);
+
+ /* Remember to free buffer */
+ free(buf);
+
+ return 0;
+}
diff --git a/doc/README.gpt.mtd b/doc/README.gpt.mtd
new file mode 100644
index 0000000..326b8f8
--- /dev/null
+++ b/doc/README.gpt.mtd
@@ -0,0 +1,187 @@
+#
+#
+# SPDX-License-Identifier: GPL-2.0+
+
+Glossary:
+========
+- GPT (GUID Partition Table) - it is the EFI standard part
+- MTD (Memory Technology Device) - abstraction layer for RAW flah device
+
+Introduction:
+=============
+This document describes the GPT support on MTD and usage of
+the associated command in U-Boot.
+
+The GPT is normally defined only for block device with built-in controller
+which manage flash translation layer (FTL) as MMC, SD, USB or ATA.
+
+For raw flash device, the MTD partionning are usally defined in U-Boot
+environment and provided to kernel (see mtdparts command).
+
+U-Boot support GPT for MTD device to save the partition informations of
+raw flash device directly in this device (usefull for CONFIG_ENV_IS_NOWHERE)
+and to use these informations to support MTD devices in DISTRO without
+hardcoded MTD partitioning in U-Boot environment
+
+The GPT support on top of MTD is defined under CONFIG_EFI_PARTITION_MTD.
+
+GPT on MTD brief explanation:
+=============================
+
+The GPT standard is respected (header and field meaning).
+
+The GPT header and each partition need to be eraseblock-align to allow
+individual udpate for header or partiton.
+
+The primary and the backup GPT header are located in the first and
+the last -not bad- eraseblock.
+
+We assume that one eraseblock is enought for MBR and GPT header
+(size = 17 KB for 128 entry)
+
+So it not compatible with the feature CONFIG_SPI_FLASH_USE_4K_SECTORS
+
+ Layout:
+ -------
+
+ ----------------------------------------------------------
+ LBA 0-33 |Protective MBR + Primary GPT | 1rst eraseblock
+ --------------------------------------------------
+ LBA 34 | (not used) |
+ LBA N-1 | |
+ ----------------------------------------------------------
+ LBA N |Partition 1 | 2nd eraseblock
+ | | = first usable
+ -----------------------------------
+ |Partition 2 |
+ | |
+ ----------------------------------- last-1 eraseblock
+ LBA M |Partition n | = last usable
+ ----------------------------------------------------------
+ LBA M+1 | (not used) | last eraseblock
+ LBA -35 | |
+ --------------------------------------------------
+ LBA -1 to -34 |Backup GPT Header |
+ ----------------------------------------------------------
+
+ NB: this layout change (LBA0 and LBA-1) if bad block are present
+
+ GPT header:
+ -----------
+
+ for details of GPT header, see README.gpt
+
+ "Current LBA" and "Backup LBA" give the location of the primary and
+ secondary GPT header.
+
+ All the bad block are detected and skipped when the GPT header is build.
+
+ For Primary GPT:
+
+ - Current LBA = 2nd LBA of the first good eraseblock
+
+ - Backup LBA = Last LBA of the last good block
+
+ - First usable LBA = First LBA of the first usable eraseblock
+ i.e. the block after primary GPT one
+ Current LBA - 1 + erase block size
+
+ - Last usable LBA = Last LBA of the last usable eraseblock
+ i.e. the block before backup GPT one
+ Backup LBA - erase block size
+
+ Bad Block management (NAND):
+ ---------------------------
+ As the bad blocks are skipped, Current LBA and Backup LBA give the real
+ location of primary and backup GPT header
+
+ warning: the first and the last usable LBA are not guarantee
+ to be in a good block
+
+
+ Typically, the last 4 erase blocks for NAND are used for the bad block
+ table (BBT, see bbt_options and NAND_BBT_USE_FLASH).
+ They are indicated bad by MTD framework and they are also skipped.
+ So the layout for NAND with bad :
+
+ NAND layout with bad blocks:
+ ----------------------------------------------------------
+ N * BAD (*) | | skipped bad
+ -----------------------------------------------------------
+ |Protective MBR | 1rst good eraseblock
+ |Primary GPT Header |
+ | |
+ -------------------------------------------
+ | | = first usable
+ | |
+ | Partitions |
+ | |
+ | | = last usable
+ -------------------------------------------
+ | |
+ |Backup GPT Header | last good eraseblock
+ ----------------------------------------------------------
+ M * BAD (*) | | skipped bad
+ ----------------------------------------------------------
+ BBT => BAD (*) | | skipped 4 blocks
+ ----------------------------------------------------------
+ (*) BBT and block marked bad are skipped
+
+
+Drawbacks:
+==========
+1. 2 eraseblocks are used in the device just to save the GPT headers
+ (primary and backup)
+
+2. for device with back block (NAND), any read request can disturb the device
+ so the GPT header should be refreshed when one fixable bit-flip ECC error is
+ detected...
+ but it is not the case today
+
+3. for gpt write the eraseblock for the primary or backup GPT header
+ (expected good) can become bad for the erase request
+
+ And then U-Boot will mark this block bad
+
+ In this case the first / last usable LBA need to change and to skip the new
+ bad block, so header need to be recomputed
+ => the requested gpt write command failed to force new request
+ PS: the next request will work (skip the new bad block)
+
+ And as the first / last usable LBA can change the same partionning after
+ the block is marked bad
+
+GPT on MTD commands:
+====================
+some command are modified to support GPT on MTD devices under CONFIG_EFI_PARTITION_MTD
+
+ Creating GPT on MTD partitions:
+ -------------------------------
+
+ 1. Define partition layout in the environment.
+ "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
+ name=kernel,size=60MiB,uuid=...;"
+
+ 2. From U-Boot prompt type:
+ gpt write nand 0 $partitions
+ gpt write nor 0 $partitions
+
+ List GPT partition on MTD:
+ ---------------------------------
+ part list nand 0
+ part list nor 0
+
+ to find bootable partition (used for distro):
+
+ part list nand 0 -bootable nand_boot_part
+ part list nor 0 -bootable nor_boot_part
+
+ NB: bootable partition can be used with UBIFS
+
+ Generate MTD partitions from GPT:
+ ---------------------------------
+ mtdparts gpt nand0
+ mtdparts gpt nor0
+
+ Then to check mtd partition created with:
+ mtdparts
diff --git a/include/part.h b/include/part.h
index b6d1b33..8896b5c 100644
--- a/include/part.h
+++ b/include/part.h
@@ -311,7 +311,6 @@ int gpt_fill_header(struct blk_desc *dev_desc, gpt_header *gpt_h,
*/
int gpt_restore(struct blk_desc *dev_desc, char *str_disk_guid,
disk_partition_t *partitions, const int parts_count);
-
/**
* is_valid_gpt_buf() - Ensure that the Primary GPT information is valid
*
@@ -366,7 +365,46 @@ int gpt_verify_headers(struct blk_desc *dev_desc, gpt_header *gpt_head,
int gpt_verify_partitions(struct blk_desc *dev_desc,
disk_partition_t *partitions, int parts,
gpt_header *gpt_head, gpt_entry **gpt_pte);
-#endif
+
+#ifdef CONFIG_EFI_PARTITION_MTD
+
+struct mtd_info;
+
+#define MTD_LBA_SIZE 512
+/**
+ * gpt_restore_mtd() - Restore GPT partition table on MTD device
+ *
+ * @param mtd - mtd device descriptor
+ * @param str_disk_guid - disk GUID
+ * @param partitions - list of partitions
+ * @param parts_count - number of partitions
+ *
+ * @return - '0' on success, otherwise error
+ */
+int gpt_restore_mtd(struct mtd_info *mtd, char *str_disk_guid,
+ disk_partition_t *partitions, const int parts_count);
+
+/*
+ * part_print_efi() - display GPT Partition information for MTD device
+ *
+ * @param mtd_info - pointer to MTD device descriptor
+ */
+void part_print_efi_mtd(struct mtd_info *mtd_info);
+
+/*
+ * part_get_info_efi_mtd() - extract partition information for one GPT entry
+ * for a MTD device
+ *
+ * @param mtd_info - pointer to MTD device descriptor
+ * @param part - index of entry in gpt_pte
+ * @param gpt_pte - pointer to disk partition (output)
+ *
+ * @return - '0' on success, otherwise error
+ */
+int part_get_info_efi_mtd(struct mtd_info *mtd, int part,
+ disk_partition_t *info);
+#endif /* CONFIG_EFI_PARTITION_MTD */
+#endif /* CONFIG_EFI_PARTITION */
#if CONFIG_IS_ENABLED(DOS_PARTITION)
/**
--
1.9.1
More information about the U-Boot
mailing list