All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 0/6] Introduce NVIDIA Tegra Partition Table
@ 2020-05-15  1:41 ` Dmitry Osipenko
  0 siblings, 0 replies; 17+ messages in thread
From: Dmitry Osipenko @ 2020-05-15  1:41 UTC (permalink / raw)
  To: Jens Axboe, Thierry Reding, Jonathan Hunter,
	Michał Mirosław, David Heidelberg, Peter Geis,
	Stephen Warren, Nicolas Chauvet, Ulf Hansson, Adrian Hunter,
	Billy Laws, Nils Östlund, Christoph Hellwig, Ard Biesheuvel,
	Davidlohr Bueso
  Cc: linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-block-u79uwXL29TY76Z2rM5mHXA, Andrey Danin, Gilles Grandou,
	Ryan Grachek, linux-mmc-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, linux-efi

Hello,

This series adds support for the NVIDIA Tegra Partition Table format,
which is needed in order to support consumer-grade Tegra-based devices
by the upstream kernel.  These devices have Secure Boot enabled and it
can't be disabled, and thus, it's not possible to easily modify bootloader
and eMMC storage partitioning.

Big thanks to everyone who helped with figuring out the TegraPT format
and with testing!

Changelog:

v4: - Scanning of the eMMC boot partitions has been dropped because it
      requires a bit too messy hacks in the kernel. We can live without
      this feature, at least for now it's not really needed.

    - Instead of the dropped boot partitions scanning, the "gpt_sector="
      command line option has been brought back [1]. But now it's done
      in a different way, not bothering platforms other than Tegra and
      not touching block devices other than eMMC, which was requested during
      of the [1] review. The "gpt_sector=" usage is needed when partition
      table is inaccessible by kernel, which is the case for the Ouya game
      console device for example. Please note that "gpt_sector=" is not
      available on all devices, such devices will fall back to the TegraPT,
      Samsung Galaxy Tab 10.1 is an example of a such device.

      [1] https://patchwork.ozlabs.org/project/linux-tegra/patch/20200219162339.16192-1-digetx-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org/

    - We got a bit more broad testing and discovered that Samsung Galaxy
      Tab 10.1 uses 2K logical sectors instead of 4K. So the 2K sectors
      are supported now by the TegraPT parser. Thanks to Nils Östlund for
      the testing!

    - TegraPT parser now utilizes "tegraboot=" cmdline option which is
      passed to kernel by the NVIDIA's bootloader. It's used for verifying
      that SDMMC device is *the* boot source.

    - Added patch that exposes Boot Configuration Table to userspace via
      sysfs. Thanks to Michał Mirosław for the suggestion!

    - Misc changes:
        - The EB2 (second bootloader) partition is added to the list of
          known partitions. Used by the Galaxy Tab 10.

        - The blkdev logical sector size is checked now, for consistency.
          It always should be 512 bytes on the supported/tested devices.

        - Verbose error messages are replaced with pr_debug().

v3: - Fixed "BUG: KASAN: slab-out-of-bounds in tegra_partition". Thanks to
      Peter Geis for noticing the problem.

    - The MMC boot partitions scanning is now opt-in. See this patch:

        mmc: block: Support partition-table scanning on boot partitions

    - The found MMC boot partitions won't be assigned to the MMC boot
      block device ever due to the new GENHD_FL_PART_SCAN_ONCE flag.

      This makes us to ensure that the old behavior of the MMC core is
      preserved for a non-Tegra MMC-block users.

    New patches in v3:

        block: Introduce GENHD_FL_PART_SCAN_ONCE
        mmc: sdhci-tegra: Enable boot partitions scanning on Tegra20 and Tegra30

v2: - Addressed v1 review comments from Stephen Warren by using BIT for
      locating BCT position in IRAM.

    - Added more validations to the TegraPT parser: partition type is
      verified, eMMC instance ID is verified.

    - TegraPT parser now doesn't touch any devices other than eMMC.

    - EKS (encrypted keys) partition is blacklisted now.

    - Implemented eMMC boot partitions scanning. These new patches are
      added in a result:

        mmc: block: Add mmc_bdev_to_part_type() helper
        mmc: block: Add mmc_bdev_to_area_type() helper
        mmc: block: Add MMC_QUIRK_RESCAN_MAIN_BLKDEV
        mmc: block: Enable partition-table scanning for boot partitions
        partitions/tegra: Implement eMMC boot partitions scanning

Dmitry Osipenko (6):
  mmc: core: Add raw_boot_mult field to mmc_ext_csd
  mmc: block: Add mmc_bdev_to_card() helper
  partitions: Introduce NVIDIA Tegra Partition Table
  partitions/efi: Support GPT entry lookup at a non-standard location
  partitions/tegra: Support gpt_sector= command line option
  soc/tegra: Expose Boot Configuration Table via sysfs

 arch/arm/mach-tegra/tegra.c   |  58 ++++
 block/partitions/Kconfig      |   8 +
 block/partitions/Makefile     |   1 +
 block/partitions/check.h      |   2 +
 block/partitions/core.c       |   4 +
 block/partitions/efi.c        |  16 +
 block/partitions/efi.h        |   2 +
 block/partitions/tegra.c      | 603 ++++++++++++++++++++++++++++++++++
 drivers/mmc/core/block.c      |  15 +
 drivers/mmc/core/mmc.c        |   2 +
 drivers/soc/tegra/Makefile    |   1 +
 drivers/soc/tegra/bootdata.c  |  51 +++
 drivers/soc/tegra/common.c    |  17 +
 include/linux/mmc/blkdev.h    |  13 +
 include/linux/mmc/card.h      |   1 +
 include/soc/tegra/bootdata.h  |  48 +++
 include/soc/tegra/common.h    |  12 +
 include/soc/tegra/partition.h |  83 +++++
 18 files changed, 937 insertions(+)
 create mode 100644 block/partitions/tegra.c
 create mode 100644 drivers/soc/tegra/bootdata.c
 create mode 100644 include/linux/mmc/blkdev.h
 create mode 100644 include/soc/tegra/bootdata.h
 create mode 100644 include/soc/tegra/partition.h

-- 
2.26.0

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

* [PATCH v4 0/6] Introduce NVIDIA Tegra Partition Table
@ 2020-05-15  1:41 ` Dmitry Osipenko
  0 siblings, 0 replies; 17+ messages in thread
From: Dmitry Osipenko @ 2020-05-15  1:41 UTC (permalink / raw)
  To: Jens Axboe, Thierry Reding, Jonathan Hunter,
	Michał Mirosław, David Heidelberg, Peter Geis,
	Stephen Warren, Nicolas Chauvet, Ulf Hansson, Adrian Hunter,
	Billy Laws, Nils Östlund, Christoph Hellwig, Ard Biesheuvel,
	Davidlohr Bueso
  Cc: linux-tegra, linux-block, Andrey Danin, Gilles Grandou,
	Ryan Grachek, linux-mmc, linux-kernel, linux-efi

Hello,

This series adds support for the NVIDIA Tegra Partition Table format,
which is needed in order to support consumer-grade Tegra-based devices
by the upstream kernel.  These devices have Secure Boot enabled and it
can't be disabled, and thus, it's not possible to easily modify bootloader
and eMMC storage partitioning.

Big thanks to everyone who helped with figuring out the TegraPT format
and with testing!

Changelog:

v4: - Scanning of the eMMC boot partitions has been dropped because it
      requires a bit too messy hacks in the kernel. We can live without
      this feature, at least for now it's not really needed.

    - Instead of the dropped boot partitions scanning, the "gpt_sector="
      command line option has been brought back [1]. But now it's done
      in a different way, not bothering platforms other than Tegra and
      not touching block devices other than eMMC, which was requested during
      of the [1] review. The "gpt_sector=" usage is needed when partition
      table is inaccessible by kernel, which is the case for the Ouya game
      console device for example. Please note that "gpt_sector=" is not
      available on all devices, such devices will fall back to the TegraPT,
      Samsung Galaxy Tab 10.1 is an example of a such device.

      [1] https://patchwork.ozlabs.org/project/linux-tegra/patch/20200219162339.16192-1-digetx@gmail.com/

    - We got a bit more broad testing and discovered that Samsung Galaxy
      Tab 10.1 uses 2K logical sectors instead of 4K. So the 2K sectors
      are supported now by the TegraPT parser. Thanks to Nils Östlund for
      the testing!

    - TegraPT parser now utilizes "tegraboot=" cmdline option which is
      passed to kernel by the NVIDIA's bootloader. It's used for verifying
      that SDMMC device is *the* boot source.

    - Added patch that exposes Boot Configuration Table to userspace via
      sysfs. Thanks to Michał Mirosław for the suggestion!

    - Misc changes:
        - The EB2 (second bootloader) partition is added to the list of
          known partitions. Used by the Galaxy Tab 10.

        - The blkdev logical sector size is checked now, for consistency.
          It always should be 512 bytes on the supported/tested devices.

        - Verbose error messages are replaced with pr_debug().

v3: - Fixed "BUG: KASAN: slab-out-of-bounds in tegra_partition". Thanks to
      Peter Geis for noticing the problem.

    - The MMC boot partitions scanning is now opt-in. See this patch:

        mmc: block: Support partition-table scanning on boot partitions

    - The found MMC boot partitions won't be assigned to the MMC boot
      block device ever due to the new GENHD_FL_PART_SCAN_ONCE flag.

      This makes us to ensure that the old behavior of the MMC core is
      preserved for a non-Tegra MMC-block users.

    New patches in v3:

        block: Introduce GENHD_FL_PART_SCAN_ONCE
        mmc: sdhci-tegra: Enable boot partitions scanning on Tegra20 and Tegra30

v2: - Addressed v1 review comments from Stephen Warren by using BIT for
      locating BCT position in IRAM.

    - Added more validations to the TegraPT parser: partition type is
      verified, eMMC instance ID is verified.

    - TegraPT parser now doesn't touch any devices other than eMMC.

    - EKS (encrypted keys) partition is blacklisted now.

    - Implemented eMMC boot partitions scanning. These new patches are
      added in a result:

        mmc: block: Add mmc_bdev_to_part_type() helper
        mmc: block: Add mmc_bdev_to_area_type() helper
        mmc: block: Add MMC_QUIRK_RESCAN_MAIN_BLKDEV
        mmc: block: Enable partition-table scanning for boot partitions
        partitions/tegra: Implement eMMC boot partitions scanning

Dmitry Osipenko (6):
  mmc: core: Add raw_boot_mult field to mmc_ext_csd
  mmc: block: Add mmc_bdev_to_card() helper
  partitions: Introduce NVIDIA Tegra Partition Table
  partitions/efi: Support GPT entry lookup at a non-standard location
  partitions/tegra: Support gpt_sector= command line option
  soc/tegra: Expose Boot Configuration Table via sysfs

 arch/arm/mach-tegra/tegra.c   |  58 ++++
 block/partitions/Kconfig      |   8 +
 block/partitions/Makefile     |   1 +
 block/partitions/check.h      |   2 +
 block/partitions/core.c       |   4 +
 block/partitions/efi.c        |  16 +
 block/partitions/efi.h        |   2 +
 block/partitions/tegra.c      | 603 ++++++++++++++++++++++++++++++++++
 drivers/mmc/core/block.c      |  15 +
 drivers/mmc/core/mmc.c        |   2 +
 drivers/soc/tegra/Makefile    |   1 +
 drivers/soc/tegra/bootdata.c  |  51 +++
 drivers/soc/tegra/common.c    |  17 +
 include/linux/mmc/blkdev.h    |  13 +
 include/linux/mmc/card.h      |   1 +
 include/soc/tegra/bootdata.h  |  48 +++
 include/soc/tegra/common.h    |  12 +
 include/soc/tegra/partition.h |  83 +++++
 18 files changed, 937 insertions(+)
 create mode 100644 block/partitions/tegra.c
 create mode 100644 drivers/soc/tegra/bootdata.c
 create mode 100644 include/linux/mmc/blkdev.h
 create mode 100644 include/soc/tegra/bootdata.h
 create mode 100644 include/soc/tegra/partition.h

-- 
2.26.0


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

* [PATCH v4 1/6] mmc: core: Add raw_boot_mult field to mmc_ext_csd
  2020-05-15  1:41 ` Dmitry Osipenko
  (?)
@ 2020-05-15  1:41 ` Dmitry Osipenko
  -1 siblings, 0 replies; 17+ messages in thread
From: Dmitry Osipenko @ 2020-05-15  1:41 UTC (permalink / raw)
  To: Jens Axboe, Thierry Reding, Jonathan Hunter,
	Michał Mirosław, David Heidelberg, Peter Geis,
	Stephen Warren, Nicolas Chauvet, Ulf Hansson, Adrian Hunter,
	Billy Laws, Nils Östlund, Christoph Hellwig, Ard Biesheuvel,
	Davidlohr Bueso
  Cc: linux-tegra, linux-block, Andrey Danin, Gilles Grandou,
	Ryan Grachek, linux-mmc, linux-kernel, linux-efi

In order to support parsing of NVIDIA Tegra Partition Table format, we
need to know the BOOT_SIZE_MULT value of the Extended CSD register because
NVIDIA's bootloader linearizes the boot0/boot1/main partitions into a
single virtual space, and thus, all partition addresses are shifted by
the size of boot0 + boot1 partitions.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 drivers/mmc/core/mmc.c   | 2 ++
 include/linux/mmc/card.h | 1 +
 2 files changed, 3 insertions(+)

diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 4203303f946a..112edfb1eb1d 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -417,6 +417,8 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
 		ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT];
 	card->ext_csd.raw_hc_erase_grp_size =
 		ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
