Skip to content

Commit

Permalink
part_efi: support padding between the GPT header and partition entries
Browse files Browse the repository at this point in the history
Some architectures require their SPL loader at a fixed address within
the first 16KB of the disk. To avoid an overlap with the partition
entries of the EFI partition table, the first safe offset (in bytes,
from the start of the device) for the entries can be set through
CONFIG_EFI_PARTITION_ENTRIES_OFF (via Kconfig)

When formatting a device with an EFI partition table, we may need to
leave a gap between the GPT header (always in LBA 1) and the partition
entries. The GPT header already contains a field to specify the
on-disk location, which has so far always been set to LBA 2. With this
change, a configurable offset will be translated into a LBA address
indicating where to put the entries.

Now also allows an override via device-tree using a config-node (see
doc/device-tree-bindings/config.txt for documentation).

Tested (exporting an internal MMC formatted with this) against Linux,
MacOS X and Windows.

Signed-off-by: Philipp Tomsich <[email protected]>
Reviewed-by: Simon Glass <[email protected]>
[trini: __maybe_unused on config_offset to avoid warning]
Signed-off-by: Tom Rini <[email protected]>
  • Loading branch information
Philipp Tomsich authored and trini committed Mar 20, 2017
1 parent ee6fdfa commit 02e4353
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 4 deletions.
13 changes: 13 additions & 0 deletions disk/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,19 @@ config EFI_PARTITION
common when EFI is the bootloader. Note 2TB partition limit;
see disk/part_efi.c

config EFI_PARTITION_ENTRIES_OFF
int "Offset (in bytes) of the EFI partition entries"
depends on EFI_PARTITION
default 0
help
Specify an earliest location (in bytes) where the partition
entries may be located. This is meant to allow "punching a
hole into a device" to create a gap for an SPL, its payload
and the U-Boot environment.

If unsure, leave at 0 (which will locate the partition
entries at the first possible LBA following the GPT header).

config SPL_EFI_PARTITION
bool "Enable EFI GPT partition table for SPL"
depends on SPL && PARTITIONS
Expand Down
55 changes: 51 additions & 4 deletions disk/part_efi.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@
#include <asm/unaligned.h>
#include <common.h>
#include <command.h>
#include <fdtdec.h>
#include <ide.h>
#include <inttypes.h>
#include <malloc.h>
#include <memalign.h>
#include <part_efi.h>
#include <linux/compiler.h>
#include <linux/ctype.h>

DECLARE_GLOBAL_DATA_PTR;
Expand Down Expand Up @@ -373,8 +375,8 @@ int write_gpt_table(struct blk_desc *dev_desc,
if (blk_dwrite(dev_desc, 1, 1, gpt_h) != 1)
goto err;

if (blk_dwrite(dev_desc, 2, pte_blk_cnt, gpt_e)
!= pte_blk_cnt)
if (blk_dwrite(dev_desc, le64_to_cpu(gpt_h->partition_entry_lba),
pte_blk_cnt, gpt_e) != pte_blk_cnt)
goto err;

prepare_backup_gpt_header(gpt_h);
Expand Down Expand Up @@ -498,6 +500,49 @@ int gpt_fill_pte(gpt_header *gpt_h, gpt_entry *gpt_e,
return 0;
}

static uint32_t partition_entries_offset(struct blk_desc *dev_desc)
{
uint32_t offset_blks = 2;
int __maybe_unused config_offset;

#if defined(CONFIG_EFI_PARTITION_ENTRIES_OFF)
/*
* Some architectures require their SPL loader at a fixed
* address within the first 16KB of the disk. To avoid an
* overlap with the partition entries of the EFI partition
* table, the first safe offset (in bytes, from the start of
* the disk) for the entries can be set in
* CONFIG_EFI_PARTITION_ENTRIES_OFF.
*/
offset_blks =
PAD_TO_BLOCKSIZE(CONFIG_EFI_PARTITION_ENTRIES_OFF, dev_desc);
#endif

#if defined(CONFIG_OF_CONTROL)
/*
* Allow the offset of the first partition entires (in bytes
* from the start of the device) to be specified as a property
* of the device tree '/config' node.
*/
config_offset = fdtdec_get_config_int(gd->fdt_blob,
"u-boot,efi-partition-entries-offset",
-EINVAL);
if (config_offset != -EINVAL)
offset_blks = PAD_TO_BLOCKSIZE(config_offset, dev_desc);
#endif

debug("efi: partition entries offset (in blocks): %d\n", offset_blks);

/*
* The earliest LBA this can be at is LBA#2 (i.e. right behind
* the (protective) MBR and the GPT header.
*/
if (offset_blks < 2)
offset_blks = 2;

return offset_blks;
}

int gpt_fill_header(struct blk_desc *dev_desc, gpt_header *gpt_h,
char *str_guid, int parts_count)
{
Expand All @@ -506,9 +551,11 @@ int gpt_fill_header(struct blk_desc *dev_desc, gpt_header *gpt_h,
gpt_h->header_size = cpu_to_le32(sizeof(gpt_header));
gpt_h->my_lba = cpu_to_le64(1);
gpt_h->alternate_lba = cpu_to_le64(dev_desc->lba - 1);
gpt_h->first_usable_lba = cpu_to_le64(34);
gpt_h->last_usable_lba = cpu_to_le64(dev_desc->lba - 34);
gpt_h->partition_entry_lba = cpu_to_le64(2);
gpt_h->partition_entry_lba =
cpu_to_le64(partition_entries_offset(dev_desc));
gpt_h->first_usable_lba =
cpu_to_le64(le64_to_cpu(gpt_h->partition_entry_lba) + 32);
gpt_h->num_partition_entries = cpu_to_le32(GPT_ENTRY_NUMBERS);
gpt_h->sizeof_partition_entry = cpu_to_le32(sizeof(gpt_entry));
gpt_h->header_crc32 = 0;
Expand Down

0 comments on commit 02e4353

Please sign in to comment.