+	card->ext_csd.raw_boot_mult =
+		ext_csd[EXT_CSD_BOOT_MULT];
 	if (card->ext_csd.rev >= 3) {
 		u8 sa_shift = ext_csd[EXT_CSD_S_A_TIMEOUT];
 		card->ext_csd.part_config = ext_csd[EXT_CSD_PART_CONFIG];
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 7d46411ffaa2..cd6b58b66010 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -109,6 +109,7 @@ struct mmc_ext_csd {
 	u8			raw_hc_erase_gap_size;	/* 221 */
 	u8			raw_erase_timeout_mult;	/* 223 */
 	u8			raw_hc_erase_grp_size;	/* 224 */
+	u8			raw_boot_mult;		/* 226 */
 	u8			raw_sec_trim_mult;	/* 229 */
 	u8			raw_sec_erase_mult;	/* 230 */
 	u8			raw_sec_feature_support;/* 231 */
-- 
2.26.0

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

* [PATCH v4 2/6] mmc: block: Add mmc_bdev_to_card() helper
  2020-05-15  1:41 ` Dmitry Osipenko
@ 2020-05-15  1:41     ` Dmitry Osipenko
  -1 siblings, 0 replies; 17+ messages in thread
From: Dmitry Osipenko @ 2020-05-15  1:41 UTC (permalink / raw)
  To: Jens Axboe, Thierry Reding, Jonathan Hunter,
	Michał Mirosław, David Heidelberg, Peter Geis,
	Stephen Warren, Nicolas Chauvet, Ulf Hansson, Adrian Hunter,
	Billy Laws, Nils Östlund, Christoph Hellwig, Ard Biesheuvel,
	Davidlohr Bueso
  Cc: linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-block-u79uwXL29TY76Z2rM5mHXA, Andrey Danin, Gilles Grandou,
	Ryan Grachek, linux-mmc-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, linux-efi

NVIDIA Tegra Partition Table takes into account MMC card's BOOT_SIZE_MULT
parameter, and thus, the partition parser needs to retrieve that EXT_CSD
value from the block device. There are also some other parts of struct
mmc_card that are needed for the partition parser in order to calculate
the eMMC offset and verify different things. This patch introduces new
helper which takes block device for the input argument and returns the
corresponding MMC card.

Signed-off-by: Dmitry Osipenko <digetx-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
 drivers/mmc/core/block.c   | 15 +++++++++++++++
 include/linux/mmc/blkdev.h | 13 +++++++++++++
 2 files changed, 28 insertions(+)
 create mode 100644 include/linux/mmc/blkdev.h

diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c
index c5367e2c8487..99298e888381 100644
--- a/drivers/mmc/core/block.c
+++ b/drivers/mmc/core/block.c
@@ -40,6 +40,7 @@
 #include <linux/debugfs.h>
 
 #include <linux/mmc/ioctl.h>
+#include <linux/mmc/blkdev.h>
 #include <linux/mmc/card.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/mmc.h>
@@ -305,6 +306,20 @@ static ssize_t force_ro_store(struct device *dev, struct device_attribute *attr,
 	return ret;
 }
 
+struct mmc_card *mmc_bdev_to_card(struct block_device *bdev)
+{
+	struct mmc_blk_data *md;
+
+	if (bdev->bd_disk->major != MMC_BLOCK_MAJOR)
+		return NULL;
+
+	md = mmc_blk_get(bdev->bd_disk);
+	if (!md)
+		return NULL;
+
+	return md->queue.card;
+}
+
 static int mmc_blk_open(struct block_device *bdev, fmode_t mode)
 {
 	struct mmc_blk_data *md = mmc_blk_get(bdev->bd_disk);
diff --git a/include/linux/mmc/blkdev.h b/include/linux/mmc/blkdev.h
new file mode 100644
index 000000000000..67608c58de70
--- /dev/null
+++ b/include/linux/mmc/blkdev.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ *  linux/include/linux/mmc/blkdev.h
+ */
+#ifndef LINUX_MMC_BLOCK_DEVICE_H
+#define LINUX_MMC_BLOCK_DEVICE_H
+
+struct block_device;
+struct mmc_card;
+
+struct mmc_card *mmc_bdev_to_card(struct block_device *bdev);
+
+#endif /* LINUX_MMC_BLOCK_DEVICE_H */
-- 
2.26.0

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

* [PATCH v4 2/6] mmc: block: Add mmc_bdev_to_card() helper
@ 2020-05-15  1:41     ` Dmitry Osipenko
  0 siblings, 0 replies; 17+ messages in thread
From: Dmitry Osipenko @ 2020-05-15  1:41 UTC (permalink / raw)
  To: Jens Axboe, Thierry Reding, Jonathan Hunter,
	Michał Mirosław, David Heidelberg, Peter Geis,
	Stephen Warren, Nicolas Chauvet, Ulf Hansson, Adrian Hunter,
	Billy Laws, Nils Östlund, Christoph Hellwig, Ard Biesheuvel,
	Davidlohr Bueso
  Cc: linux-tegra, linux-block, Andrey Danin, Gilles Grandou,
	Ryan Grachek, linux-mmc, linux-kernel, linux-efi

NVIDIA Tegra Partition Table takes into account MMC card's BOOT_SIZE_MULT
parameter, and thus, the partition parser needs to retrieve that EXT_CSD
value from the block device. There are also some other parts of struct
mmc_card that are needed for the partition parser in order to calculate
the eMMC offset and verify different things. This patch introduces new
helper which takes block device for the input argument and returns the
corresponding MMC card.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 drivers/mmc/core/block.c   | 15 +++++++++++++++
 include/linux/mmc/blkdev.h | 13 +++++++++++++
 2 files changed, 28 insertions(+)
 create mode 100644 include/linux/mmc/blkdev.h

diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c
index c5367e2c8487..99298e888381 100644
--- a/drivers/mmc/core/block.c
+++ b/drivers/mmc/core/block.c
@@ -40,6 +40,7 @@
 #include <linux/debugfs.h>
 
 #include <linux/mmc/ioctl.h>
+#include <linux/mmc/blkdev.h>
 #include <linux/mmc/card.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/mmc.h>
@@ -305,6 +306,20 @@ static ssize_t force_ro_store(struct device *dev, struct device_attribute *attr,
 	return ret;
 }
 
+struct mmc_card *mmc_bdev_to_card(struct block_device *bdev)
+{
+	struct mmc_blk_data *md;
+
+	if (bdev->bd_disk->major != MMC_BLOCK_MAJOR)
+		return NULL;
+
+	md = mmc_blk_get(bdev->bd_disk);
+	if (!md)
+		return NULL;
+
+	return md->queue.card;
+}
+
 static int mmc_blk_open(struct block_device *bdev, fmode_t mode)
 {
 	struct mmc_blk_data *md = mmc_blk_get(bdev->bd_disk);
diff --git a/include/linux/mmc/blkdev.h b/include/linux/mmc/blkdev.h
new file mode 100644
index 000000000000..67608c58de70
--- /dev/null
+++ b/include/linux/mmc/blkdev.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ *  linux/include/linux/mmc/blkdev.h
+ */
+#ifndef LINUX_MMC_BLOCK_DEVICE_H
+#define LINUX_MMC_BLOCK_DEVICE_H
+
+struct block_device;
+struct mmc_card;
+
+struct mmc_card *mmc_bdev_to_card(struct block_device *bdev);
+
+#endif /* LINUX_MMC_BLOCK_DEVICE_H */
-- 
2.26.0


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

* [PATCH v4 3/6] partitions: Introduce NVIDIA Tegra Partition Table
  2020-05-15  1:41 ` Dmitry Osipenko
@ 2020-05-15  1:41     ` Dmitry Osipenko
  -1 siblings, 0 replies; 17+ messages in thread
From: Dmitry Osipenko @ 2020-05-15  1:41 UTC (permalink / raw)
  To: Jens Axboe, Thierry Reding, Jonathan Hunter,
	Michał Mirosław, David Heidelberg, Peter Geis,
	Stephen Warren, Nicolas Chauvet, Ulf Hansson, Adrian Hunter,
	Billy Laws, Nils Östlund, Christoph Hellwig, Ard Biesheuvel,
	Davidlohr Bueso
  Cc: linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-block-u79uwXL29TY76Z2rM5mHXA, Andrey Danin, Gilles Grandou,
	Ryan Grachek, linux-mmc-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, linux-efi

All NVIDIA Tegra devices use a special partition table format for the
internal storage partitioning. Most of Tegra devices have GPT partition
in addition to TegraPT, but some older Android consumer-grade devices do
not or GPT is placed in a wrong sector, and thus, the TegraPT is needed
in order to support these devices properly by the upstream kernel. This
patch adds support for NVIDIA Tegra Partition Table format that is used
at least by all NVIDIA Tegra20 and Tegra30 devices.

Tested-by: Nils Östlund <nils-ElENwYY5mljQT0dZR+AlfA@public.gmane.org>
Signed-off-by: Dmitry Osipenko <digetx-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
 arch/arm/mach-tegra/tegra.c   |  54 ++++
 block/partitions/Kconfig      |   8 +
 block/partitions/Makefile     |   1 +
 block/partitions/check.h      |   1 +
 block/partitions/core.c       |   3 +
 block/partitions/tegra.c      | 565 ++++++++++++++++++++++++++++++++++
 include/soc/tegra/bootdata.h  |  46 +++
 include/soc/tegra/common.h    |   9 +
 include/soc/tegra/partition.h |  83 +++++
 9 files changed, 770 insertions(+)
 create mode 100644 block/partitions/tegra.c
 create mode 100644 include/soc/tegra/bootdata.h
 create mode 100644 include/soc/tegra/partition.h

diff --git a/arch/arm/mach-tegra/tegra.c b/arch/arm/mach-tegra/tegra.c
index c011359bcdb4..da6bcd85398b 100644
--- a/arch/arm/mach-tegra/tegra.c
+++ b/arch/arm/mach-tegra/tegra.c
@@ -28,7 +28,9 @@
 
 #include <linux/firmware/trusted_foundations.h>
 
+#include <soc/tegra/bootdata.h>
 #include <soc/tegra/fuse.h>
+#include <soc/tegra/partition.h>
 #include <soc/tegra/pmc.h>
 
 #include <asm/firmware.h>
@@ -62,9 +64,61 @@ u32 tegra_uart_config[3] = {
 	0,
 };
 
+static void __init tegra_boot_config_table_init(void)
+{
+	struct tegra30_boot_config_table __iomem *t30_bct;
+	struct tegra20_boot_config_table __iomem *t20_bct;
+	struct tegra20_boot_info_table   __iomem *t20_bit;
+	u32 iram_end   = TEGRA_IRAM_BASE + TEGRA_IRAM_SIZE;
+	u32 iram_start = TEGRA_IRAM_BASE;
+	u32 pt_addr, pt_size, bct_size;
+
+	t20_bit = IO_ADDRESS(TEGRA_IRAM_BASE);
+
+	if (of_machine_is_compatible("nvidia,tegra20")) {
+		bct_size = sizeof(*t20_bct);
+
+		if (t20_bit->bct_size != bct_size ||
+		    t20_bit->bct_ptr < iram_start ||
+		    t20_bit->bct_ptr > iram_end - bct_size)
+			return;
+
+		t20_bct = IO_ADDRESS(t20_bit->bct_ptr);
+
+		if (t20_bct->boot_data_version != TEGRA_BOOTDATA_VERSION_T20)
+			return;
+
+		pt_addr = t20_bct->partition_table_logical_sector_address;
+		pt_size = t20_bct->partition_table_num_logical_sectors;
+
+	} else if (of_machine_is_compatible("nvidia,tegra30")) {
+		bct_size = sizeof(*t30_bct);
+
+		if (t20_bit->bct_size != bct_size ||
+		    t20_bit->bct_ptr < iram_start ||
+		    t20_bit->bct_ptr > iram_end - bct_size)
+			return;
+
+		t30_bct = IO_ADDRESS(t20_bit->bct_ptr);
+
+		if (t30_bct->boot_data_version != TEGRA_BOOTDATA_VERSION_T30)
+			return;
+
+		pt_addr = t30_bct->partition_table_logical_sector_address;
+		pt_size = t30_bct->partition_table_num_logical_sectors;
+	} else {
+		return;
+	}
+
+	pr_info("%s: BCT found in IRAM\n", __func__);
+
+	tegra_partition_table_setup(pt_addr, pt_size);
+}
+
 static void __init tegra_init_early(void)
 {
 	of_register_trusted_foundations();
+	tegra_boot_config_table_init();
 	tegra_cpu_reset_handler_init();
 	call_firmware_op(l2x0_init);
 }
diff --git a/block/partitions/Kconfig b/block/partitions/Kconfig
index 702689a628f0..2c1408cba1a6 100644
--- a/block/partitions/Kconfig
+++ b/block/partitions/Kconfig
@@ -268,3 +268,11 @@ config CMDLINE_PARTITION
 	help
 	  Say Y here if you want to read the partition table from bootargs.
 	  The format for the command line is just like mtdparts.
+
+config TEGRA_PARTITION
+	bool "NVIDIA Tegra Partition support" if PARTITION_ADVANCED
+	default y if ARCH_TEGRA
+	depends on (ARCH_TEGRA && MMC_BLOCK) || COMPILE_TEST
+	help
+	  Say Y here if you would like to be able to read the hard disk
+	  partition table format used by NVIDIA Tegra machines.
diff --git a/block/partitions/Makefile b/block/partitions/Makefile
index a7f05cdb02a8..83cb70c6d08d 100644
--- a/block/partitions/Makefile
+++ b/block/partitions/Makefile
@@ -20,3 +20,4 @@ obj-$(CONFIG_IBM_PARTITION) += ibm.o
 obj-$(CONFIG_EFI_PARTITION) += efi.o
 obj-$(CONFIG_KARMA_PARTITION) += karma.o
 obj-$(CONFIG_SYSV68_PARTITION) += sysv68.o
+obj-$(CONFIG_TEGRA_PARTITION) += tegra.o
diff --git a/block/partitions/check.h b/block/partitions/check.h
index c577e9ee67f0..ffa01cc4b0b0 100644
--- a/block/partitions/check.h
+++ b/block/partitions/check.h
@@ -67,4 +67,5 @@ int osf_partition(struct parsed_partitions *state);
 int sgi_partition(struct parsed_partitions *state);
 int sun_partition(struct parsed_partitions *state);
 int sysv68_partition(struct parsed_partitions *state);
+int tegra_partition(struct parsed_partitions *state);
 int ultrix_partition(struct parsed_partitions *state);
diff --git a/block/partitions/core.c b/block/partitions/core.c
index 297004fd2264..0b4720372f07 100644
--- a/block/partitions/core.c
+++ b/block/partitions/core.c
@@ -81,6 +81,9 @@ static int (*check_part[])(struct parsed_partitions *) = {
 #endif
 #ifdef CONFIG_SYSV68_PARTITION
 	sysv68_partition,
+#endif
+#ifdef CONFIG_TEGRA_PARTITION
+	tegra_partition,
 #endif
 	NULL
 };
diff --git a/block/partitions/tegra.c b/block/partitions/tegra.c
new file mode 100644
index 000000000000..d1b84fff362c
--- /dev/null
+++ b/block/partitions/tegra.c
@@ -0,0 +1,565 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * NVIDIA Tegra Partition Table
+ *
+ * Copyright (C) 2020 GRATE-DRIVER project
+ * Copyright (C) 2020 Dmitry Osipenko <digetx-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
+ *
+ * Credits for the partition table format:
+ *
+ *   Andrey Danin <danindrey-JGs/UdohzUI@public.gmane.org>       (Toshiba AC100 TegraPT format)
+ *   Gilles Grandou <gilles-4LeZiQkTMnPR7s880joybQ@public.gmane.org>    (Toshiba AC100 TegraPT format)
+ *   Ryan Grachek <ryan-JnT2LfGw4MD1P9xLtpHBDw@public.gmane.org>          (Google TV "Molly" TegraPT format)
+ *   Stephen Warren <swarren-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org> (Useful suggestions about eMMC/etc)
+ */
+
+#define pr_fmt(fmt) "tegra-partition: " fmt
+
+#include <linux/blkdev.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/sizes.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+
+#include <linux/mmc/blkdev.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/host.h>
+
+#include <soc/tegra/common.h>
+#include <soc/tegra/partition.h>
+
+#include "check.h"
+
+#define TEGRA_PT_SECTOR_SIZE(ptp)	((ptp)->logical_sector_size / SZ_512)
+#define TEGRA_PT_SECTOR(ptp, s)		((s) * TEGRA_PT_SECTOR_SIZE(ptp))
+
+#define TEGRA_PT_HEADER_SIZE						\
+	(sizeof(struct tegra_partition_header_insecure) +		\
+	 sizeof(struct tegra_partition_header_secure))			\
+
+#define TEGRA_PT_MAX_PARTITIONS(ptp)					\
+	(((ptp)->logical_sector_size - TEGRA_PT_HEADER_SIZE) /		\
+	 sizeof(struct tegra_partition))
+
+#define TEGRA_PT_ERR(ptp, fmt, ...)					\
+	pr_debug("%s: " fmt,						\
+		 (ptp)->state->bdev->bd_disk->disk_name, ##__VA_ARGS__)	\
+
+#define TEGRA_PT_PARSE_ERR(ptp, fmt, ...)				\
+	TEGRA_PT_ERR(ptp, "sector %llu: invalid " fmt,			\
+		     (ptp)->sector, ##__VA_ARGS__)
+
+struct tegra_partition_table_parser {
+	struct tegra_partition_table *pt;
+	unsigned int logical_sector_size;
+	struct parsed_partitions *state;
+	bool pt_entry_checked;
+	sector_t sector;
+	int boot_offset;
+	u32 dev_instance;
+	u32 dev_id;
+};
+
+union tegra_partition_table_u {
+	struct tegra_partition_table pt;
+	u8 pt_parts[SZ_4K / SZ_512][SZ_512];
+};
+
+struct tegra_partition_type {
+	unsigned int type;
+	char *name;
+};
+
+static sector_t tegra_pt_logical_sector_address;
+static sector_t tegra_pt_logical_sectors_num;
+
+void tegra_partition_table_setup(unsigned int logical_sector_address,
+				 unsigned int logical_sectors_num)
+{
+	tegra_pt_logical_sector_address = logical_sector_address;
+	tegra_pt_logical_sectors_num    = logical_sectors_num;
+
+	pr_info("initialized to logical sector = %llu sectors_num = %llu\n",
+		tegra_pt_logical_sector_address, tegra_pt_logical_sectors_num);
+}
+
+/*
+ * Some partitions are very sensitive, changing data on them may brick device.
+ *
+ * For more details about partitions see:
+ *
+ *  "https://docs.nvidia.com/jetson/l4t/Tegra Linux Driver Package Development Guide/part_config.html"
+ */
+static const char * const partitions_blacklist[] = {
+	"BCT", "EBT", "EB2", "EKS", "GP1", "GPT", "MBR", "PT",
+};
+
+static bool tegra_partition_name_match(struct tegra_partition *p,
+				       const char *name)
+{
+	return !strncmp(p->partition_name, name, TEGRA_PT_NAME_SIZE);
+}
+
+static bool tegra_partition_skip(struct tegra_partition *p,
+				 struct tegra_partition_table_parser *ptp,
+				 sector_t sector)
+{
+	unsigned int i;
+
+	/* skip eMMC boot partitions */
+	if (sector < ptp->boot_offset)
+		return true;
+
+	for (i = 0; i < ARRAY_SIZE(partitions_blacklist); i++) {
+		if (tegra_partition_name_match(p, partitions_blacklist[i]))
+			return true;
+	}
+
+	return false;
+}
+
+static const struct tegra_partition_type tegra_partition_expected_types[] = {
+	{ .type = TEGRA_PT_PART_TYPE_BCT,	.name = "BCT", },
+	{ .type = TEGRA_PT_PART_TYPE_EBT,	.name = "EBT", },
+	{ .type = TEGRA_PT_PART_TYPE_EBT,	.name = "EB2", },
+	{ .type = TEGRA_PT_PART_TYPE_PT,	.name = "PT",  },
+	{ .type = TEGRA_PT_PART_TYPE_GP1,	.name = "GP1", },
+	{ .type = TEGRA_PT_PART_TYPE_GPT,	.name = "GPT", },
+	{ .type = TEGRA_PT_PART_TYPE_GENERIC,	.name = NULL,  },
+};
+
+static int tegra_partition_type_valid(struct tegra_partition_table_parser *ptp,
+				      struct tegra_partition *p)
+{
+	const struct tegra_partition_type *ptype;
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(tegra_partition_expected_types); i++) {
+		ptype = &tegra_partition_expected_types[i];
+
+		if (ptype->name && !tegra_partition_name_match(p, ptype->name))
+			continue;
+
+		if (p->part_info.partition_type == ptype->type)
+			return 0;
+
+		/*
+		 * Unsure about all possible types, let's emit error and
+		 * allow to continue for now.
+		 */
+		if (!ptype->name)
+			return 1;
+	}
+
+	return -1;
+}
+
+static bool tegra_partition_valid(struct tegra_partition_table_parser *ptp,
+				  struct tegra_partition *p,
+				  struct tegra_partition *prev,
+				  sector_t sector,
+				  sector_t size)
+{
+	struct tegra_partition_info *prev_pi = &prev->part_info;
+	sector_t sect_end = TEGRA_PT_SECTOR(ptp,
+					    prev_pi->logical_sector_address +
+					    prev_pi->logical_sectors_num);
+	char *type, name[2][TEGRA_PT_NAME_SIZE + 1];
+	int err;
+
+	strscpy(name[0], p->partition_name,    sizeof(name[0]));
+	strscpy(name[1], prev->partition_name, sizeof(name[1]));
+
+	/* validate expected partition name/type */
+	err = tegra_partition_type_valid(ptp, p);
+	if (err) {
+		TEGRA_PT_PARSE_ERR(ptp, "partition_type: [%s] partition_type=%u\n",
+				   name[0], p->part_info.partition_type);
+		if (err < 0)
+			return false;
+
+		TEGRA_PT_ERR(ptp, "continuing, please update list of expected types\n");
+	}
+
+	/* validate partition table BCT addresses */
+	if (tegra_partition_name_match(p, "PT")) {
+		if (sector != TEGRA_PT_SECTOR(ptp, tegra_pt_logical_sector_address) &&
+		    size   != TEGRA_PT_SECTOR(ptp, tegra_pt_logical_sectors_num)) {
+			TEGRA_PT_PARSE_ERR(ptp, "PT location: sector=%llu size=%llu\n",
+					   sector, size);
+			return false;
+		}
+
+		if (ptp->pt_entry_checked) {
+			TEGRA_PT_PARSE_ERR(ptp, "(duplicated) PT\n");
+			return false;
+		}
+
+		ptp->pt_entry_checked = true;
+	}
+
+	if (sector + size < sector) {
+		TEGRA_PT_PARSE_ERR(ptp, "size: [%s] integer overflow sector=%llu size=%llu\n",
+				   name[0], sector, size);
+		return false;
+	}
+
+	/* validate allocation_policy=sequential (absolute unsupported) */
+	if (p != prev && sect_end > sector) {
+		TEGRA_PT_PARSE_ERR(ptp, "allocation_policy: [%s] end=%llu [%s] sector=%llu size=%llu\n",
+				   name[1], sect_end, name[0], sector, size);
+		return false;
+	}
+
+	if (ptp->dev_instance != p->mount_info.device_instance) {
+		TEGRA_PT_PARSE_ERR(ptp, "device_instance: [%s] device_instance=%u|%u\n",
+				   name[0], ptp->dev_instance,
+				   p->mount_info.device_instance);
+		return false;
+	}
+
+	if (ptp->dev_id != p->mount_info.device_id) {
+		TEGRA_PT_PARSE_ERR(ptp, "device_id: [%s] device_id=%u|%u\n",
+				   name[0], ptp->dev_id,
+				   p->mount_info.device_id);
+		return false;
+	}
+
+	if (p->partition_id > 127) {
+		TEGRA_PT_PARSE_ERR(ptp, "partition_id: [%s] partition_id=%u\n",
+				   name[0], p->partition_id);
+		return false;
+	}
+
+	sect_end = get_capacity(ptp->state->bdev->bd_disk);
+
+	/* eMMC boot partitions are below ptp->boot_offset */
+	if (sector < ptp->boot_offset) {
+		sect_end += ptp->boot_offset;
+		type = "boot";
+	} else {
+		sector -= ptp->boot_offset;
+		type = "main";
+	}
+
+	/* validate size */
+	if (!size || sector + size > sect_end) {
+		TEGRA_PT_PARSE_ERR(ptp, "size: [%s] %s partition boot_offt=%d end=%llu sector=%llu size=%llu\n",
+				   name[0], type, ptp->boot_offset, sect_end,
+				   sector, size);
+		return false;
+	}
+
+	return true;
+}
+
+static bool tegra_partitions_parsed(struct tegra_partition_table_parser *ptp,
+				    bool check_only)
+{
+	struct parsed_partitions *state = ptp->state;
+	struct tegra_partition_table *pt = ptp->pt;
+	sector_t sector, size;
+	int i, slot = 1;
+
+	ptp->pt_entry_checked = false;
+
+	for (i = 0; i < pt->secure.num_partitions; i++) {
+		struct tegra_partition *p = &pt->partitions[i];
+		struct tegra_partition *prev = &pt->partitions[max(i - 1, 0)];
+		struct tegra_partition_info *pi = &p->part_info;
+
+		if (slot == state->limit && !check_only)
+			break;
+
+		sector = TEGRA_PT_SECTOR(ptp, pi->logical_sector_address);
+		size   = TEGRA_PT_SECTOR(ptp, pi->logical_sectors_num);
+
+		if (check_only &&
+		    !tegra_partition_valid(ptp, p, prev, sector, size))
+			return false;
+
+		if (check_only ||
+		    tegra_partition_skip(p, ptp, sector))
+			continue;
+
+		put_partition(state, slot++, sector - ptp->boot_offset, size);
+	}
+
+	if (check_only && !ptp->pt_entry_checked) {
+		TEGRA_PT_PARSE_ERR(ptp, "PT: table entry not found\n");
+		return false;
+	}
+
+	return true;
+}
+
+static bool
+tegra_partition_table_parsed(struct tegra_partition_table_parser *ptp)
+{
+	if (ptp->pt->secure.num_partitions == 0 ||
+	    ptp->pt->secure.num_partitions > TEGRA_PT_MAX_PARTITIONS(ptp)) {
+		TEGRA_PT_PARSE_ERR(ptp, "num_partitions=%u\n",
+				   ptp->pt->secure.num_partitions);
+		return false;
+	}
+
+	return tegra_partitions_parsed(ptp, true) &&
+	       tegra_partitions_parsed(ptp, false);
+}
+
+static int
+tegra_partition_table_insec_hdr_valid(struct tegra_partition_table_parser *ptp)
+{
+	if (ptp->pt->insecure.magic   != TEGRA_PT_MAGIC ||
+	    ptp->pt->insecure.version != TEGRA_PT_VERSION) {
+		TEGRA_PT_PARSE_ERR(ptp, "insecure header: magic=0x%llx ver=0x%x\n",
+				   ptp->pt->insecure.magic,
+				   ptp->pt->insecure.version);
+		return 0;
+	}
+
+	return 1;
+}
+
+static int
+tegra_partition_table_sec_hdr_valid(struct tegra_partition_table_parser *ptp)
+{
+	size_t pt_size = ptp->pt->secure.num_partitions;
+
+	pt_size *= sizeof(ptp->pt->partitions[0]);
+	pt_size += TEGRA_PT_HEADER_SIZE;
+
+	if (ptp->pt->secure.magic   != TEGRA_PT_MAGIC ||
+	    ptp->pt->secure.version != TEGRA_PT_VERSION ||
+	    ptp->pt->secure.length  != ptp->pt->insecure.length ||
+	    ptp->pt->secure.length  < pt_size) {
+		TEGRA_PT_PARSE_ERR(ptp, "secure header: magic=0x%llx ver=0x%x length=%u|%u|%zu\n",
+				   ptp->pt->secure.magic,
+				   ptp->pt->secure.version,
+				   ptp->pt->secure.length,
+				   ptp->pt->insecure.length,
+				   pt_size);
+		return 0;
+	}
+
+	return 1;
+}
+
+static int
+tegra_partition_table_unencrypted(struct tegra_partition_table_parser *ptp)
+{
+	/* AES IV, all zeros if unencrypted */
+	if (ptp->pt->secure.random_data[0] || ptp->pt->secure.random_data[1] ||
+	    ptp->pt->secure.random_data[2] || ptp->pt->secure.random_data[3]) {
+		pr_err_once("encrypted partition table unsupported\n");
+		return 0;
+	}
+
+	return 1;
+}
+
+static int tegra_read_partition_table(struct tegra_partition_table_parser *ptp)
+{
+	union tegra_partition_table_u *ptu = (typeof(ptu))ptp->pt;
+	unsigned int i;
+	Sector sect;
+	void *part;
+
+	for (i = 0; i < ptp->logical_sector_size / SZ_512; i++) {
+		/*
+		 * Partition table takes at maximum 4096 bytes, but
+		 * read_part_sector() guarantees only that SECTOR_SIZE will
+		 * be read at minimum.
+		 */
+		part = read_part_sector(ptp->state, ptp->sector + i, &sect);
+		if (!part) {
+			TEGRA_PT_ERR(ptp, "failed to read sector %llu\n",
+				     ptp->sector + i);
+			return 0;
+		}
+
+		memcpy(ptu->pt_parts[i], part, SZ_512);
+		put_dev_sector(sect);
+	}
+
+	return 1;
+}
+
+static int tegra_partition_scan(struct tegra_partition_table_parser *ptp)
+{
+	sector_t start_sector, num_sectors;
+	int ret = 0;
+
+	num_sectors  = TEGRA_PT_SECTOR(ptp, tegra_pt_logical_sectors_num);
+	start_sector = TEGRA_PT_SECTOR(ptp, tegra_pt_logical_sector_address);
+
+	if (start_sector < ptp->boot_offset) {
+		TEGRA_PT_ERR(ptp,
+			     "scanning eMMC boot partitions unimplemented\n");
+		return 0;
+	}
+
+	ptp->sector = start_sector - ptp->boot_offset;
+
+	/*
+	 * Partition table is duplicated for num_sectors.
+	 * If first table is corrupted, we will try next.
+	 */
+	while (num_sectors--) {
+		ret = tegra_read_partition_table(ptp);
+		if (!ret)
+			goto next_sector;
+
+		ret = tegra_partition_table_insec_hdr_valid(ptp);
+		if (!ret)
+			goto next_sector;
+
+		ret = tegra_partition_table_unencrypted(ptp);
+		if (!ret)
+			goto next_sector;
+
+		ret = tegra_partition_table_sec_hdr_valid(ptp);
+		if (!ret)
+			goto next_sector;
+
+		ret = tegra_partition_table_parsed(ptp);
+		if (ret)
+			break;
+next_sector:
+		ptp->sector += TEGRA_PT_SECTOR_SIZE(ptp);
+	}
+
+	return ret;
+}
+
+static const u32 tegra20_sdhci_bases[TEGRA_PT_SDHCI_DEVICE_INSTANCES] = {
+	0xc8000000, 0xc8000200, 0xc8000400, 0xc8000600,
+};
+
+static const u32 tegra30_sdhci_bases[TEGRA_PT_SDHCI_DEVICE_INSTANCES] = {
+	0x78000000, 0x78000200, 0x78000400, 0x78000600,
+};
+
+static const struct of_device_id tegra_sdhci_match[] = {
+	{ .compatible = "nvidia,tegra20-sdhci", .data = tegra20_sdhci_bases, },
+	{ .compatible = "nvidia,tegra30-sdhci", .data = tegra30_sdhci_bases, },
+	{}
+};
+
+static int
+tegra_partition_table_emmc_boot_offset(struct tegra_partition_table_parser *ptp)
+{
+	struct mmc_card *card = mmc_bdev_to_card(ptp->state->bdev);
+	const struct of_device_id *matched;
+	const u32 *sdhci_bases;
+	u32 sdhci_base;
+	unsigned int i;
+	int err;
+
+	/* filter out unexpected/untested boot sources */
+	if (!card || card->ext_csd.rev < 3 ||
+	    !mmc_card_is_blockaddr(card) ||
+	     mmc_card_is_removable(card->host) ||
+	     bdev_logical_block_size(ptp->state->bdev) != SZ_512)
+		return -1;
+
+	/* skip everything unrelated to Tegra eMMC */
+	matched = of_match_node(tegra_sdhci_match, card->host->parent->of_node);
+	if (!matched)
+		return -1;
+
+	sdhci_bases = matched->data;
+
+	/* figure out SDHCI instance ID by the base address */
+	err = of_property_read_u32_index(card->host->parent->of_node,
+					 "reg", 0, &sdhci_base);
+	if (err)
+		return -1;
+
+	for (i = 0; i < TEGRA_PT_SDHCI_DEVICE_INSTANCES; i++) {
+		if (sdhci_base == sdhci_bases[i])
+			break;
+	}
+
+	if (i == TEGRA_PT_SDHCI_DEVICE_INSTANCES)
+		return -1;
+
+	ptp->dev_id       = TEGRA_PT_SDHCI_DEVICE_ID;
+	ptp->dev_instance = i;
+
+	/*
+	 * eMMC storage has two special boot partitions in addition to the
+	 * main one.  NVIDIA's bootloader linearizes eMMC boot0->boot1->main
+	 * accesses, this means that the partition table addresses are shifted
+	 * by the size of boot partitions.  In accordance with the eMMC
+	 * specification, the boot partition size is calculated as follows:
+	 *
+	 *	boot partition size = 128K byte x BOOT_SIZE_MULT
+	 *
+	 * This function returns number of sectors occupied by the both boot
+	 * partitions.
+	 */
+	return card->ext_csd.raw_boot_mult * SZ_128K /
+	       SZ_512 * MMC_NUM_BOOT_PARTITION;
+}
+
+/*
+ * Logical sector size may vary per device model and apparently there is no
+ * way to get information about the size from kernel. The info is hardcoded
+ * into bootloader and it doesn't tell us, so we'll just try all possible
+ * well-known sizes until succeed.
+ *
+ * For example Samsung Galaxy Tab 10.1 uses 2K sectors. While Acer A500,
+ * Nexus 7 and Ouya are using 4K sectors.
+ */
+static const unsigned int tegra_pt_logical_sector_sizes[] = {
+	SZ_4K, SZ_2K,
+};
+
+/*
+ * The 'tegraboot=<source>' command line option is supplied by NVIDIA
+ * bootloader.
+ */
+static bool tegra_boot_sdmmc;
+static int __init tegra_boot_fn(char *str)
+{
+	tegra_boot_sdmmc = !strcmp(str, "sdmmc");
+	return 1;
+}
+__setup("tegraboot=", tegra_boot_fn);
+
+int tegra_partition(struct parsed_partitions *state)
+{
+	struct tegra_partition_table_parser ptp = {};
+	unsigned int i;
+	int ret;
+
+	if (!soc_is_tegra() || !tegra_boot_sdmmc)
+		return 0;
+
+	ptp.state = state;
+
+	ptp.boot_offset = tegra_partition_table_emmc_boot_offset(&ptp);
+	if (ptp.boot_offset < 0)
+		return 0;
+
+	ptp.pt = kmalloc(SZ_4K, GFP_KERNEL);
+	if (!ptp.pt)
+		return 0;
+
+	for (i = 0; i < ARRAY_SIZE(tegra_pt_logical_sector_sizes); i++) {
+		ptp.logical_sector_size = tegra_pt_logical_sector_sizes[i];
+
+		ret = tegra_partition_scan(&ptp);
+		if (ret == 1) {
+			strlcat(state->pp_buf, "\n", PAGE_SIZE);
+			break;
+		}
+	}
+
+	kfree(ptp.pt);
+
+	return ret;
+}
diff --git a/include/soc/tegra/bootdata.h b/include/soc/tegra/bootdata.h
new file mode 100644
index 000000000000..7be207cb2519
--- /dev/null
+++ b/include/soc/tegra/bootdata.h
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __SOC_TEGRA_BOOTDATA_H__
+#define __SOC_TEGRA_BOOTDATA_H__
+
+#include <linux/compiler.h>
+#include <linux/types.h>
+
+#define TEGRA_BOOTDATA_VERSION_T20	NVBOOT_BOOTDATA_VERSION(0x2, 0x1)
+#define TEGRA_BOOTDATA_VERSION_T30	NVBOOT_BOOTDATA_VERSION(0x3, 0x1)
+
+#define NVBOOT_BOOTDATA_VERSION(a, b)	((((a) & 0xffff) << 16) | \
+					  ((b) & 0xffff))
+#define NVBOOT_CMAC_AES_HASH_LENGTH	4
+
+struct tegra20_boot_info_table {
+	u32 unused_data1[14];
+	u32 bct_size;
+	u32 bct_ptr;
+} __packed;
+
+struct tegra20_boot_config_table {
+	u32 crypto_hash[NVBOOT_CMAC_AES_HASH_LENGTH];
+	u32 random_aes_blk[NVBOOT_CMAC_AES_HASH_LENGTH];
+	u32 boot_data_version;
+	u32 unused_data1[712];
+	u32 unused_consumer_data1;
+	u16 partition_table_logical_sector_address;
+	u16 partition_table_num_logical_sectors;
+	u32 unused_consumer_data[294];
+	u32 unused_data[3];
+} __packed;
+
+struct tegra30_boot_config_table {
+	u32 crypto_hash[NVBOOT_CMAC_AES_HASH_LENGTH];
+	u32 random_aes_blk[NVBOOT_CMAC_AES_HASH_LENGTH];
+	u32 boot_data_version;
+	u32 unused_data1[1016];
+	u32 unused_consumer_data1;
+	u16 partition_table_logical_sector_address;
+	u16 partition_table_num_logical_sectors;
+	u32 unused_consumer_data[502];
+	u32 unused_data[3];
+} __packed;
+
+#endif /* __SOC_TEGRA_BOOTDATA_H__ */
diff --git a/include/soc/tegra/common.h b/include/soc/tegra/common.h
index 98027a76ce3d..744280ecab5f 100644
--- a/include/soc/tegra/common.h
+++ b/include/soc/tegra/common.h
@@ -6,6 +6,15 @@
 #ifndef __SOC_TEGRA_COMMON_H__
 #define __SOC_TEGRA_COMMON_H__
 
+#include <linux/types.h>
+
+#ifdef CONFIG_ARCH_TEGRA
 bool soc_is_tegra(void);
+#else
+static inline bool soc_is_tegra(void)
+{
+	return false;
+}
+#endif
 
 #endif /* __SOC_TEGRA_COMMON_H__ */
diff --git a/include/soc/tegra/partition.h b/include/soc/tegra/partition.h
new file mode 100644
index 000000000000..4e424543973c
--- /dev/null
+++ b/include/soc/tegra/partition.h
@@ -0,0 +1,83 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __SOC_TEGRA_PARTITION_H__
+#define __SOC_TEGRA_PARTITION_H__
+
+#include <linux/compiler.h>
+#include <linux/types.h>
+
+#define TEGRA_PT_MAGIC				0xffffffff8f9e8d8bULL
+#define TEGRA_PT_VERSION			0x100
+#define TEGRA_PT_AES_HASH_SIZE			4
+#define TEGRA_PT_NAME_SIZE			4
+
+#define TEGRA_PT_SDHCI_DEVICE_ID		18
+#define TEGRA_PT_SDHCI_DEVICE_INSTANCES		4
+
+#define TEGRA_PT_PART_TYPE_BCT			1
+#define TEGRA_PT_PART_TYPE_EBT			2
+#define TEGRA_PT_PART_TYPE_PT			3
+#define TEGRA_PT_PART_TYPE_GENERIC		6
+#define TEGRA_PT_PART_TYPE_GP1			9
+#define TEGRA_PT_PART_TYPE_GPT			10
+
+struct tegra_partition_mount_info {
+	u32 device_id;
+	u32 device_instance;
+	u32 device_attr;
+	u8  mount_path[TEGRA_PT_NAME_SIZE];
+	u32 file_system_type;
+	u32 file_system_attr;
+} __packed;
+
+struct tegra_partition_info {
+	u32 partition_attr;
+	u32 __pad1;
+	u64 logical_sector_address;
+	u64 logical_sectors_num;
+	u64 __pad2[2];
+	u32 partition_type;
+	u32 __pad3;
+} __packed;
+
+struct tegra_partition {
+	u32 partition_id;
+	u8  partition_name[TEGRA_PT_NAME_SIZE];
+	struct tegra_partition_mount_info mount_info;
+	struct tegra_partition_info part_info;
+} __packed;
+
+struct tegra_partition_header_insecure {
+	u64 magic;
+	u32 version;
+	u32 length;
+	u32 signature[TEGRA_PT_AES_HASH_SIZE];
+} __packed;
+
+struct tegra_partition_header_secure {
+	u32 random_data[TEGRA_PT_AES_HASH_SIZE];
+	u64 magic;
+	u32 version;
+	u32 length;
+	u32 num_partitions;
+	u32 __pad;
+} __packed;
+
+struct tegra_partition_table {
+	struct tegra_partition_header_insecure insecure;
+	struct tegra_partition_header_secure secure;
+	struct tegra_partition partitions[];
+} __packed;
+
+#ifdef CONFIG_TEGRA_PARTITION
+void tegra_partition_table_setup(unsigned int logical_sector_address,
+				 unsigned int logical_sectors_num);
+#else
+static inline void
+tegra_partition_table_setup(unsigned int logical_sector_address,
+			    unsigned int logical_sectors_num)
+{
+}
+#endif
+
+#endif /* __SOC_TEGRA_PARTITION_H__ */
-- 
2.26.0

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

* [PATCH v4 3/6] partitions: Introduce NVIDIA Tegra Partition Table
@ 2020-05-15  1:41     ` Dmitry Osipenko
  0 siblings, 0 replies; 17+ messages in thread
From: Dmitry Osipenko @ 2020-05-15  1:41 UTC (permalink / raw)
  To: Jens Axboe, Thierry Reding, Jonathan Hunter,
	Michał Mirosław, David Heidelberg, Peter Geis,
	Stephen Warren, Nicolas Chauvet, Ulf Hansson, Adrian Hunter,
	Billy Laws, Nils Östlund, Christoph Hellwig, Ard Biesheuvel,
	Davidlohr Bueso
  Cc: linux-tegra, linux-block, Andrey Danin, Gilles Grandou,
	Ryan Grachek, linux-mmc, linux-kernel, linux-efi

All NVIDIA Tegra devices use a special partition table format for the
internal storage partitioning. Most of Tegra devices have GPT partition
in addition to TegraPT, but some older Android consumer-grade devices do
not or GPT is placed in a wrong sector, and thus, the TegraPT is needed
in order to support these devices properly by the upstream kernel. This
patch adds support for NVIDIA Tegra Partition Table format that is used
at least by all NVIDIA Tegra20 and Tegra30 devices.

Tested-by: Nils Östlund <nils@naltan.com>
Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 arch/arm/mach-tegra/tegra.c   |  54 ++++
 block/partitions/Kconfig      |   8 +
 block/partitions/Makefile     |   1 +
 block/partitions/check.h      |   1 +
 block/partitions/core.c       |   3 +
 block/partitions/tegra.c      | 565 ++++++++++++++++++++++++++++++++++
 include/soc/tegra/bootdata.h  |  46 +++
 include/soc/tegra/common.h    |   9 +
 include/soc/tegra/partition.h |  83 +++++
 9 files changed, 770 insertions(+)
 create mode 100644 block/partitions/tegra.c
 create mode 100644 include/soc/tegra/bootdata.h
 create mode 100644 include/soc/tegra/partition.h

diff --git a/arch/arm/mach-tegra/tegra.c b/arch/arm/mach-tegra/tegra.c
index c011359bcdb4..da6bcd85398b 100644
--- a/arch/arm/mach-tegra/tegra.c
+++ b/arch/arm/mach-tegra/tegra.c
@@ -28,7 +28,9 @@
 
 #include <linux/firmware/trusted_foundations.h>
 
+#include <soc/tegra/bootdata.h>
 #include <soc/tegra/fuse.h>
+#include <soc/tegra/partition.h>
 #include <soc/tegra/pmc.h>
 
 #include <asm/firmware.h>
@@ -62,9 +64,61 @@ u32 tegra_uart_config[3] = {
 	0,
 };
 
+static void __init tegra_boot_config_table_init(void)
+{
+	struct tegra30_boot_config_table __iomem *t30_bct;
+	struct tegra20_boot_config_table __iomem *t20_bct;
+	struct tegra20_boot_info_table   __iomem *t20_bit;
+	u32 iram_end   = TEGRA_IRAM_BASE + TEGRA_IRAM_SIZE;
+	u32 iram_start = TEGRA_IRAM_BASE;
+	u32 pt_addr, pt_size, bct_size;
+
+	t20_bit = IO_ADDRESS(TEGRA_IRAM_BASE);
+
+	if (of_machine_is_compatible("nvidia,tegra20")) {
+		bct_size = sizeof(*t20_bct);
+
+		if (t20_bit->bct_size != bct_size ||
+		    t20_bit->bct_ptr < iram_start ||
+		    t20_bit->bct_ptr > iram_end - bct_size)
+			return;
+
+		t20_bct = IO_ADDRESS(t20_bit->bct_ptr);
+
+		if (t20_bct->boot_data_version != TEGRA_BOOTDATA_VERSION_T20)
+			return;
+
+		pt_addr = t20_bct->partition_table_logical_sector_address;
+		pt_size = t20_bct->partition_table_num_logical_sectors;
+
+	} else if (of_machine_is_compatible("nvidia,tegra30")) {
+		bct_size = sizeof(*t30_bct);
+
+		if (t20_bit->bct_size != bct_size ||
+		    t20_bit->bct_ptr < iram_start ||
+		    t20_bit->bct_ptr > iram_end - bct_size)
+			return;
+
+		t30_bct = IO_ADDRESS(t20_bit->bct_ptr);
+
+		if (t30_bct->boot_data_version != TEGRA_BOOTDATA_VERSION_T30)
+			return;
+
+		pt_addr = t30_bct->partition_table_logical_sector_address;
+		pt_size = t30_bct->partition_table_num_logical_sectors;
+	} else {
+		return;
+	}
+
+	pr_info("%s: BCT found in IRAM\n", __func__);
+
+	tegra_partition_table_setup(pt_addr, pt_size);
+}
+
 static void __init tegra_init_early(void)
 {
 	of_register_trusted_foundations();
+	tegra_boot_config_table_init();
 	tegra_cpu_reset_handler_init();
 	call_firmware_op(l2x0_init);
 }
diff --git a/block/partitions/Kconfig b/block/partitions/Kconfig
index 702689a628f0..2c1408cba1a6 100644
--- a/block/partitions/Kconfig
+++ b/block/partitions/Kconfig
@@ -268,3 +268,11 @@ config CMDLINE_PARTITION
 	help
 	  Say Y here if you want to read the partition table from bootargs.
 	  The format for the command line is just like mtdparts.
+
+config TEGRA_PARTITION
+	bool "NVIDIA Tegra Partition support" if PARTITION_ADVANCED
+	default y if ARCH_TEGRA
+	depends on (ARCH_TEGRA && MMC_BLOCK) || COMPILE_TEST
+	help
+	  Say Y here if you would like to be able to read the hard disk
+	  partition table format used by NVIDIA Tegra machines.
diff --git a/block/partitions/Makefile b/block/partitions/Makefile
index a7f05cdb02a8..83cb70c6d08d 100644
--- a/block/partitions/Makefile
+++ b/block/partitions/Makefile
@@ -20,3 +20,4 @@ obj-$(CONFIG_IBM_PARTITION) += ibm.o
 obj-$(CONFIG_EFI_PARTITION) += efi.o
 obj-$(CONFIG_KARMA_PARTITION) += karma.o
 obj-$(CONFIG_SYSV68_PARTITION) += sysv68.o
+obj-$(CONFIG_TEGRA_PARTITION) += tegra.o
diff --git a/block/partitions/check.h b/block/partitions/check.h
index c577e9ee67f0..ffa01cc4b0b0 100644
--- a/block/partitions/check.h
+++ b/block/partitions/check.h
@@ -67,4 +67,5 @@ int osf_partition(struct parsed_partitions *state);
 int sgi_partition(struct parsed_partitions *state);
 int sun_partition(struct parsed_partitions *state);
 int sysv68_partition(struct parsed_partitions *state);
+int tegra_partition(struct parsed_partitions *state);
 int ultrix_partition(struct parsed_partitions *state);
diff --git a/block/partitions/core.c b/block/partitions/core.c
index 297004fd2264..0b4720372f07 100644
--- a/block/partitions/core.c
+++ b/block/partitions/core.c
@@ -81,6 +81,9 @@ static int (*check_part[])(struct parsed_partitions *) = {
 #endif
 #ifdef CONFIG_SYSV68_PARTITION
 	sysv68_partition,
+#endif
+#ifdef CONFIG_TEGRA_PARTITION
+	tegra_partition,
 #endif
 	NULL
 };
diff --git a/block/partitions/tegra.c b/block/partitions/tegra.c
new file mode 100644
index 000000000000..d1b84fff362c
--- /dev/null
+++ b/block/partitions/tegra.c
@@ -0,0 +1,565 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * NVIDIA Tegra Partition Table
+ *
+ * Copyright (C) 2020 GRATE-DRIVER project
+ * Copyright (C) 2020 Dmitry Osipenko <digetx@gmail.com>
+ *
+ * Credits for the partition table format:
+ *
+ *   Andrey Danin <danindrey@mail.ru>       (Toshiba AC100 TegraPT format)
+ *   Gilles Grandou <gilles@grandou.net>    (Toshiba AC100 TegraPT format)
+ *   Ryan Grachek <ryan@edited.us>          (Google TV "Molly" TegraPT format)
+ *   Stephen Warren <swarren@wwwdotorg.org> (Useful suggestions about eMMC/etc)
+ */
+
+#define pr_fmt(fmt) "tegra-partition: " fmt
+
+#include <linux/blkdev.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/sizes.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+
+#include <linux/mmc/blkdev.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/host.h>
+
+#include <soc/tegra/common.h>
+#include <soc/tegra/partition.h>
+
+#include "check.h"
+
+#define TEGRA_PT_SECTOR_SIZE(ptp)	((ptp)->logical_sector_size / SZ_512)
+#define TEGRA_PT_SECTOR(ptp, s)		((s) * TEGRA_PT_SECTOR_SIZE(ptp))
+
+#define TEGRA_PT_HEADER_SIZE						\
+	(sizeof(struct tegra_partition_header_insecure) +		\
+	 sizeof(struct tegra_partition_header_secure))			\
+
+#define TEGRA_PT_MAX_PARTITIONS(ptp)					\
+	(((ptp)->logical_sector_size - TEGRA_PT_HEADER_SIZE) /		\
+	 sizeof(struct tegra_partition))
+
+#define TEGRA_PT_ERR(ptp, fmt, ...)					\
+	pr_debug("%s: " fmt,						\
+		 (ptp)->state->bdev->bd_disk->disk_name, ##__VA_ARGS__)	\
+
+#define TEGRA_PT_PARSE_ERR(ptp, fmt, ...)				\
+	TEGRA_PT_ERR(ptp, "sector %llu: invalid " fmt,			\
+		     (ptp)->sector, ##__VA_ARGS__)
+
+struct tegra_partition_table_parser {
+	struct tegra_partition_table *pt;
+	unsigned int logical_sector_size;
+	struct parsed_partitions *state;
+	bool pt_entry_checked;
+	sector_t sector;
+	int boot_offset;
+	u32 dev_instance;
+	u32 dev_id;
+};
+
+union tegra_partition_table_u {
+	struct tegra_partition_table pt;
+	u8 pt_parts[SZ_4K / SZ_512][SZ_512];
+};
+
+struct tegra_partition_type {
+	unsigned int type;
+	char *name;
+};
+
+static sector_t tegra_pt_logical_sector_address;
+static sector_t tegra_pt_logical_sectors_num;
+
+void tegra_partition_table_setup(unsigned int logical_sector_address,
+				 unsigned int logical_sectors_num)
+{
+	tegra_pt_logical_sector_address = logical_sector_address;
+	tegra_pt_logical_sectors_num    = logical_sectors_num;
+
+	pr_info("initialized to logical sector = %llu sectors_num = %llu\n",
+		tegra_pt_logical_sector_address, tegra_pt_logical_sectors_num);
+}
+
+/*
+ * Some partitions are very sensitive, changing data on them may brick device.
+ *
+ * For more details about partitions see:
+ *
+ *  "https://docs.nvidia.com/jetson/l4t/Tegra Linux Driver Package Development Guide/part_config.html"
+ */
+static const char * const partitions_blacklist[] = {
+	"BCT", "EBT", "EB2", "EKS", "GP1", "GPT", "MBR", "PT",
+};
+
+static bool tegra_partition_name_match(struct tegra_partition *p,
+				       const char *name)
+{
+	return !strncmp(p->partition_name, name, TEGRA_PT_NAME_SIZE);
+}
+
+static bool tegra_partition_skip(struct tegra_partition *p,
+				 struct tegra_partition_table_parser *ptp,
+				 sector_t sector)
+{
+	unsigned int i;
+
+	/* skip eMMC boot partitions */
+	if (sector < ptp->boot_offset)
+		return true;
+
+	for (i = 0; i < ARRAY_SIZE(partitions_blacklist); i++) {
+		if (tegra_partition_name_match(p, partitions_blacklist[i]))
+			return true;
+	}
+
+	return false;
+}
+
+static const struct tegra_partition_type tegra_partition_expected_types[] = {
+	{ .type = TEGRA_PT_PART_TYPE_BCT,	.name = "BCT", },
+	{ .type = TEGRA_PT_PART_TYPE_EBT,	.name = "EBT", },
+	{ .type = TEGRA_PT_PART_TYPE_EBT,	.name = "EB2", },
+	{ .type = TEGRA_PT_PART_TYPE_PT,	.name = "PT",  },
+	{ .type = TEGRA_PT_PART_TYPE_GP1,	.name = "GP1", },
+	{ .type = TEGRA_PT_PART_TYPE_GPT,	.name = "GPT", },
+	{ .type = TEGRA_PT_PART_TYPE_GENERIC,	.name = NULL,  },
+};
+
+static int tegra_partition_type_valid(struct tegra_partition_table_parser *ptp,
+				      struct tegra_partition *p)
+{
+	const struct tegra_partition_type *ptype;
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(tegra_partition_expected_types); i++) {
+		ptype = &tegra_partition_expected_types[i];
+
+		if (ptype->name && !tegra_partition_name_match(p, ptype->name))
+			continue;
+
+		if (p->part_info.partition_type == ptype->type)
+			return 0;
+
+		/*
+		 * Unsure about all possible types, let's emit error and
+		 * allow to continue for now.
+		 */
+		if (!ptype->name)
+			return 1;
+	}
+
+	return -1;
+}
+
+static bool tegra_partition_valid(struct tegra_partition_table_parser *ptp,
+				  struct tegra_partition *p,
+				  struct tegra_partition *prev,
+				  sector_t sector,
+				  sector_t size)
+{
+	struct tegra_partition_info *prev_pi = &prev->part_info;
+	sector_t sect_end = TEGRA_PT_SECTOR(ptp,
+					    prev_pi->logical_sector_address +
+					    prev_pi->logical_sectors_num);
+	char *type, name[2][TEGRA_PT_NAME_SIZE + 1];
+	int err;
+
+	strscpy(name[0], p->partition_name,    sizeof(name[0]));
+	strscpy(name[1], prev->partition_name, sizeof(name[1]));
+
+	/* validate expected partition name/type */
+	err = tegra_partition_type_valid(ptp, p);
+	if (err) {
+		TEGRA_PT_PARSE_ERR(ptp, "partition_type: [%s] partition_type=%u\n",
+				   name[0], p->part_info.partition_type);
+		if (err < 0)
+			return false;
+
+		TEGRA_PT_ERR(ptp, "continuing, please update list of expected types\n");
+	}
+
+	/* validate partition table BCT addresses */
+	if (tegra_partition_name_match(p, "PT")) {
+		if (sector != TEGRA_PT_SECTOR(ptp, tegra_pt_logical_sector_address) &&
+		    size   != TEGRA_PT_SECTOR(ptp, tegra_pt_logical_sectors_num)) {
+			TEGRA_PT_PARSE_ERR(ptp, "PT location: sector=%llu size=%llu\n",
+					   sector, size);
+			return false;
+		}
+
+		if (ptp->pt_entry_checked) {
+			TEGRA_PT_PARSE_ERR(ptp, "(duplicated) PT\n");
+			return false;
+		}
+
+		ptp->pt_entry_checked = true;
+	}
+
+	if (sector + size < sector) {
+		TEGRA_PT_PARSE_ERR(ptp, "size: [%s] integer overflow sector=%llu size=%llu\n",
+				   name[0], sector, size);
+		return false;
+	}
+
+	/* validate allocation_policy=sequential (absolute unsupported) */
+	if (p != prev && sect_end > sector) {
+		TEGRA_PT_PARSE_ERR(ptp, "allocation_policy: [%s] end=%llu [%s] sector=%llu size=%llu\n",
+				   name[1], sect_end, name[0], sector, size);
+		return false;
+	}
+
+	if (ptp->dev_instance != p->mount_info.device_instance) {
+		TEGRA_PT_PARSE_ERR(ptp, "device_instance: [%s] device_instance=%u|%u\n",
+				   name[0], ptp->dev_instance,
+				   p->mount_info.device_instance);
+		return false;
+	}
+
+	if (ptp->dev_id != p->mount_info.device_id) {
+		TEGRA_PT_PARSE_ERR(ptp, "device_id: [%s] device_id=%u|%u\n",
+				   name[0], ptp->dev_id,
+				   p->mount_info.device_id);
+		return false;
+	}
+
+	if (p->partition_id > 127) {
+		TEGRA_PT_PARSE_ERR(ptp, "partition_id: [%s] partition_id=%u\n",
+				   name[0], p->partition_id);
+		return false;
+	}
+
+	sect_end = get_capacity(ptp->state->bdev->bd_disk);
+
+	/* eMMC boot partitions are below ptp->boot_offset */
+	if (sector < ptp->boot_offset) {
+		sect_end += ptp->boot_offset;
+		type = "boot";
+	} else {
+		sector -= ptp->boot_offset;
+		type = "main";
+	}
+
+	/* validate size */
+	if (!size || sector + size > sect_end) {
+		TEGRA_PT_PARSE_ERR(ptp, "size: [%s] %s partition boot_offt=%d end=%llu sector=%llu size=%llu\n",
+				   name[0], type, ptp->boot_offset, sect_end,
+				   sector, size);
+		return false;
+	}
+
+	return true;
+}
+
+static bool tegra_partitions_parsed(struct tegra_partition_table_parser *ptp,
+				    bool check_only)
+{
+	struct parsed_partitions *state = ptp->state;
+	struct tegra_partition_table *pt = ptp->pt;
+	sector_t sector, size;
+	int i, slot = 1;
+
+	ptp->pt_entry_checked = false;
+
+	for (i = 0; i < pt->secure.num_partitions; i++) {
+		struct tegra_partition *p = &pt->partitions[i];
+		struct tegra_partition *prev = &pt->partitions[max(i - 1, 0)];
+		struct tegra_partition_info *pi = &p->part_info;
+
+		if (slot == state->limit && !check_only)
+			break;
+
+		sector = TEGRA_PT_SECTOR(ptp, pi->logical_sector_address);
+		size   = TEGRA_PT_SECTOR(ptp, pi->logical_sectors_num);
+
+		if (check_only &&
+		    !tegra_partition_valid(ptp, p, prev, sector, size))
+			return false;
+
+		if (check_only ||
+		    tegra_partition_skip(p, ptp, sector))
+			continue;
+
+		put_partition(state, slot++, sector - ptp->boot_offset, size);
+	}
+
+	if (check_only && !ptp->pt_entry_checked) {
+		TEGRA_PT_PARSE_ERR(ptp, "PT: table entry not found\n");
+		return false;
+	}
+
+	return true;
+}
+
+static bool
+tegra_partition_table_parsed(struct tegra_partition_table_parser *ptp)
+{
+	if (ptp->pt->secure.num_partitions == 0 ||
+	    ptp->pt->secure.num_partitions > TEGRA_PT_MAX_PARTITIONS(ptp)) {
+		TEGRA_PT_PARSE_ERR(ptp, "num_partitions=%u\n",
+				   ptp->pt->secure.num_partitions);
+		return false;
+	}
+
+	return tegra_partitions_parsed(ptp, true) &&
+	       tegra_partitions_parsed(ptp, false);
+}
+
+static int
+tegra_partition_table_insec_hdr_valid(struct tegra_partition_table_parser *ptp)
+{
+	if (ptp->pt->insecure.magic   != TEGRA_PT_MAGIC ||
+	    ptp->pt->insecure.version != TEGRA_PT_VERSION) {
+		TEGRA_PT_PARSE_ERR(ptp, "insecure header: magic=0x%llx ver=0x%x\n",
+				   ptp->pt->insecure.magic,
+				   ptp->pt->insecure.version);
+		return 0;
+	}
+
+	return 1;
+}
+
+static int
+tegra_partition_table_sec_hdr_valid(struct tegra_partition_table_parser *ptp)
+{
+	size_t pt_size = ptp->pt->secure.num_partitions;
+
+	pt_size *= sizeof(ptp->pt->partitions[0]);
+	pt_size += TEGRA_PT_HEADER_SIZE;
+
+	if (ptp->pt->secure.magic   != TEGRA_PT_MAGIC ||
+	    ptp->pt->secure.version != TEGRA_PT_VERSION ||
+	    ptp->pt->secure.length  != ptp->pt->insecure.length ||
+	    ptp->pt->secure.length  < pt_size) {
+		TEGRA_PT_PARSE_ERR(ptp, "secure header: magic=0x%llx ver=0x%x length=%u|%u|%zu\n",
+				   ptp->pt->secure.magic,
+				   ptp->pt->secure.version,
+				   ptp->pt->secure.length,
+				   ptp->pt->insecure.length,
+				   pt_size);
+		return 0;
+	}
+
+	return 1;
+}
+
+static int
+tegra_partition_table_unencrypted(struct tegra_partition_table_parser *ptp)
+{
+	/* AES IV, all zeros if unencrypted */
+	if (ptp->pt->secure.random_data[0] || ptp->pt->secure.random_data[1] ||
+	    ptp->pt->secure.random_data[2] || ptp->pt->secure.random_data[3]) {
+		pr_err_once("encrypted partition table unsupported\n");
+		return 0;
+	}
+
+	return 1;
+}
+
+static int tegra_read_partition_table(struct tegra_partition_table_parser *ptp)
+{
+	union tegra_partition_table_u *ptu = (typeof(ptu))ptp->pt;
+	unsigned int i;
+	Sector sect;
+	void *part;
+
+	for (i = 0; i < ptp->logical_sector_size / SZ_512; i++) {
+		/*
+		 * Partition table takes at maximum 4096 bytes, but
+		 * read_part_sector() guarantees only that SECTOR_SIZE will
+		 * be read at minimum.
+		 */
+		part = read_part_sector(ptp->state, ptp->sector + i, &sect);
+		if (!part) {
+			TEGRA_PT_ERR(ptp, "failed to read sector %llu\n",
+				     ptp->sector + i);
+			return 0;
+		}
+
+		memcpy(ptu->pt_parts[i], part, SZ_512);
+		put_dev_sector(sect);
+	}
+
+	return 1;
+}
+
+static int tegra_partition_scan(struct tegra_partition_table_parser *ptp)
+{
+	sector_t start_sector, num_sectors;
+	int ret = 0;
+
+	num_sectors  = TEGRA_PT_SECTOR(ptp, tegra_pt_logical_sectors_num);
+	start_sector = TEGRA_PT_SECTOR(ptp, tegra_pt_logical_sector_address);
+
+	if (start_sector < ptp->boot_offset) {
+		TEGRA_PT_ERR(ptp,
+			     "scanning eMMC boot partitions unimplemented\n");
+		return 0;
+	}
+
+	ptp->sector = start_sector - ptp->boot_offset;
+
+	/*
+	 * Partition table is duplicated for num_sectors.
+	 * If first table is corrupted, we will try next.
+	 */
+	while (num_sectors--) {
+		ret = tegra_read_partition_table(ptp);
+		if (!ret)
+			goto next_sector;
+
+		ret = tegra_partition_table_insec_hdr_valid(ptp);
+		if (!ret)
+			goto next_sector;
+
+		ret = tegra_partition_table_unencrypted(ptp);
+		if (!ret)
+			goto next_sector;
+
+		ret = tegra_partition_table_sec_hdr_valid(ptp);
+		if (!ret)
+			goto next_sector;
+
+		ret = tegra_partition_table_parsed(ptp);
+		if (ret)
+			break;
+next_sector:
+		ptp->sector += TEGRA_PT_SECTOR_SIZE(ptp);
+	}
+
+	return ret;
+}
+
+static const u32 tegra20_sdhci_bases[TEGRA_PT_SDHCI_DEVICE_INSTANCES] = {
+	0xc8000000, 0xc8000200, 0xc8000400, 0xc8000600,
+};
+
+static const u32 tegra30_sdhci_bases[TEGRA_PT_SDHCI_DEVICE_INSTANCES] = {
+	0x78000000, 0x78000200, 0x78000400, 0x78000600,
+};
+
+static const struct of_device_id tegra_sdhci_match[] = {
+	{ .compatible = "nvidia,tegra20-sdhci", .data = tegra20_sdhci_bases, },
+	{ .compatible = "nvidia,tegra30-sdhci", .data = tegra30_sdhci_bases, },
+	{}
+};
+
+static int
+tegra_partition_table_emmc_boot_offset(struct tegra_partition_table_parser *ptp)
+{
+	struct mmc_card *card = mmc_bdev_to_card(ptp->state->bdev);
+	const struct of_device_id *matched;
+	const u32 *sdhci_bases;
+	u32 sdhci_base;
+	unsigned int i;
+	int err;
+
+	/* filter out unexpected/untested boot sources */
+	if (!card || card->ext_csd.rev < 3 ||
+	    !mmc_card_is_blockaddr(card) ||
+	     mmc_card_is_removable(card->host) ||
+	     bdev_logical_block_size(ptp->state->bdev) != SZ_512)
+		return -1;
+
+	/* skip everything unrelated to Tegra eMMC */
+	matched = of_match_node(tegra_sdhci_match, card->host->parent->of_node);
+	if (!matched)
+		return -1;
+
+	sdhci_bases = matched->data;
+
+	/* figure out SDHCI instance ID by the base address */
+	err = of_property_read_u32_index(card->host->parent->of_node,
+					 "reg", 0, &sdhci_base);
+	if (err)
+		return -1;
+
+	for (i = 0; i < TEGRA_PT_SDHCI_DEVICE_INSTANCES; i++) {
+		if (sdhci_base == sdhci_bases[i])
+			break;
+	}
+
+	if (i == TEGRA_PT_SDHCI_DEVICE_INSTANCES)
+		return -1;
+
+	ptp->dev_id       = TEGRA_PT_SDHCI_DEVICE_ID;
+	ptp->dev_instance = i;
+
+	/*
+	 * eMMC storage has two special boot partitions in addition to the
+	 * main one.  NVIDIA's bootloader linearizes eMMC boot0->boot1->main
+	 * accesses, this means that the partition table addresses are shifted
+	 * by the size of boot partitions.  In accordance with the eMMC
+	 * specification, the boot partition size is calculated as follows:
+	 *
+	 *	boot partition size = 128K byte x BOOT_SIZE_MULT
+	 *
+	 * This function returns number of sectors occupied by the both boot
+	 * partitions.
+	 */
+	return card->ext_csd.raw_boot_mult * SZ_128K /
+	       SZ_512 * MMC_NUM_BOOT_PARTITION;
+}
+
+/*
+ * Logical sector size may vary per device model and apparently there is no
+ * way to get information about the size from kernel. The info is hardcoded
+ * into bootloader and it doesn't tell us, so we'll just try all possible
+ * well-known sizes until succeed.
+ *
+ * For example Samsung Galaxy Tab 10.1 uses 2K sectors. While Acer A500,
+ * Nexus 7 and Ouya are using 4K sectors.
+ */
+static const unsigned int tegra_pt_logical_sector_sizes[] = {
+	SZ_4K, SZ_2K,
+};
+
+/*
+ * The 'tegraboot=<source>' command line option is supplied by NVIDIA
+ * bootloader.
+ */
+static bool tegra_boot_sdmmc;
+static int __init tegra_boot_fn(char *str)
+{
+	tegra_boot_sdmmc = !strcmp(str, "sdmmc");
+	return 1;
+}
+__setup("tegraboot=", tegra_boot_fn);
+
+int tegra_partition(struct parsed_partitions *state)
+{
+	struct tegra_partition_table_parser ptp = {};
+	unsigned int i;
+	int ret;
+
+	if (!soc_is_tegra() || !tegra_boot_sdmmc)
+		return 0;
+
+	ptp.state = state;
+
+	ptp.boot_offset = tegra_partition_table_emmc_boot_offset(&ptp);
+	if (ptp.boot_offset < 0)
+		return 0;
+
+	ptp.pt = kmalloc(SZ_4K, GFP_KERNEL);
+	if (!ptp.pt)
+		return 0;
+
+	for (i = 0; i < ARRAY_SIZE(tegra_pt_logical_sector_sizes); i++) {
+		ptp.logical_sector_size = tegra_pt_logical_sector_sizes[i];
+
+		ret = tegra_partition_scan(&ptp);
+		if (ret == 1) {
+			strlcat(state->pp_buf, "\n", PAGE_SIZE);
+			break;
+		}
+	}
+
+	kfree(ptp.pt);
+
+	return ret;
+}
diff --git a/include/soc/tegra/bootdata.h b/include/soc/tegra/bootdata.h
new file mode 100644
index 000000000000..7be207cb2519
--- /dev/null
+++ b/include/soc/tegra/bootdata.h
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __SOC_TEGRA_BOOTDATA_H__
+#define __SOC_TEGRA_BOOTDATA_H__
+
+#include <linux/compiler.h>
+#include <linux/types.h>
+
+#define TEGRA_BOOTDATA_VERSION_T20	NVBOOT_BOOTDATA_VERSION(0x2, 0x1)
+#define TEGRA_BOOTDATA_VERSION_T30	NVBOOT_BOOTDATA_VERSION(0x3, 0x1)
+
+#define NVBOOT_BOOTDATA_VERSION(a, b)	((((a) & 0xffff) << 16) | \
+					  ((b) & 0xffff))
+#define NVBOOT_CMAC_AES_HASH_LENGTH	4
+
+struct tegra20_boot_info_table {
+	u32 unused_data1[14];
+	u32 bct_size;
+	u32 bct_ptr;
+} __packed;
+
+struct tegra20_boot_config_table {
+	u32 crypto_hash[NVBOOT_CMAC_AES_HASH_LENGTH];
+	u32 random_aes_blk[NVBOOT_CMAC_AES_HASH_LENGTH];
+	u32 boot_data_version;
+	u32 unused_data1[712];
+	u32 unused_consumer_data1;
+	u16 partition_table_logical_sector_address;
+	u16 partition_table_num_logical_sectors;
+	u32 unused_consumer_data[294];
+	u32 unused_data[3];
+} __packed;
+
+struct tegra30_boot_config_table {
+	u32 crypto_hash[NVBOOT_CMAC_AES_HASH_LENGTH];
+	u32 random_aes_blk[NVBOOT_CMAC_AES_HASH_LENGTH];
+	u32 boot_data_version;
+	u32 unused_data1[1016];
+	u32 unused_consumer_data1;
+	u16 partition_table_logical_sector_address;
+	u16 partition_table_num_logical_sectors;
+	u32 unused_consumer_data[502];
+	u32 unused_data[3];
+} __packed;
+
+#endif /* __SOC_TEGRA_BOOTDATA_H__ */
diff --git a/include/soc/tegra/common.h b/include/soc/tegra/common.h
index 98027a76ce3d..744280ecab5f 100644
--- a/include/soc/tegra/common.h
+++ b/include/soc/tegra/common.h
@@ -6,6 +6,15 @@
 #ifndef __SOC_TEGRA_COMMON_H__
 #define __SOC_TEGRA_COMMON_H__
 
+#include <linux/types.h>
+
+#ifdef CONFIG_ARCH_TEGRA
 bool soc_is_tegra(void);
+#else
+static inline bool soc_is_tegra(void)
+{
+	return false;
+}
+#endif
 
 #endif /* __SOC_TEGRA_COMMON_H__ */
diff --git a/include/soc/tegra/partition.h b/include/soc/tegra/partition.h
new file mode 100644
index 000000000000..4e424543973c
--- /dev/null
+++ b/include/soc/tegra/partition.h
@@ -0,0 +1,83 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __SOC_TEGRA_PARTITION_H__
+#define __SOC_TEGRA_PARTITION_H__
+
+#include <linux/compiler.h>
+#include <linux/types.h>
+
+#define TEGRA_PT_MAGIC				0xffffffff8f9e8d8bULL
+#define TEGRA_PT_VERSION			0x100
+#define TEGRA_PT_AES_HASH_SIZE			4
+#define TEGRA_PT_NAME_SIZE			4
+
+#define TEGRA_PT_SDHCI_DEVICE_ID		18
+#define TEGRA_PT_SDHCI_DEVICE_INSTANCES		4
+
+#define TEGRA_PT_PART_TYPE_BCT			1
+#define TEGRA_PT_PART_TYPE_EBT			2
+#define TEGRA_PT_PART_TYPE_PT			3
+#define TEGRA_PT_PART_TYPE_GENERIC		6
+#define TEGRA_PT_PART_TYPE_GP1			9
+#define TEGRA_PT_PART_TYPE_GPT			10
+
+struct tegra_partition_mount_info {
+	u32 device_id;
+	u32 device_instance;
+	u32 device_attr;
+	u8  mount_path[TEGRA_PT_NAME_SIZE];
+	u32 file_system_type;
+	u32 file_system_attr;
+} __packed;
+
+struct tegra_partition_info {
+	u32 partition_attr;
+	u32 __pad1;
+	u64 logical_sector_address;
+	u64 logical_sectors_num;
+	u64 __pad2[2];
+	u32 partition_type;
+	u32 __pad3;
+} __packed;
+
+struct tegra_partition {
+	u32 partition_id;
+	u8  partition_name[TEGRA_PT_NAME_SIZE];
+	struct tegra_partition_mount_info mount_info;
+	struct tegra_partition_info part_info;
+} __packed;
+
+struct tegra_partition_header_insecure {
+	u64 magic;
+	u32 version;
+	u32 length;
+	u32 signature[TEGRA_PT_AES_HASH_SIZE];
+} __packed;
+
+struct tegra_partition_header_secure {
+	u32 random_data[TEGRA_PT_AES_HASH_SIZE];
+	u64 magic;
+	u32 version;
+	u32 length;
+	u32 num_partitions;
+	u32 __pad;
+} __packed;
+
+struct tegra_partition_table {
+	struct tegra_partition_header_insecure insecure;
+	struct tegra_partition_header_secure secure;
+	struct tegra_partition partitions[];
+} __packed;
+
+#ifdef CONFIG_TEGRA_PARTITION
+void tegra_partition_table_setup(unsigned int logical_sector_address,
+				 unsigned int logical_sectors_num);
+#else
+static inline void
+tegra_partition_table_setup(unsigned int logical_sector_address,
+			    unsigned int logical_sectors_num)
+{
+}
+#endif
+
+#endif /* __SOC_TEGRA_PARTITION_H__ */
-- 
2.26.0


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

* [PATCH v4 4/6] partitions/efi: Support GPT entry lookup at a non-standard location
  2020-05-15  1:41 ` Dmitry Osipenko
                   ` (2 preceding siblings ...)
  (?)
@ 2020-05-15  1:41 ` Dmitry Osipenko
  2020-05-15 10:03     ` Steve McIntyre
  -1 siblings, 1 reply; 17+ messages in thread
From: Dmitry Osipenko @ 2020-05-15  1:41 UTC (permalink / raw)
  To: Jens Axboe, Thierry Reding, Jonathan Hunter,
	Michał Mirosław, David Heidelberg, Peter Geis,
	Stephen Warren, Nicolas Chauvet, Ulf Hansson, Adrian Hunter,
	Billy Laws, Nils Östlund, Christoph Hellwig, Ard Biesheuvel,
	Davidlohr Bueso
  Cc: linux-tegra, linux-block, Andrey Danin, Gilles Grandou,
	Ryan Grachek, linux-mmc, linux-kernel, linux-efi

Most of consumer-grade NVIDIA Tegra devices use a proprietary bootloader
that can't be easily replaced because it's locked down using Secure Boot
cryptography singing and the crypto keys aren't given to a device owner.
These devices usually have eMMC storage that is partitioned using a custom
NVIDIA Tegra partition table format.  Of course bootloader and other
"special things" are stored on the eMMC storage, and thus, the partition
format can't be changed.

The Tegra partition format has been reverse-engineered, but NVIDIA did
another odd thing by merging "boot" and "main" eMMC HW partitions into a
single virtual partition in theirs bootloader.  This is not supported by
Linux kernel and can't be easily implemented.  Hence partition table entry
isn't accessible by kernel if it's located at the "boot" eMMC partition.
Luckily this is a rare case in practice and even if it's the case, likely
that the proprietary bootloader will supply kernel with a non-standard
gpt_sector= cmdline option.  This gpt_sector= argument points at a GPT
entry that is placed at a non-standard location on the eMMC storage.

This patch allows to support the non-standard cmdline option for NVIDIA
Tegra devices without bothering any other platforms.  The force_gpt_sector
variable should be set before invoking efi_partition() and be unset after
the invocation completion.  This variable, if set, instructs GPT parser
to look up GPT entry at the given sector in addition to the standard GPT
locations.

This patch is based on the original work done by Colin Cross for the
downstream Android kernel.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 block/partitions/efi.c | 10 ++++++++++
 block/partitions/efi.h |  2 ++
 2 files changed, 12 insertions(+)

diff --git a/block/partitions/efi.c b/block/partitions/efi.c
index b64bfdd4326c..48e4c2aeeded 100644
--- a/block/partitions/efi.c
+++ b/block/partitions/efi.c
@@ -103,6 +103,12 @@ force_gpt_fn(char *str)
 }
 __setup("gpt", force_gpt_fn);
 
+/* Used by NVIDIA Tegra partition parser in order to convey a non-standard
+ * location of the GPT entry for lookup. This variable should be set before
+ * efi_partition() invocation for instructing parser to look up GPT entry at
+ * the given sector, and it should be unset after completion of the invocation.
+ */
+sector_t force_gpt_sector;
 
 /**
  * efi_crc32() - EFI version of crc32 function
@@ -621,6 +627,10 @@ static int find_valid_gpt(struct parsed_partitions *state, gpt_header **gpt,
         if (!good_agpt && force_gpt)
                 good_agpt = is_gpt_valid(state, lastlba, &agpt, &aptes);
 
+	if (!good_agpt && force_gpt && force_gpt_sector)
+		good_agpt = is_gpt_valid(state, force_gpt_sector,
+					 &agpt, &aptes);
+
         /* The obviously unsuccessful case */
         if (!good_pgpt && !good_agpt)
                 goto fail;
diff --git a/block/partitions/efi.h b/block/partitions/efi.h
index 8cc2b88d0aa8..630cf21439af 100644
--- a/block/partitions/efi.h
+++ b/block/partitions/efi.h
@@ -113,4 +113,6 @@ typedef struct _legacy_mbr {
 	__le16 signature;
 } __packed legacy_mbr;
 
+extern sector_t force_gpt_sector;
+
 #endif
-- 
2.26.0

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

* [PATCH v4 5/6] partitions/tegra: Support gpt_sector= command line option
  2020-05-15  1:41 ` Dmitry Osipenko
                   ` (3 preceding siblings ...)
  (?)
@ 2020-05-15  1:41 ` Dmitry Osipenko
  -1 siblings, 0 replies; 17+ messages in thread
From: Dmitry Osipenko @ 2020-05-15  1:41 UTC (permalink / raw)
  To: Jens Axboe, Thierry Reding, Jonathan Hunter,
	Michał Mirosław, David Heidelberg, Peter Geis,
	Stephen Warren, Nicolas Chauvet, Ulf Hansson, Adrian Hunter,
	Billy Laws, Nils Östlund, Christoph Hellwig, Ard Biesheuvel,
	Davidlohr Bueso
  Cc: linux-tegra, linux-block, Andrey Danin, Gilles Grandou,
	Ryan Grachek, linux-mmc, linux-kernel, linux-efi

The gpt_sector=<sector> causes the GPT partition parser to look at the
specified sector for a valid GPT header if the GPT is not found at the
beginning or the end of a block device.  This is needed by Tegra-based
devices that have TegraPT and GPT placed in inaccessible by kernel
locations.  The GPT entry duplicates TegraPT partitions.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 block/partitions/check.h |  1 +
 block/partitions/core.c  |  1 +
 block/partitions/efi.c   |  6 ++++++
 block/partitions/tegra.c | 38 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 46 insertions(+)

diff --git a/block/partitions/check.h b/block/partitions/check.h
index ffa01cc4b0b0..ff07435b3ac3 100644
--- a/block/partitions/check.h
+++ b/block/partitions/check.h
@@ -67,5 +67,6 @@ int osf_partition(struct parsed_partitions *state);
 int sgi_partition(struct parsed_partitions *state);
 int sun_partition(struct parsed_partitions *state);
 int sysv68_partition(struct parsed_partitions *state);
+int tegra_partition_gpt(struct parsed_partitions *state);
 int tegra_partition(struct parsed_partitions *state);
 int ultrix_partition(struct parsed_partitions *state);
diff --git a/block/partitions/core.c b/block/partitions/core.c
index 0b4720372f07..ece70f15f24d 100644
--- a/block/partitions/core.c
+++ b/block/partitions/core.c
@@ -83,6 +83,7 @@ static int (*check_part[])(struct parsed_partitions *) = {
 	sysv68_partition,
 #endif
 #ifdef CONFIG_TEGRA_PARTITION
+	tegra_partition_gpt,
 	tegra_partition,
 #endif
 	NULL
diff --git a/block/partitions/efi.c b/block/partitions/efi.c
index 48e4c2aeeded..f3b26be2bd6e 100644
--- a/block/partitions/efi.c
+++ b/block/partitions/efi.c
@@ -98,6 +98,12 @@ static int force_gpt;
 static int __init
 force_gpt_fn(char *str)
 {
+	/* This check allows to parse "gpt gpt_sector=" properly since
+	 * "gpt" overlaps with "gpt_sector", see tegra_gpt_sector_fn().
+	 */
+	if (force_gpt)
+		return 0;
+
 	force_gpt = 1;
 	return 1;
 }
diff --git a/block/partitions/tegra.c b/block/partitions/tegra.c
index d1b84fff362c..c2dae0f32c2a 100644
--- a/block/partitions/tegra.c
+++ b/block/partitions/tegra.c
@@ -30,6 +30,7 @@
 #include <soc/tegra/common.h>
 #include <soc/tegra/partition.h>
 
+#include "efi.h"
 #include "check.h"
 
 #define TEGRA_PT_SECTOR_SIZE(ptp)	((ptp)->logical_sector_size / SZ_512)
@@ -563,3 +564,40 @@ int tegra_partition(struct parsed_partitions *state)
 
 	return ret;
 }
+
+/*
+ * This allows a kernel command line option 'gpt_sector=<sector>' to
+ * enable GPT header lookup at a non-standard location. This option
+ * is given to kernel by a proprietary bootloader, which is used by
+ * *most* (but not all) of NVIDIA Tegra-based devices.
+ */
+static sector_t tegra_gpt_sector;
+static int __init tegra_gpt_sector_fn(char *str)
+{
+	WARN_ON(kstrtoull(str, 10, &tegra_gpt_sector) < 0);
+	return 1;
+}
+__setup("gpt_sector=", tegra_gpt_sector_fn);
+
+int tegra_partition_gpt(struct parsed_partitions *state)
+{
+	int ret = 0;
+
+#ifdef CONFIG_EFI_PARTITION
+	struct tegra_partition_table_parser ptp = {};
+
+	if (!soc_is_tegra() || !tegra_boot_sdmmc || !tegra_gpt_sector)
+		return 0;
+
+	ptp.state = state;
+
+	ptp.boot_offset = tegra_partition_table_emmc_boot_offset(&ptp);
+	if (ptp.boot_offset < 0)
+		return 0;
+
+	force_gpt_sector = tegra_gpt_sector;
+	ret = efi_partition(ptp.state);
+	force_gpt_sector = 0;
+#endif
+	return ret;
+}
-- 
2.26.0

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

* [PATCH v4 6/6] soc/tegra: Expose Boot Configuration Table via sysfs
  2020-05-15  1:41 ` Dmitry Osipenko
                   ` (4 preceding siblings ...)
  (?)
@ 2020-05-15  1:41 ` Dmitry Osipenko
  -1 siblings, 0 replies; 17+ messages in thread
From: Dmitry Osipenko @ 2020-05-15  1:41 UTC (permalink / raw)
  To: Jens Axboe, Thierry Reding, Jonathan Hunter,
	Michał Mirosław, David Heidelberg, Peter Geis,
	Stephen Warren, Nicolas Chauvet, Ulf Hansson, Adrian Hunter,
	Billy Laws, Nils Östlund, Christoph Hellwig, Ard Biesheuvel,
	Davidlohr Bueso
  Cc: linux-tegra, linux-block, Andrey Danin, Gilles Grandou,
	Ryan Grachek, linux-mmc, linux-kernel, linux-efi

It's quite useful to have unencrypted BCT exposed to userspace for
debugging purposes, so let's expose it via sysfs. The BCT data will
present in /sys/tegra/boot_config_table binary file if BCT is available.

Suggested-by: Michał Mirosław <mirq-linux@rere.qmqm.pl>
Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 arch/arm/mach-tegra/tegra.c  |  4 +++
 drivers/soc/tegra/Makefile   |  1 +
 drivers/soc/tegra/bootdata.c | 51 ++++++++++++++++++++++++++++++++++++
 drivers/soc/tegra/common.c   | 17 ++++++++++++
 include/soc/tegra/bootdata.h |  2 ++
 include/soc/tegra/common.h   |  3 +++
 6 files changed, 78 insertions(+)
 create mode 100644 drivers/soc/tegra/bootdata.c

diff --git a/arch/arm/mach-tegra/tegra.c b/arch/arm/mach-tegra/tegra.c
index da6bcd85398b..5f40463f1b97 100644
--- a/arch/arm/mach-tegra/tegra.c
+++ b/arch/arm/mach-tegra/tegra.c
@@ -72,6 +72,7 @@ static void __init tegra_boot_config_table_init(void)
 	u32 iram_end   = TEGRA_IRAM_BASE + TEGRA_IRAM_SIZE;
 	u32 iram_start = TEGRA_IRAM_BASE;
 	u32 pt_addr, pt_size, bct_size;
+	void __iomem *bct_ptr;
 
 	t20_bit = IO_ADDRESS(TEGRA_IRAM_BASE);
 
@@ -90,6 +91,7 @@ static void __init tegra_boot_config_table_init(void)
 
 		pt_addr = t20_bct->partition_table_logical_sector_address;
 		pt_size = t20_bct->partition_table_num_logical_sectors;
+		bct_ptr = t20_bct;
 
 	} else if (of_machine_is_compatible("nvidia,tegra30")) {
 		bct_size = sizeof(*t30_bct);
@@ -106,12 +108,14 @@ static void __init tegra_boot_config_table_init(void)
 
 		pt_addr = t30_bct->partition_table_logical_sector_address;
 		pt_size = t30_bct->partition_table_num_logical_sectors;
+		bct_ptr = t30_bct;
 	} else {
 		return;
 	}
 
 	pr_info("%s: BCT found in IRAM\n", __func__);
 
+	tegra_bootdata_bct_setup(bct_ptr, bct_size);
 	tegra_partition_table_setup(pt_addr, pt_size);
 }
 
diff --git a/drivers/soc/tegra/Makefile b/drivers/soc/tegra/Makefile
index 9c809c1814bd..8be2bfb4d95d 100644
--- a/drivers/soc/tegra/Makefile
+++ b/drivers/soc/tegra/Makefile
@@ -1,6 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0
 obj-y += fuse/
 
+obj-y += bootdata.o
 obj-y += common.o
 obj-$(CONFIG_SOC_TEGRA_FLOWCTRL) += flowctrl.o
 obj-$(CONFIG_SOC_TEGRA_PMC) += pmc.o
diff --git a/drivers/soc/tegra/bootdata.c b/drivers/soc/tegra/bootdata.c
new file mode 100644
index 000000000000..e18a27b74023
--- /dev/null
+++ b/drivers/soc/tegra/bootdata.c
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/sizes.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/types.h>
+
+#include <soc/tegra/bootdata.h>
+#include <soc/tegra/common.h>
+
+/*
+ * spare_bct[] will be released once kernel is booted, hence not wasting
+ * kernel space if BCT is missing. The tegra_bct can't be allocated during
+ * of BCT setting up because it's too early for the slab allocator.
+ */
+static u8 spare_bct[SZ_8K] __initdata;
+static u8 *tegra_bct;
+
+static ssize_t boot_config_table_read(struct file *filp,
+				      struct kobject *kobj,
+				      struct bin_attribute *bin_attr,
+				      char *buf, loff_t off, size_t count)
+{
+	memcpy(buf, tegra_bct + off, count);
+	return count;
+}
+static BIN_ATTR_RO(boot_config_table, 0);
+
+static int __init tegra_bootdata_bct_sysfs_init(void)
+{
+	if (!bin_attr_boot_config_table.size)
+		return 0;
+
+	tegra_bct = kmalloc(GFP_KERNEL, bin_attr_boot_config_table.size);
+	if (!tegra_bct)
+		return -ENOMEM;
+
+	memcpy(tegra_bct, spare_bct, bin_attr_boot_config_table.size);
+
+	return sysfs_create_bin_file(tegra_soc_kobj,
+				     &bin_attr_boot_config_table);
+}
+late_initcall(tegra_bootdata_bct_sysfs_init)
+
+void __init tegra_bootdata_bct_setup(void __iomem *bct_ptr, size_t bct_size)
+{
+	memcpy_fromio(spare_bct, bct_ptr, bct_size);
+	bin_attr_boot_config_table.size = bct_size;
+}
diff --git a/drivers/soc/tegra/common.c b/drivers/soc/tegra/common.c
index 3dc54f59cafe..2b4b49eacb2e 100644
--- a/drivers/soc/tegra/common.c
+++ b/drivers/soc/tegra/common.c
@@ -3,10 +3,15 @@
  * Copyright (C) 2014 NVIDIA CORPORATION.  All rights reserved.
  */
 
+#include <linux/init.h>
+#include <linux/kernel.h>
 #include <linux/of.h>
+#include <linux/sysfs.h>
 
 #include <soc/tegra/common.h>
 
+struct kobject *tegra_soc_kobj;
+
 static const struct of_device_id tegra_machine_match[] = {
 	{ .compatible = "nvidia,tegra20", },
 	{ .compatible = "nvidia,tegra30", },
@@ -31,3 +36,15 @@ bool soc_is_tegra(void)
 
 	return match != NULL;
 }
+
+static int __init tegra_soc_sysfs_init(void)
+{
+	if (!soc_is_tegra())
+		return 0;
+
+	tegra_soc_kobj = kobject_create_and_add("tegra", NULL);
+	WARN_ON(!tegra_soc_kobj);
+
+	return 0;
+}
+arch_initcall(tegra_soc_sysfs_init)
diff --git a/include/soc/tegra/bootdata.h b/include/soc/tegra/bootdata.h
index 7be207cb2519..d5c7a251517d 100644
--- a/include/soc/tegra/bootdata.h
+++ b/include/soc/tegra/bootdata.h
@@ -43,4 +43,6 @@ struct tegra30_boot_config_table {
 	u32 unused_data[3];
 } __packed;
 
+void tegra_bootdata_bct_setup(void __iomem *bct_ptr, size_t bct_size);
+
 #endif /* __SOC_TEGRA_BOOTDATA_H__ */
diff --git a/include/soc/tegra/common.h b/include/soc/tegra/common.h
index 744280ecab5f..0bc11b45c98e 100644
--- a/include/soc/tegra/common.h
+++ b/include/soc/tegra/common.h
@@ -7,8 +7,11 @@
 #define __SOC_TEGRA_COMMON_H__
 
 #include <linux/types.h>
+#include <linux/sysfs.h>
 
 #ifdef CONFIG_ARCH_TEGRA
+extern struct kobject *tegra_soc_kobj;
+
 bool soc_is_tegra(void);
 #else
 static inline bool soc_is_tegra(void)
-- 
2.26.0

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

* Re: [PATCH v4 3/6] partitions: Introduce NVIDIA Tegra Partition Table
  2020-05-15  1:41     ` Dmitry Osipenko
@ 2020-05-15  1:58         ` Randy Dunlap
  -1 siblings, 0 replies; 17+ messages in thread
From: Randy Dunlap @ 2020-05-15  1:58 UTC (permalink / raw)
  To: Dmitry Osipenko, Jens Axboe, Thierry Reding, Jonathan Hunter,
	Michał Mirosław, David Heidelberg, Peter Geis,
	Stephen Warren, Nicolas Chauvet, Ulf Hansson, Adrian Hunter,
	Billy Laws, Nils Östlund, Christoph Hellwig, Ard Biesheuvel,
	Davidlohr Bueso
  Cc: linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-block-u79uwXL29TY76Z2rM5mHXA, Andrey Danin, Gilles Grandou,
	Ryan Grachek, linux-mmc-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, linux-efi

On 5/14/20 6:41 PM, Dmitry Osipenko wrote:
> diff --git a/block/partitions/Kconfig b/block/partitions/Kconfig
> index 702689a628f0..2c1408cba1a6 100644
> --- a/block/partitions/Kconfig
> +++ b/block/partitions/Kconfig
> @@ -268,3 +268,11 @@ config CMDLINE_PARTITION
>  	help
>  	  Say Y here if you want to read the partition table from bootargs.
>  	  The format for the command line is just like mtdparts.
> +
> +config TEGRA_PARTITION
> +	bool "NVIDIA Tegra Partition support" if PARTITION_ADVANCED
> +	default y if ARCH_TEGRA
> +	depends on (ARCH_TEGRA && MMC_BLOCK) || COMPILE_TEST

That looks odd. Such depends are more often like:
	depends on MMC_BLOCK && (ARCH_TEGRA || COMPILE_TEST)

but that's just my experience. If this works when ARCH_TEGRA and MMC_BLOCK
are not set and COMPILE_TEST is set, that's fine.

> +	help
> +	  Say Y here if you would like to be able to read the hard disk
> +	  partition table format used by NVIDIA Tegra machines.

thanks.
-- 
~Randy

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

* Re: [PATCH v4 3/6] partitions: Introduce NVIDIA Tegra Partition Table
@ 2020-05-15  1:58         ` Randy Dunlap
  0 siblings, 0 replies; 17+ messages in thread
From: Randy Dunlap @ 2020-05-15  1:58 UTC (permalink / raw)
  To: Dmitry Osipenko, Jens Axboe, Thierry Reding, Jonathan Hunter,
	Michał Mirosław, David Heidelberg, Peter Geis,
	Stephen Warren, Nicolas Chauvet, Ulf Hansson, Adrian Hunter,
	Billy Laws, Nils Östlund, Christoph Hellwig, Ard Biesheuvel,
	Davidlohr Bueso
  Cc: linux-tegra, linux-block, Andrey Danin, Gilles Grandou,
	Ryan Grachek, linux-mmc, linux-kernel, linux-efi

On 5/14/20 6:41 PM, Dmitry Osipenko wrote:
> diff --git a/block/partitions/Kconfig b/block/partitions/Kconfig
> index 702689a628f0..2c1408cba1a6 100644
> --- a/block/partitions/Kconfig
> +++ b/block/partitions/Kconfig
> @@ -268,3 +268,11 @@ config CMDLINE_PARTITION
>  	help
>  	  Say Y here if you want to read the partition table from bootargs.
>  	  The format for the command line is just like mtdparts.
> +
> +config TEGRA_PARTITION
> +	bool "NVIDIA Tegra Partition support" if PARTITION_ADVANCED
> +	default y if ARCH_TEGRA
> +	depends on (ARCH_TEGRA && MMC_BLOCK) || COMPILE_TEST

That looks odd. Such depends are more often like:
	depends on MMC_BLOCK && (ARCH_TEGRA || COMPILE_TEST)

but that's just my experience. If this works when ARCH_TEGRA and MMC_BLOCK
are not set and COMPILE_TEST is set, that's fine.

> +	help
> +	  Say Y here if you would like to be able to read the hard disk
> +	  partition table format used by NVIDIA Tegra machines.

thanks.
-- 
~Randy


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

* Re: [PATCH v4 3/6] partitions: Introduce NVIDIA Tegra Partition Table
  2020-05-15  1:58         ` Randy Dunlap
  (?)
@ 2020-05-15  2:02         ` Dmitry Osipenko
  -1 siblings, 0 replies; 17+ messages in thread
From: Dmitry Osipenko @ 2020-05-15  2:02 UTC (permalink / raw)
  To: Randy Dunlap, Jens Axboe, Thierry Reding, Jonathan Hunter,
	Michał Mirosław, David Heidelberg, Peter Geis,
	Stephen Warren, Nicolas Chauvet, Ulf Hansson, Adrian Hunter,
	Billy Laws, Nils Östlund, Christoph Hellwig, Ard Biesheuvel,
	Davidlohr Bueso
  Cc: linux-tegra, linux-block, Andrey Danin, Gilles Grandou,
	Ryan Grachek, linux-mmc, linux-kernel, linux-efi

15.05.2020 04:58, Randy Dunlap пишет:
> On 5/14/20 6:41 PM, Dmitry Osipenko wrote:
>> diff --git a/block/partitions/Kconfig b/block/partitions/Kconfig
>> index 702689a628f0..2c1408cba1a6 100644
>> --- a/block/partitions/Kconfig
>> +++ b/block/partitions/Kconfig
>> @@ -268,3 +268,11 @@ config CMDLINE_PARTITION
>>  	help
>>  	  Say Y here if you want to read the partition table from bootargs.
>>  	  The format for the command line is just like mtdparts.
>> +
>> +config TEGRA_PARTITION
>> +	bool "NVIDIA Tegra Partition support" if PARTITION_ADVANCED
>> +	default y if ARCH_TEGRA
>> +	depends on (ARCH_TEGRA && MMC_BLOCK) || COMPILE_TEST
> 
> That looks odd. Such depends are more often like:
> 	depends on MMC_BLOCK && (ARCH_TEGRA || COMPILE_TEST)
> 
> but that's just my experience. If this works when ARCH_TEGRA and MMC_BLOCK
> are not set and COMPILE_TEST is set, that's fine.

Ah, right! It shouldn't work since mmc_bdev_to_card() will be undefined
if MMC_BLOCK=n. Good catch, thank you! :)

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

* Re: [PATCH v4 4/6] partitions/efi: Support GPT entry lookup at a non-standard location
  2020-05-15  1:41 ` [PATCH v4 4/6] partitions/efi: Support GPT entry lookup at a non-standard location Dmitry Osipenko
@ 2020-05-15 10:03     ` Steve McIntyre
  0 siblings, 0 replies; 17+ messages in thread
From: Steve McIntyre @ 2020-05-15 10:03 UTC (permalink / raw)
  To: Dmitry Osipenko
  Cc: Jens Axboe, Thierry Reding, Jonathan Hunter,
	Michał Mirosław, David Heidelberg, Peter Geis,
	Stephen Warren, Nicolas Chauvet, Ulf Hansson, Adrian Hunter,
	Billy Laws, Nils Östlund, Christoph Hellwig, Ard Biesheuvel,
	Davidlohr Bueso, linux-tegra, linux-block, Andrey Danin,
	Gilles Grandou

On Fri, May 15, 2020 at 04:41:41AM +0300, Dmitry Osipenko wrote:
>Most of consumer-grade NVIDIA Tegra devices use a proprietary bootloader
>that can't be easily replaced because it's locked down using Secure Boot
>cryptography singing and the crypto keys aren't given to a device owner.
              ^^^^^^^ typo
>These devices usually have eMMC storage that is partitioned using a custom
>NVIDIA Tegra partition table format.  Of course bootloader and other
>"special things" are stored on the eMMC storage, and thus, the partition
>format can't be changed.

...

-- 
Steve McIntyre, Cambridge, UK.                                steve@einval.com
"Further comment on how I feel about IBM will appear once I've worked out
 whether they're being malicious or incompetent. Capital letters are forecast."
 Matthew Garrett, http://www.livejournal.com/users/mjg59/30675.html

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

* Re: [PATCH v4 4/6] partitions/efi: Support GPT entry lookup at a non-standard location
@ 2020-05-15 10:03     ` Steve McIntyre
  0 siblings, 0 replies; 17+ messages in thread
From: Steve McIntyre @ 2020-05-15 10:03 UTC (permalink / raw)
  To: Dmitry Osipenko
  Cc: Jens Axboe, Thierry Reding, Jonathan Hunter,
	Michał Mirosław, David Heidelberg, Peter Geis,
	Stephen Warren, Nicolas Chauvet, Ulf Hansson, Adrian Hunter,
	Billy Laws, Nils Östlund, Christoph Hellwig, Ard Biesheuvel,
	Davidlohr Bueso, linux-tegra, linux-block, Andrey Danin,
	Gilles Grandou, Ryan Grachek, linux-mmc, linux-kernel, linux-efi

On Fri, May 15, 2020 at 04:41:41AM +0300, Dmitry Osipenko wrote:
>Most of consumer-grade NVIDIA Tegra devices use a proprietary bootloader
>that can't be easily replaced because it's locked down using Secure Boot
>cryptography singing and the crypto keys aren't given to a device owner.
              ^^^^^^^ typo
>These devices usually have eMMC storage that is partitioned using a custom
>NVIDIA Tegra partition table format.  Of course bootloader and other
>"special things" are stored on the eMMC storage, and thus, the partition
>format can't be changed.

...

-- 
Steve McIntyre, Cambridge, UK.                                steve@einval.com
"Further comment on how I feel about IBM will appear once I've worked out
 whether they're being malicious or incompetent. Capital letters are forecast."
 Matthew Garrett, http://www.livejournal.com/users/mjg59/30675.html


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

* Re: [PATCH v4 4/6] partitions/efi: Support GPT entry lookup at a non-standard location
  2020-05-15 10:03     ` Steve McIntyre
@ 2020-05-15 15:52         ` Dmitry Osipenko
  -1 siblings, 0 replies; 17+ messages in thread
From: Dmitry Osipenko @ 2020-05-15 15:52 UTC (permalink / raw)
  To: Steve McIntyre
  Cc: Jens Axboe, Thierry Reding, Jonathan Hunter,
	Michał Mirosław, David Heidelberg, Peter Geis,
	Stephen Warren, Nicolas Chauvet, Ulf Hansson, Adrian Hunter,
	Billy Laws, Nils Östlund, Christoph Hellwig, Ard Biesheuvel,
	Davidlohr Bueso, linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-block-u79uwXL29TY76Z2rM5mHXA, Andrey Danin, Gilles Grandou,
	Ryan Grachek

15.05.2020 13:03, Steve McIntyre пишет:
> On Fri, May 15, 2020 at 04:41:41AM +0300, Dmitry Osipenko wrote:
>> Most of consumer-grade NVIDIA Tegra devices use a proprietary bootloader
>> that can't be easily replaced because it's locked down using Secure Boot
>> cryptography singing and the crypto keys aren't given to a device owner.
>               ^^^^^^^ typo
>> These devices usually have eMMC storage that is partitioned using a custom
>> NVIDIA Tegra partition table format.  Of course bootloader and other
>> "special things" are stored on the eMMC storage, and thus, the partition
>> format can't be changed.
> 
> ...
> 

Thanks! I'll correct it in v5.

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

* Re: [PATCH v4 4/6] partitions/efi: Support GPT entry lookup at a non-standard location
@ 2020-05-15 15:52         ` Dmitry Osipenko
  0 siblings, 0 replies; 17+ messages in thread
From: Dmitry Osipenko @ 2020-05-15 15:52 UTC (permalink / raw)
  To: Steve McIntyre
  Cc: Jens Axboe, Thierry Reding, Jonathan Hunter,
	Michał Mirosław, David Heidelberg, Peter Geis,
	Stephen Warren, Nicolas Chauvet, Ulf Hansson, Adrian Hunter,
	Billy Laws, Nils Östlund, Christoph Hellwig, Ard Biesheuvel,
	Davidlohr Bueso, linux-tegra, linux-block, Andrey Danin,
	Gilles Grandou, Ryan Grachek, linux-mmc, linux-kernel, linux-efi

15.05.2020 13:03, Steve McIntyre пишет:
> On Fri, May 15, 2020 at 04:41:41AM +0300, Dmitry Osipenko wrote:
>> Most of consumer-grade NVIDIA Tegra devices use a proprietary bootloader
>> that can't be easily replaced because it's locked down using Secure Boot
>> cryptography singing and the crypto keys aren't given to a device owner.
>               ^^^^^^^ typo
>> These devices usually have eMMC storage that is partitioned using a custom
>> NVIDIA Tegra partition table format.  Of course bootloader and other
>> "special things" are stored on the eMMC storage, and thus, the partition
>> format can't be changed.
> 
> ...
> 

Thanks! I'll correct it in v5.

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

end of thread, other threads:[~2020-05-15 15:53 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-05-15  1:41 [PATCH v4 0/6] Introduce NVIDIA Tegra Partition Table Dmitry Osipenko
2020-05-15  1:41 ` Dmitry Osipenko
2020-05-15  1:41 ` [PATCH v4 1/6] mmc: core: Add raw_boot_mult field to mmc_ext_csd Dmitry Osipenko
     [not found] ` <20200515014143.12984-1-digetx-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2020-05-15  1:41   ` [PATCH v4 2/6] mmc: block: Add mmc_bdev_to_card() helper Dmitry Osipenko
2020-05-15  1:41     ` Dmitry Osipenko
2020-05-15  1:41   ` [PATCH v4 3/6] partitions: Introduce NVIDIA Tegra Partition Table Dmitry Osipenko
2020-05-15  1:41     ` Dmitry Osipenko
     [not found]     ` <20200515014143.12984-4-digetx-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2020-05-15  1:58       ` Randy Dunlap
2020-05-15  1:58         ` Randy Dunlap
2020-05-15  2:02         ` Dmitry Osipenko
2020-05-15  1:41 ` [PATCH v4 4/6] partitions/efi: Support GPT entry lookup at a non-standard location Dmitry Osipenko
2020-05-15 10:03   ` Steve McIntyre
2020-05-15 10:03     ` Steve McIntyre
     [not found]     ` <20200515100320.GB30674-RWaXQMOneMVkKwkEErXb8g@public.gmane.org>
2020-05-15 15:52       ` Dmitry Osipenko
2020-05-15 15:52         ` Dmitry Osipenko
2020-05-15  1:41 ` [PATCH v4 5/6] partitions/tegra: Support gpt_sector= command line option Dmitry Osipenko
2020-05-15  1:41 ` [PATCH v4 6/6] soc/tegra: Expose Boot Configuration Table via sysfs Dmitry Osipenko

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.