BINMAN
M: Simon Glass <sjg@chromium.org>
+M: Alper Nebi Yasak <alpernebiyasak@gmail.com>
S: Maintained
F: tools/binman/
config CMD_PART
bool "part"
+ depends on PARTITIONS
select HAVE_BLOCK_DEVICE
select PARTITION_UUIDS
help
* Set up memory image for the binary to be loaded, prepare device path, and
* then call do_bootefi_exec() to execute it.
*
- * @image_opt: string of image start address
+ * @image_opt: string with image start address
+ * @size_opt: string with image size or NULL
* Return: status code
*/
-static int do_bootefi_image(const char *image_opt)
+static int do_bootefi_image(const char *image_opt, const char *size_opt)
{
void *image_buf;
unsigned long addr, size;
/* Check that a numeric value was passed */
if (!addr)
return CMD_RET_USAGE;
-
image_buf = map_sysmem(addr, 0);
- if (image_buf != image_addr) {
- log_err("No UEFI binary known at %s\n", image_opt);
- return CMD_RET_FAILURE;
+ if (size_opt) {
+ size = strtoul(size_opt, NULL, 16);
+ if (!size)
+ return CMD_RET_USAGE;
+ efi_clear_bootdev();
+ } else {
+ if (image_buf != image_addr) {
+ log_err("No UEFI binary known at %s\n",
+ image_opt);
+ return CMD_RET_FAILURE;
+ }
+ size = image_size;
}
- size = image_size;
}
ret = efi_run_image(image_buf, size);
return CMD_RET_FAILURE;
}
- if (argc > 2) {
+ if (argc > 2 && strcmp(argv[2], "-")) {
uintptr_t fdt_addr;
fdt_addr = hextoul(argv[2], NULL);
return do_efi_selftest();
#endif
- return do_bootefi_image(argv[1]);
+ return do_bootefi_image(argv[1], argc > 3 ? argv[3] : NULL);
}
#ifdef CONFIG_SYS_LONGHELP
static char bootefi_help_text[] =
- "<image address> [fdt address]\n"
- " - boot EFI payload stored at address <image address>.\n"
- " If specified, the device tree located at <fdt address> gets\n"
- " exposed as EFI configuration table.\n"
+ "<image address> [fdt address [image size]]\n"
+ " - boot EFI payload stored at <image address>\n"
+ " fdt address, address of device-tree or '-'\n"
+ " image size, required if image not preloaded\n"
#ifdef CONFIG_CMD_BOOTEFI_HELLO
"bootefi hello\n"
" - boot a sample Hello World application stored within U-Boot\n"
#endif
U_BOOT_CMD(
- bootefi, 3, 0, do_bootefi,
+ bootefi, 4, 0, do_bootefi,
"Boots an EFI payload from memory",
bootefi_help_text
);
}
for (iter = bootmenu->first; iter; iter = iter->next) {
- if (!menu_item_add(menu, iter->key, iter))
+ if (menu_item_add(menu, iter->key, iter) != 1)
goto cleanup;
}
init = 1;
- if (menu_get_choice(menu, &choice)) {
+ if (menu_get_choice(menu, &choice) == 1) {
iter = choice;
title = strdup(iter->title);
command = strdup(iter->command);
initr_mem,
#endif
#ifdef CONFIG_EFI_SETUP_EARLY
- (init_fnc_t)efi_init_obj_list,
+ efi_init_early,
#endif
run_main_loop,
};
if (IS_ENABLED(CONFIG_UPDATE_TFTP))
update_tftp(0UL, NULL, NULL);
- if (IS_ENABLED(CONFIG_EFI_CAPSULE_ON_DISK_EARLY))
- efi_launch_capsules();
+ if (IS_ENABLED(CONFIG_EFI_CAPSULE_ON_DISK_EARLY)) {
+ /* efi_init_early() already called */
+ if (efi_init_obj_list() == EFI_SUCCESS)
+ efi_launch_capsules();
+ }
s = bootdelay_process();
if (cli_process_fdt(&s))
CONFIG_SYS_PROMPT="G3#"
CONFIG_CMD_I2C=y
CONFIG_CMD_MMC=y
-CONFIG_CMD_PART=y
CONFIG_CMD_WDT=y
CONFIG_BOOTP_BOOTFILESIZE=y
CONFIG_CMD_CACHE=y
menu "Partition Types"
config PARTITIONS
- bool "Enable Partition Labels (disklabels) support"
- default y
+ bool
help
Partition Labels (disklabels) Supported:
Zero or more of the following:
as well.
config SPL_PARTITIONS
- bool "Enable Partition Labels (disklabels) support in SPL"
- default y if PARTITIONS
+ bool
select SPL_SPRINTF
select SPL_STRTO
help
small amount of size to SPL, typically 500 bytes.
config TPL_PARTITIONS
- bool "Enable Partition Labels (disklabels) support in TPL"
- default y if PARTITIONS
+ bool
select TPL_SPRINTF
select TPL_STRTO
help
config MAC_PARTITION
bool "Enable Apple's MacOS partition table"
- depends on PARTITIONS
+ select PARTITIONS
help
Say Y here if you would like to use device under U-Boot which
were partitioned on a Macintosh.
config SPL_MAC_PARTITION
bool "Enable Apple's MacOS partition table for SPL"
- depends on SPL && PARTITIONS
+ depends on SPL
default y if MAC_PARTITION
+ select SPL_PARTITIONS
config DOS_PARTITION
bool "Enable MS Dos partition table"
- depends on PARTITIONS
default y if DISTRO_DEFAULTS
default y if x86 || CMD_FAT || USB_STORAGE
+ select PARTITIONS
help
traditional on the Intel architecture, USB sticks, etc.
config SPL_DOS_PARTITION
bool "Enable MS Dos partition table for SPL"
- depends on SPL && PARTITIONS
+ depends on SPL
default n if ARCH_SUNXI
default y if DOS_PARTITION
+ select SPL_PARTITIONS
config ISO_PARTITION
bool "Enable ISO partition table"
- depends on PARTITIONS
default y if DISTRO_DEFAULTS
default y if MIPS || ARCH_TEGRA
+ select PARTITIONS
config SPL_ISO_PARTITION
bool "Enable ISO partition table for SPL"
- depends on SPL && PARTITIONS
+ depends on SPL
+ select SPL_PARTITIONS
config AMIGA_PARTITION
bool "Enable AMIGA partition table"
- depends on PARTITIONS
+ select PARTITIONS
help
Say Y here if you would like to use device under U-Boot which
were partitioned under AmigaOS.
config SPL_AMIGA_PARTITION
bool "Enable AMIGA partition table for SPL"
- depends on SPL && PARTITIONS
+ depends on SPL
default y if AMIGA_PARTITION
+ select SPL_PARTITIONS
config EFI_PARTITION
bool "Enable EFI GPT partition table"
- depends on PARTITIONS
default y if DISTRO_DEFAULTS
default y if ARCH_TEGRA
+ select PARTITIONS
select LIB_UUID
help
Say Y here if you would like to use device under U-Boot which
config SPL_EFI_PARTITION
bool "Enable EFI GPT partition table for SPL"
- depends on SPL && PARTITIONS
+ depends on SPL
default n if ARCH_SUNXI
default y if EFI_PARTITION
+ select SPL_PARTITIONS
config PARTITION_UUIDS
bool "Enable support of UUID for partition"
config SPL_PARTITION_UUIDS
bool "Enable support of UUID for partition in SPL"
- depends on SPL && PARTITIONS
+ depends on SPL_PARTITIONS
default y if SPL_EFI_PARTITION
config PARTITION_TYPE_GUID
bool "Enable support of GUID for partition type"
- depends on PARTITIONS
depends on EFI_PARTITION
help
Activate the configuration of GUID type
#ccflags-y += -DET_DEBUG -DDEBUG
obj-$(CONFIG_$(SPL_TPL_)PARTITIONS) += part.o
+ifdef CONFIG_$(SPL_TPL_)BLK
+obj-$(CONFIG_$(SPL_TPL_)PARTITIONS) += disk-uclass.o
+endif
obj-$(CONFIG_$(SPL_TPL_)MAC_PARTITION) += part_mac.o
obj-$(CONFIG_$(SPL_TPL_)DOS_PARTITION) += part_dos.o
obj-$(CONFIG_$(SPL_TPL_)ISO_PARTITION) += part_iso.o
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Software partition device (UCLASS_PARTITION)
+ *
+ * Copyright (c) 2021 Linaro Limited
+ * Author: AKASHI Takahiro
+ */
+
+#define LOG_CATEGORY UCLASS_PARTITION
+
+#include <blk.h>
+#include <dm.h>
+#include <log.h>
+#include <part.h>
+#include <vsprintf.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+
+int part_create_block_devices(struct udevice *blk_dev)
+{
+ int part, count;
+ struct blk_desc *desc = dev_get_uclass_plat(blk_dev);
+ struct disk_partition info;
+ struct disk_part *part_data;
+ char devname[32];
+ struct udevice *dev;
+ int ret;
+
+ if (!CONFIG_IS_ENABLED(PARTITIONS) ||
+ !CONFIG_IS_ENABLED(HAVE_BLOCK_DEVICE))
+ return 0;
+
+ if (device_get_uclass_id(blk_dev) != UCLASS_BLK)
+ return 0;
+
+ /* Add devices for each partition */
+ for (count = 0, part = 1; part <= MAX_SEARCH_PARTITIONS; part++) {
+ if (part_get_info(desc, part, &info))
+ continue;
+ snprintf(devname, sizeof(devname), "%s:%d", blk_dev->name,
+ part);
+
+ ret = device_bind_driver(blk_dev, "blk_partition",
+ strdup(devname), &dev);
+ if (ret)
+ return ret;
+
+ part_data = dev_get_uclass_plat(dev);
+ part_data->partnum = part;
+ part_data->gpt_part_info = info;
+ count++;
+
+ ret = device_probe(dev);
+ if (ret) {
+ debug("Can't probe\n");
+ count--;
+ device_unbind(dev);
+
+ continue;
+ }
+ }
+ debug("%s: %d partitions found in %s\n", __func__, count,
+ blk_dev->name);
+
+ return 0;
+}
+
+static ulong blk_part_read(struct udevice *dev, lbaint_t start,
+ lbaint_t blkcnt, void *buffer)
+{
+ struct udevice *parent;
+ struct disk_part *part;
+ const struct blk_ops *ops;
+
+ parent = dev_get_parent(dev);
+ ops = blk_get_ops(parent);
+ if (!ops->read)
+ return -ENOSYS;
+
+ part = dev_get_uclass_plat(dev);
+ if (start >= part->gpt_part_info.size)
+ return 0;
+
+ if ((start + blkcnt) > part->gpt_part_info.size)
+ blkcnt = part->gpt_part_info.size - start;
+ start += part->gpt_part_info.start;
+
+ return ops->read(parent, start, blkcnt, buffer);
+}
+
+static ulong blk_part_write(struct udevice *dev, lbaint_t start,
+ lbaint_t blkcnt, const void *buffer)
+{
+ struct udevice *parent;
+ struct disk_part *part;
+ const struct blk_ops *ops;
+
+ parent = dev_get_parent(dev);
+ ops = blk_get_ops(parent);
+ if (!ops->write)
+ return -ENOSYS;
+
+ part = dev_get_uclass_plat(dev);
+ if (start >= part->gpt_part_info.size)
+ return 0;
+
+ if ((start + blkcnt) > part->gpt_part_info.size)
+ blkcnt = part->gpt_part_info.size - start;
+ start += part->gpt_part_info.start;
+
+ return ops->write(parent, start, blkcnt, buffer);
+}
+
+static ulong blk_part_erase(struct udevice *dev, lbaint_t start,
+ lbaint_t blkcnt)
+{
+ struct udevice *parent;
+ struct disk_part *part;
+ const struct blk_ops *ops;
+
+ parent = dev_get_parent(dev);
+ ops = blk_get_ops(parent);
+ if (!ops->erase)
+ return -ENOSYS;
+
+ part = dev_get_uclass_plat(dev);
+ if (start >= part->gpt_part_info.size)
+ return 0;
+
+ if ((start + blkcnt) > part->gpt_part_info.size)
+ blkcnt = part->gpt_part_info.size - start;
+ start += part->gpt_part_info.start;
+
+ return ops->erase(parent, start, blkcnt);
+}
+
+static const struct blk_ops blk_part_ops = {
+ .read = blk_part_read,
+ .write = blk_part_write,
+ .erase = blk_part_erase,
+};
+
+U_BOOT_DRIVER(blk_partition) = {
+ .name = "blk_partition",
+ .id = UCLASS_PARTITION,
+ .ops = &blk_part_ops,
+};
+
+/*
+ * BLOCK IO APIs
+ */
+static struct blk_desc *dev_get_blk(struct udevice *dev)
+{
+ struct blk_desc *block_dev;
+
+ switch (device_get_uclass_id(dev)) {
+ /*
+ * We won't support UCLASS_BLK with dev_* interfaces.
+ */
+ case UCLASS_PARTITION:
+ block_dev = dev_get_uclass_plat(dev_get_parent(dev));
+ break;
+ default:
+ block_dev = NULL;
+ break;
+ }
+
+ return block_dev;
+}
+
+unsigned long dev_read(struct udevice *dev, lbaint_t start,
+ lbaint_t blkcnt, void *buffer)
+{
+ struct blk_desc *block_dev;
+ const struct blk_ops *ops;
+ struct disk_part *part;
+ lbaint_t start_in_disk;
+ ulong blks_read;
+
+ block_dev = dev_get_blk(dev);
+ if (!block_dev)
+ return -ENOSYS;
+
+ ops = blk_get_ops(dev);
+ if (!ops->read)
+ return -ENOSYS;
+
+ start_in_disk = start;
+ if (device_get_uclass_id(dev) == UCLASS_PARTITION) {
+ part = dev_get_uclass_plat(dev);
+ start_in_disk += part->gpt_part_info.start;
+ }
+
+ if (blkcache_read(block_dev->if_type, block_dev->devnum,
+ start_in_disk, blkcnt, block_dev->blksz, buffer))
+ return blkcnt;
+ blks_read = ops->read(dev, start, blkcnt, buffer);
+ if (blks_read == blkcnt)
+ blkcache_fill(block_dev->if_type, block_dev->devnum,
+ start_in_disk, blkcnt, block_dev->blksz, buffer);
+
+ return blks_read;
+}
+
+unsigned long dev_write(struct udevice *dev, lbaint_t start,
+ lbaint_t blkcnt, const void *buffer)
+{
+ struct blk_desc *block_dev;
+ const struct blk_ops *ops;
+
+ block_dev = dev_get_blk(dev);
+ if (!block_dev)
+ return -ENOSYS;
+
+ ops = blk_get_ops(dev);
+ if (!ops->write)
+ return -ENOSYS;
+
+ blkcache_invalidate(block_dev->if_type, block_dev->devnum);
+
+ return ops->write(dev, start, blkcnt, buffer);
+}
+
+unsigned long dev_erase(struct udevice *dev, lbaint_t start,
+ lbaint_t blkcnt)
+{
+ struct blk_desc *block_dev;
+ const struct blk_ops *ops;
+
+ block_dev = dev_get_blk(dev);
+ if (!block_dev)
+ return -ENOSYS;
+
+ ops = blk_get_ops(dev);
+ if (!ops->erase)
+ return -ENOSYS;
+
+ blkcache_invalidate(block_dev->if_type, block_dev->devnum);
+
+ return ops->erase(dev, start, blkcnt);
+}
+
+UCLASS_DRIVER(partition) = {
+ .id = UCLASS_PARTITION,
+ .per_device_plat_auto = sizeof(struct disk_part),
+ .name = "partition",
+};
- Apple M1 SoC (t8103)
- Apple M1 Pro SoC (t6000)
- Apple M1 Max SoC (t6001)
+ - Apple M1 Ultra SoC (t6002)
On these SoCs the following hardware is supported:
- Base Address
* - M1 (t8103)
- 0x235200000
- * - M1 Pro/Max (t6000/t6001)
+ * - M1 Pro/Max/Ultra (t6000/t6001/t6002)
- 0x39b200000
what the bottlenecks are.
+Tag Support
+-----------
+
+It is sometimes useful for a subsystem to associate its own private
+data (or object) to a DM device, i.e. struct udevice, to support
+additional features.
+
+Tag support in driver model will give us the ability to do so dynamically
+instead of modifying "udevice" data structure. In the initial release, we
+will support two type of attributes:
+
+- a pointer with dm_tag_set_ptr(), and
+- an unsigned long with dm_tag_set_val()
+
+For example, UEFI subsystem utilizes the feature to maintain efi_disk
+objects depending on linked udevice's lifecycle.
+
+While the current implementation is quite simple, it will get evolved
+as the feature is more extensively used in U-Boot subsystems.
+
+
Changes since v1
----------------
fine. To workaround this BootROM bug with standard output, it is possible
to manually overwrite BootROM variables stored in SRAM which BootROM use
for checking if standard output is enabled or not. To enable BootROM
-standard output on UART, type this command folled by ENTER key:
+standard output on UART, type this command followed by ENTER key:
.RS 1.2i
.TP
::
- bootefi [image_addr] [fdt_addr]
+ bootefi [image_addr] [fdt_addr [image_size]]
bootefi bootmgr [fdt_addr]
bootefi hello [fdt_addr]
bootefi selftest [fdt_addr]
load mmc 0:1 $kernel_addr_r /EFI/grub/grubaa64.efi
bootefi $kernel_addr_r $fdt_addr_r
-The last file loaded defines the image file path in the loaded image protocol.
-Hence the executable should always be loaded last.
+The last UEFI binary loaded defines the image file path in the loaded image
+protocol.
The value of the environment variable *bootargs* is converted from UTF-8 to
UTF-16 and passed as load options in the loaded image protocol to the UEFI
binary.
+image_addr
+ Address of the UEFI binary.
+
+fdt_addr
+ Address of the device-tree or '-'. If no address is specifiy, the
+ environment variable $fdt_addr is used as first fallback, the address of
+ U-Boot's internal device-tree $fdtcontroladdr as second fallback.
+ When using ACPI no device-tree shall be specified.
+
+image_size
+ Size of the UEFI binary file. This argument is only needed if *image_addr*
+ does not match the address of the last loaded UEFI binary. In this case
+ a memory device path will be used as image file path in the loaded image
+ protocol.
+
Note
UEFI binaries that are contained in FIT images are launched via the
*bootm* command.
struct blk_desc *desc = dev_get_uclass_plat(dev);
part_init(desc);
+
+ if (desc->part_type != PART_TYPE_UNKNOWN &&
+ part_create_block_devices(dev))
+ debug("*** creating partitions failed\n");
}
return 0;
node = calloc(sizeof(*node), 1);
if (!node)
- return -ENOSPC;
+ return -ENOMEM;
node->dev = dev;
node->tag = tag;
node = calloc(sizeof(*node), 1);
if (!node)
- return -ENOSPC;
+ return -ENOMEM;
node->dev = dev;
node->tag = tag;
UCLASS_P2SB, /* (x86) Primary-to-Sideband Bus */
UCLASS_PANEL, /* Display panel, such as an LCD */
UCLASS_PANEL_BACKLIGHT, /* Backlight controller for panel */
+ UCLASS_PARTITION, /* Logical disk partition device */
UCLASS_PCH, /* x86 platform controller hub */
UCLASS_PCI, /* PCI bus */
UCLASS_PCI_EP, /* PCI endpoint device */
/* List of all events registered by RegisterProtocolNotify() */
extern struct list_head efi_register_notify_events;
+/* called at pre-initialization */
+int efi_init_early(void);
/* Initialize efi execution environment */
efi_status_t efi_init_obj_list(void);
/* Install device tree */
void efi_try_purge_kaslr_seed(void *fdt);
/* Called by bootefi to make console interface available */
efi_status_t efi_console_register(void);
-/* Called by bootefi to make all disk storage accessible as EFI objects */
-efi_status_t efi_disk_register(void);
+/* Called by efi_init_obj_list() to initialize efi_disks */
+efi_status_t efi_disk_init(void);
/* Called by efi_init_obj_list() to install EFI_RNG_PROTOCOL */
efi_status_t efi_rng_register(void);
/* Called by efi_init_obj_list() to install EFI_TCG2_PROTOCOL */
#include <ide.h>
#include <uuid.h>
#include <linker_lists.h>
+#include <linux/errno.h>
#include <linux/list.h>
struct block_drvr {
};
/* Misc _get_dev functions */
-#ifdef CONFIG_PARTITIONS
+#if CONFIG_IS_ENABLED(PARTITIONS)
/**
* blk_get_dev() - get a pointer to a block device given its type and number
*
struct blk_desc *blk_get_dev(const char *ifname, int dev);
struct blk_desc *mg_disk_get_dev(int dev);
-int host_get_dev_err(int dev, struct blk_desc **blk_devp);
/* disk/part.c */
int part_get_info(struct blk_desc *dev_desc, int part,
struct disk_partition *info,
int allow_whole_dev)
{ *dev_desc = NULL; return -1; }
+
+static inline int part_get_info_by_name_type(struct blk_desc *dev_desc,
+ const char *name,
+ struct disk_partition *info,
+ int part_type)
+{
+ return -ENOENT;
+}
+
+static inline int part_get_info_by_name(struct blk_desc *dev_desc,
+ const char *name,
+ struct disk_partition *info)
+{
+ return -ENOENT;
+}
+
static inline int
part_get_info_by_dev_and_name_or_num(const char *dev_iface,
const char *dev_part_str,
}
#endif
+struct udevice;
+/**
+ * part_create_block_devices - Create block devices for disk partitions
+ *
+ * Create UCLASS_PARTITION udevices for each of disk partitions in @parent
+ *
+ * @blk_dev: Whole disk device
+ */
+int part_create_block_devices(struct udevice *blk_dev);
+
+unsigned long dev_read(struct udevice *dev, lbaint_t start,
+ lbaint_t blkcnt, void *buffer);
+unsigned long dev_write(struct udevice *dev, lbaint_t start,
+ lbaint_t blkcnt, const void *buffer);
+unsigned long dev_erase(struct udevice *dev, lbaint_t start,
+ lbaint_t blkcnt);
+
/*
* We don't support printing partition information in SPL and only support
* getting partition information in a few cases.
#endif
-#ifdef CONFIG_PARTITIONS
+#if CONFIG_IS_ENABLED(PARTITIONS)
/**
* part_driver_get_count() - get partition driver count
*
*/
int host_dev_bind(int dev, char *filename, bool removable);
+int host_get_dev_err(int dev, struct blk_desc **blk_devp);
+
#endif
#include <malloc.h>
#include <dm/device-internal.h>
#include <dm/root.h>
+#include <dm/tag.h>
/*
* EFI attributes of the udevice handled by this driver.
}
/**
- * Create partions for the block device.
- *
- * @handle: EFI handle of the block device
- * @dev: udevice of the block device
- * Return: number of partitions created
- */
-static int efi_bl_bind_partitions(efi_handle_t handle, struct udevice *dev)
-{
- struct blk_desc *desc;
- const char *if_typename;
-
- desc = dev_get_uclass_plat(dev);
- if_typename = blk_get_if_type_name(desc->if_type);
-
- return efi_disk_create_partitions(handle, desc, if_typename,
- desc->devnum, dev->name);
-}
-
-/**
* Create a block device for a handle
*
* @handle: handle
char *name;
struct efi_object *obj = efi_search_obj(handle);
struct efi_block_io *io = interface;
- int disks;
struct efi_blk_plat *plat;
EFI_PRINT("%s: handle %p, interface %p\n", __func__, handle, io);
plat->handle = handle;
plat->io = interface;
+ /*
+ * FIXME: necessary because we won't do almost nothing in
+ * efi_disk_create() when called from device_probe().
+ */
+ ret = dev_tag_set_ptr(bdev, DM_TAG_EFI, handle);
+ if (ret)
+ /* FIXME: cleanup for bdev */
+ return ret;
+
ret = device_probe(bdev);
if (ret)
return ret;
EFI_PRINT("%s: block device '%s' created\n", __func__, bdev->name);
- /* Create handles for the partions of the block device */
- disks = efi_bl_bind_partitions(handle, bdev);
- EFI_PRINT("Found %d partitions\n", disks);
-
return 0;
}
depends on DM_ETH || !NET
depends on !EFI_APP
default y if !ARM || SYS_CPU = armv7 || SYS_CPU = armv8
+ select DM_EVENT
+ select EVENT_DYNAMIC
select LIB_UUID
- select PARTITION_UUIDS
+ imply PARTITION_UUIDS
select HAVE_BLOCK_DEVICE
select REGEX
imply FAT
config EFI_SETUP_EARLY
bool
+ default y
choice
prompt "Store for non-volatile UEFI variables"
obj-$(CONFIG_EFI_ESRT) += efi_esrt.o
obj-$(CONFIG_LCD) += efi_gop.o
obj-$(CONFIG_DM_VIDEO) += efi_gop.o
-obj-$(CONFIG_PARTITIONS) += efi_disk.o
+obj-$(CONFIG_BLK) += efi_disk.o
obj-$(CONFIG_NET) += efi_net.o
obj-$(CONFIG_GENERATE_ACPI_TABLE) += efi_acpi.o
obj-$(CONFIG_GENERATE_SMBIOS_TABLE) += efi_smbios.o
break;
case SIG_TYPE_GUID:
hddp->signature_type = 2;
+#if CONFIG_IS_ENABLED(PARTITION_UUIDS)
+ /* info.uuid exists only with PARTITION_UUIDS */
if (uuid_str_to_bin(info.uuid,
- hddp->partition_signature, 1))
+ hddp->partition_signature,
+ UUID_STR_FORMAT_GUID)) {
log_warning(
- "Partition no. %d: invalid guid: %s\n",
+ "Partition %d: invalid GUID %s\n",
part, info.uuid);
+ }
+#endif
break;
}
#include <common.h>
#include <blk.h>
#include <dm.h>
+#include <dm/device-internal.h>
+#include <dm/tag.h>
+#include <event.h>
#include <efi_loader.h>
#include <fs.h>
#include <log.h>
* @part: partition
* @volume: simple file system protocol of the partition
* @offset: offset into disk for simple partition
- * @desc: internal block device descriptor
+ * @dev: associated DM device
*/
struct efi_disk_obj {
struct efi_object header;
unsigned int part;
struct efi_simple_file_system_protocol *volume;
lbaint_t offset;
- struct blk_desc *desc;
+ struct udevice *dev; /* TODO: move it to efi_object */
};
/**
void *buffer, enum efi_disk_direction direction)
{
struct efi_disk_obj *diskobj;
- struct blk_desc *desc;
int blksz;
int blocks;
unsigned long n;
diskobj = container_of(this, struct efi_disk_obj, ops);
- desc = (struct blk_desc *) diskobj->desc;
- blksz = desc->blksz;
+ blksz = diskobj->media.block_size;
blocks = buffer_size / blksz;
lba += diskobj->offset;
if (buffer_size & (blksz - 1))
return EFI_BAD_BUFFER_SIZE;
+#if CONFIG_IS_ENABLED(PARTITIONS)
+ if (direction == EFI_DISK_READ)
+ n = dev_read(diskobj->dev, lba, blocks, buffer);
+ else
+ n = dev_write(diskobj->dev, lba, blocks, buffer);
+#else
+ /* dev is always a block device (UCLASS_BLK) */
+ struct blk_desc *desc;
+
+ desc = dev_get_uclass_plat(diskobj->dev);
if (direction == EFI_DISK_READ)
n = blk_dread(desc, lba, blocks, buffer);
else
n = blk_dwrite(desc, lba, blocks, buffer);
+#endif
/* We don't do interrupts, so check for timers cooperatively */
efi_timer_check();
diskobj->ops = block_io_disk_template;
diskobj->ifname = if_typename;
diskobj->dev_index = dev_index;
- diskobj->desc = desc;
/* Fill in EFI IO Media info (for read/write callbacks) */
diskobj->media.removable_media = desc->removable;
return ret;
}
-/**
- * efi_disk_create_partitions() - create handles and protocols for partitions
+/*
+ * Create a handle for a whole raw disk
+ *
+ * @dev uclass device (UCLASS_BLK)
*
- * Create handles and protocols for the partitions of a block device.
+ * Create an efi_disk object which is associated with @dev.
+ * The type of @dev must be UCLASS_BLK.
*
- * @parent: handle of the parent disk
- * @desc: block device
- * @if_typename: interface type
- * @diskid: device number
- * @pdevname: device name
- * Return: number of partitions created
+ * @return 0 on success, -1 otherwise
*/
-int efi_disk_create_partitions(efi_handle_t parent, struct blk_desc *desc,
- const char *if_typename, int diskid,
- const char *pdevname)
+static int efi_disk_create_raw(struct udevice *dev)
{
- int disks = 0;
- char devname[32] = { 0 }; /* dp->str is u16[32] long */
- int part;
- struct efi_device_path *dp = NULL;
+ struct efi_disk_obj *disk;
+ struct blk_desc *desc;
+ const char *if_typename;
+ int diskid;
efi_status_t ret;
+
+ desc = dev_get_uclass_plat(dev);
+ if_typename = blk_get_if_type_name(desc->if_type);
+ diskid = desc->devnum;
+
+ ret = efi_disk_add_dev(NULL, NULL, if_typename, desc,
+ diskid, NULL, 0, &disk);
+ if (ret != EFI_SUCCESS) {
+ if (ret == EFI_NOT_READY)
+ log_notice("Disk %s not ready\n", dev->name);
+ else
+ log_err("Adding disk for %s failed\n", dev->name);
+
+ return -1;
+ }
+ disk->dev = dev;
+ if (dev_tag_set_ptr(dev, DM_TAG_EFI, &disk->header)) {
+ efi_free_pool(disk->dp);
+ efi_delete_handle(&disk->header);
+
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Create a handle for a disk partition
+ *
+ * @dev uclass device (UCLASS_PARTITION)
+ *
+ * Create an efi_disk object which is associated with @dev.
+ * The type of @dev must be UCLASS_PARTITION.
+ *
+ * @return 0 on success, -1 otherwise
+ */
+static int efi_disk_create_part(struct udevice *dev)
+{
+ efi_handle_t parent;
+ struct blk_desc *desc;
+ const char *if_typename;
+ struct disk_part *part_data;
+ struct disk_partition *info;
+ unsigned int part;
+ int diskid;
struct efi_handler *handler;
+ struct efi_device_path *dp_parent;
+ struct efi_disk_obj *disk;
+ efi_status_t ret;
+
+ if (dev_tag_get_ptr(dev_get_parent(dev), DM_TAG_EFI, (void **)&parent))
+ return -1;
+
+ desc = dev_get_uclass_plat(dev_get_parent(dev));
+ if_typename = blk_get_if_type_name(desc->if_type);
+ diskid = desc->devnum;
+
+ part_data = dev_get_uclass_plat(dev);
+ part = part_data->partnum;
+ info = &part_data->gpt_part_info;
- /* Get the device path of the parent */
ret = efi_search_protocol(parent, &efi_guid_device_path, &handler);
- if (ret == EFI_SUCCESS)
- dp = handler->protocol_interface;
-
- /* Add devices for each partition */
- for (part = 1; part <= MAX_SEARCH_PARTITIONS; part++) {
- struct disk_partition info;
-
- if (part_get_info(desc, part, &info))
- continue;
- snprintf(devname, sizeof(devname), "%s:%x", pdevname,
- part);
- ret = efi_disk_add_dev(parent, dp, if_typename, desc, diskid,
- &info, part, NULL);
- if (ret != EFI_SUCCESS) {
- log_err("Adding partition %s failed\n", pdevname);
- continue;
- }
- disks++;
+ if (ret != EFI_SUCCESS)
+ return -1;
+ dp_parent = (struct efi_device_path *)handler->protocol_interface;
+
+ ret = efi_disk_add_dev(parent, dp_parent, if_typename, desc, diskid,
+ info, part, &disk);
+ if (ret != EFI_SUCCESS) {
+ log_err("Adding partition for %s failed\n", dev->name);
+ return -1;
+ }
+ disk->dev = dev;
+ if (dev_tag_set_ptr(dev, DM_TAG_EFI, &disk->header)) {
+ efi_free_pool(disk->dp);
+ efi_delete_handle(&disk->header);
+
+ return -1;
}
- return disks;
+ return 0;
}
-/**
- * efi_disk_register() - register block devices
+/*
+ * Create efi_disk objects for a block device
*
- * U-Boot doesn't have a list of all online disk devices. So when running our
- * EFI payload, we scan through all of the potentially available ones and
- * store them in our object pool.
+ * @dev uclass device (UCLASS_BLK)
*
- * This function is called in efi_init_obj_list().
+ * Create efi_disk objects for partitions as well as a raw disk
+ * which is associated with @dev.
+ * The type of @dev must be UCLASS_BLK.
+ * This function is expected to be called at EV_PM_POST_PROBE.
*
- * TODO(sjg@chromium.org): Actually with CONFIG_BLK, U-Boot does have this.
- * Consider converting the code to look up devices as needed. The EFI device
- * could be a child of the UCLASS_BLK block device, perhaps.
+ * @return 0 on success, -1 otherwise
+ */
+static int efi_disk_probe(void *ctx, struct event *event)
+{
+ struct udevice *dev;
+ enum uclass_id id;
+ struct blk_desc *desc;
+ struct udevice *child;
+ int ret;
+
+ dev = event->data.dm.dev;
+ id = device_get_uclass_id(dev);
+
+ /* TODO: We won't support partitions in a partition */
+ if (id != UCLASS_BLK)
+ return 0;
+
+ /*
+ * avoid creating duplicated objects now that efi_driver
+ * has already created an efi_disk at this moment.
+ */
+ desc = dev_get_uclass_plat(dev);
+ if (desc->if_type != IF_TYPE_EFI_LOADER) {
+ ret = efi_disk_create_raw(dev);
+ if (ret)
+ return -1;
+ }
+
+ device_foreach_child(child, dev) {
+ ret = efi_disk_create_part(child);
+ if (ret)
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Delete an efi_disk object for a whole raw disk
*
- * Return: status code
+ * @dev uclass device (UCLASS_BLK)
+ *
+ * Delete an efi_disk object which is associated with @dev.
+ * The type of @dev must be UCLASS_BLK.
+ *
+ * @return 0 on success, -1 otherwise
*/
-efi_status_t efi_disk_register(void)
+static int efi_disk_delete_raw(struct udevice *dev)
{
- struct efi_disk_obj *disk;
- int disks = 0;
- efi_status_t ret;
+ efi_handle_t handle;
+ struct blk_desc *desc;
+ struct efi_disk_obj *diskobj;
+
+ if (dev_tag_get_ptr(dev, DM_TAG_EFI, (void **)&handle))
+ return -1;
+
+ desc = dev_get_uclass_plat(dev);
+ if (desc->if_type != IF_TYPE_EFI_LOADER) {
+ diskobj = container_of(handle, struct efi_disk_obj, header);
+ efi_free_pool(diskobj->dp);
+ }
+
+ efi_delete_handle(handle);
+ dev_tag_del(dev, DM_TAG_EFI);
+
+ return 0;
+}
+
+/*
+ * Delete an efi_disk object for a disk partition
+ *
+ * @dev uclass device (UCLASS_PARTITION)
+ *
+ * Delete an efi_disk object which is associated with @dev.
+ * The type of @dev must be UCLASS_PARTITION.
+ *
+ * @return 0 on success, -1 otherwise
+ */
+static int efi_disk_delete_part(struct udevice *dev)
+{
+ efi_handle_t handle;
+ struct efi_disk_obj *diskobj;
+
+ if (dev_tag_get_ptr(dev, DM_TAG_EFI, (void **)&handle))
+ return -1;
+
+ diskobj = container_of(handle, struct efi_disk_obj, header);
+
+ efi_free_pool(diskobj->dp);
+ efi_delete_handle(handle);
+ dev_tag_del(dev, DM_TAG_EFI);
+
+ return 0;
+}
+
+/*
+ * Delete an efi_disk object for a block device
+ *
+ * @dev uclass device (UCLASS_BLK or UCLASS_PARTITION)
+ *
+ * Delete an efi_disk object which is associated with @dev.
+ * The type of @dev must be either UCLASS_BLK or UCLASS_PARTITION.
+ * This function is expected to be called at EV_PM_PRE_REMOVE.
+ *
+ * @return 0 on success, -1 otherwise
+ */
+static int efi_disk_remove(void *ctx, struct event *event)
+{
+ enum uclass_id id;
struct udevice *dev;
- for (uclass_first_device_check(UCLASS_BLK, &dev); dev;
- uclass_next_device_check(&dev)) {
- struct blk_desc *desc = dev_get_uclass_plat(dev);
- const char *if_typename = blk_get_if_type_name(desc->if_type);
+ dev = event->data.dm.dev;
+ id = device_get_uclass_id(dev);
- /* Add block device for the full device */
- log_info("Scanning disk %s...\n", dev->name);
- ret = efi_disk_add_dev(NULL, NULL, if_typename,
- desc, desc->devnum, NULL, 0, &disk);
- if (ret == EFI_NOT_READY) {
- log_notice("Disk %s not ready\n", dev->name);
- continue;
- }
- if (ret) {
- log_err("ERROR: failure to add disk device %s, r = %lu\n",
- dev->name, ret & ~EFI_ERROR_MASK);
- continue;
- }
- disks++;
+ if (id == UCLASS_BLK)
+ return efi_disk_delete_raw(dev);
+ else if (id == UCLASS_PARTITION)
+ return efi_disk_delete_part(dev);
+ else
+ return 0;
+}
+
+efi_status_t efi_disk_init(void)
+{
+ int ret;
- /* Partitions show up as block devices in EFI */
- disks += efi_disk_create_partitions(
- &disk->header, desc, if_typename,
- desc->devnum, dev->name);
+ ret = event_register("efi_disk add", EVT_DM_POST_PROBE,
+ efi_disk_probe, NULL);
+ if (ret) {
+ log_err("Event registration for efi_disk add failed\n");
+ return EFI_OUT_OF_RESOURCES;
}
- log_info("Found %d disks\n", disks);
+ ret = event_register("efi_disk del", EVT_DM_PRE_REMOVE,
+ efi_disk_remove, NULL);
+ if (ret) {
+ log_err("Event registration for efi_disk del failed\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
return EFI_SUCCESS;
}
&os_indications_supported, false);
}
-
/**
- * efi_init_obj_list() - Initialize and populate EFI object list
+ * __efi_init_early() - handle initialization at early stage
+ *
+ * This function is called in efi_init_obj_list() only if
+ * !CONFIG_EFI_SETUP_EARLY.
*
* Return: status code
*/
-efi_status_t efi_init_obj_list(void)
+static efi_status_t __efi_init_early(void)
{
efi_status_t ret = EFI_SUCCESS;
- /* Initialize once only */
- if (efi_obj_list_initialized != OBJ_LIST_NOT_INITIALIZED)
- return efi_obj_list_initialized;
-
/* Allow unaligned memory access */
allow_unaligned();
if (ret != EFI_SUCCESS)
goto out;
-#ifdef CONFIG_PARTITIONS
- ret = efi_disk_register();
- if (ret != EFI_SUCCESS)
- goto out;
-#endif
+ ret = efi_disk_init();
+out:
+ return ret;
+}
+
+/**
+ * efi_init_early() - handle initialization at early stage
+ *
+ * external version of __efi_init_early(); expected to be called in
+ * board_init_r().
+ *
+ * Return: status code
+ */
+int efi_init_early(void)
+{
+ efi_status_t ret;
+
+ ret = __efi_init_early();
+ if (ret != EFI_SUCCESS) {
+ /* never re-init UEFI subsystem */
+ efi_obj_list_initialized = ret;
+ return -1;
+ }
+ return 0;
+}
+
+/**
+ * efi_init_obj_list() - Initialize and populate EFI object list
+ *
+ * Return: status code
+ */
+efi_status_t efi_init_obj_list(void)
+{
+ efi_status_t ret = EFI_SUCCESS;
+
+ /* Initialize once only */
+ if (efi_obj_list_initialized != OBJ_LIST_NOT_INITIALIZED)
+ return efi_obj_list_initialized;
+
+ if (!IS_ENABLED(CONFIG_EFI_SETUP_EARLY)) {
+ ret = __efi_init_early();
+ if (ret != EFI_SUCCESS)
+ goto out;
+ }
+
if (IS_ENABLED(CONFIG_EFI_RNG_PROTOCOL)) {
ret = efi_rng_register();
if (ret != EFI_SUCCESS)
obj-$(CONFIG_RESET_SYSCON) += syscon-reset.o
obj-$(CONFIG_SYSINFO) += sysinfo.o
obj-$(CONFIG_SYSINFO_GPIO) += sysinfo-gpio.o
+obj-$(CONFIG_UT_DM) += tag.o
obj-$(CONFIG_TEE) += tee.o
obj-$(CONFIG_TIMER) += timer.o
obj-$(CONFIG_DM_USB) += usb.o
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * DM tag test
+ *
+ * Copyright (c) 2021 Linaro Limited
+ * Author: AKASHI Takahiro
+ */
+
+#include <common.h>
+#include <dm/tag.h>
+#include <dm/test.h> /* DM_TEST() */
+#include <test/test.h> /* struct unit_test_state */
+#include <test/ut.h> /* assertions */
+
+/*
+ * Test dm_tag_ptr() API
+ */
+static int dm_test_tag_ptr(struct unit_test_state *uts)
+{
+ ulong val;
+ void *ptr = NULL;
+
+ ut_assertok(dev_tag_set_ptr(uts->root, DM_TAG_EFI, &val));
+
+ ut_assertok(dev_tag_get_ptr(uts->root, DM_TAG_EFI, &ptr));
+
+ ut_asserteq_ptr(&val, ptr);
+
+ ut_assertok(dev_tag_del(uts->root, DM_TAG_EFI));
+
+ return 0;
+}
+
+DM_TEST(dm_test_tag_ptr, 0);
+
+/*
+ * Test dm_tag_val() API
+ */
+static int dm_test_tag_val(struct unit_test_state *uts)
+{
+ ulong val1 = 0x12345678, val2 = 0;
+
+ ut_assertok(dev_tag_set_val(uts->root, DM_TAG_EFI, val1));
+
+ ut_assertok(dev_tag_get_val(uts->root, DM_TAG_EFI, &val2));
+
+ ut_asserteq_64(val1, val2);
+
+ ut_assertok(dev_tag_del(uts->root, DM_TAG_EFI));
+
+ return 0;
+}
+
+DM_TEST(dm_test_tag_val, 0);
+
+/*
+ * Test against an invalid tag
+ */
+static int dm_test_tag_inval(struct unit_test_state *uts)
+{
+ ulong val;
+
+ ut_asserteq(-EINVAL, dev_tag_set_ptr(uts->root, DM_TAG_COUNT, &val));
+
+ return 0;
+}
+
+DM_TEST(dm_test_tag_inval, 0);
+
+/*
+ * Test dm_tag_del_all() AP:
+ */
+static int dm_test_tag_del_all(struct unit_test_state *uts)
+{
+ ulong val;
+
+ ut_assertok(dev_tag_set_ptr(uts->root, DM_TAG_EFI, &val));
+
+ ut_assertok(dev_tag_del_all(uts->root));
+
+ return 0;
+}
+
+DM_TEST(dm_test_tag_del_all, 0);
"""
state.PrepareFromLoadedData(image)
image.LoadData()
+ image.CollectBintools()
# If repacking, drop the old offset/size values except for the original
# ones, so we are only left with the constraints.
- if allow_resize:
+ if image.allow_repack and allow_resize:
image.ResetForPack()
node = self._node
while node.parent:
node = node.parent
- if node.name == 'binman':
+ if node.name in ('binman', '/'):
break
name = '%s.%s' % (node.name, name)
return name
error if not)
force-bad-datatype: Force a call to GetEntryArgsOrProps() with a bad
data type (generating an error)
+ require-bintool-for-contents: Raise an error if the specified
+ bintool isn't usable in ObtainContents()
+ require-bintool-for-pack: Raise an error if the specified
+ bintool isn't usable in Pack()
"""
def __init__(self, section, etype, node):
super().__init__(section, etype, node)
self.return_contents = True
self.contents = b'aa'
+ # Set to the required bintool when collecting bintools.
+ self.bintool_for_contents = None
+ self.require_bintool_for_contents = fdt_util.GetString(self._node,
+ 'require-bintool-for-contents')
+ if self.require_bintool_for_contents == '':
+ self.require_bintool_for_contents = '_testing'
+
+ self.bintool_for_pack = None
+ self.require_bintool_for_pack = fdt_util.GetString(self._node,
+ 'require-bintool-for-pack')
+ if self.require_bintool_for_pack == '':
+ self.require_bintool_for_pack = '_testing'
+
+ def Pack(self, offset):
+ """Figure out how to pack the entry into the section"""
+ if self.require_bintool_for_pack:
+ if self.bintool_for_pack is None:
+ self.Raise("Required bintool unusable in Pack()")
+ return super().Pack(offset)
+
def ObtainContents(self, fake_size=0):
if self.return_unknown_contents or not self.return_contents:
return False
self.contents_size = len(self.data)
if self.return_contents_once:
self.return_contents = False
+ if self.require_bintool_for_contents:
+ if self.bintool_for_contents is None:
+ self.Raise("Required bintool unusable in ObtainContents()")
return True
def GetOffsets(self):
if not self.never_complete_process_fdt:
self.process_fdt_ready = True
return ready
+
+ def AddBintools(self, btools):
+ """Add the bintools used by this entry type"""
+ if self.require_bintool_for_contents is not None:
+ self.bintool_for_contents = self.AddBintool(btools,
+ self.require_bintool_for_contents)
+ if self.require_bintool_for_pack is not None:
+ self.bintool_for_pack = self.AddBintool(btools,
+ self.require_bintool_for_pack)
# section entries for them here to merge the content subnodes
# together and put the merged contents in the subimage node's
# 'data' property later.
- entry = Entry.Create(self.section, node, etype='section')
+ entry = Entry.Create(self, node, etype='section')
entry.ReadNode()
# The hash subnodes here are for mkimage, not binman.
entry.SetUpdateHash(False)
- self._entries[rel_path] = entry
+ image_name = rel_path[len('/images/'):]
+ self._entries[image_name] = entry
for subnode in node.subnodes:
_add_entries(base_node, depth + 1, subnode)
has_images = depth == 2 and in_images
if has_images:
- entry = self._priv_entries[rel_path]
+ image_name = rel_path[len('/images/'):]
+ entry = self._priv_entries[image_name]
data = entry.GetData()
fsw.property('data', bytes(data))
# fsw.add_node() or _add_node() for it.
pass
elif self.GetImage().generate and subnode.name.startswith('@'):
- entry = self._priv_entries.get(subnode_path)
+ entry = self._priv_entries.get(subnode.name)
_gen_node(base_node, subnode, depth, in_images, entry)
# This is a generator (template) entry, so remove it from
# the list of entries used by PackEntries(), etc. Otherwise
# it will appear in the binman output
- to_remove.append(subnode_path)
+ to_remove.append(subnode.name)
else:
with fsw.add_node(subnode.name):
_add_node(base_node, depth + 1, subnode)
fdt = Fdt.FromData(self.GetData())
fdt.Scan()
- for path, section in self._entries.items():
+ for image_name, section in self._entries.items():
+ path = f"/images/{image_name}"
node = fdt.GetNode(path)
data_prop = node.props.get("data")
data = new_data
return data
+ def WriteData(self, data, decomp=True):
+ self.Raise("Replacing sections is not implemented yet")
+
def WriteChildData(self, child):
return True
self.assertEqual(len(kernel_data), int(data_sizes[0].split()[0]))
self.assertEqual(len(fdt1_data), int(data_sizes[1].split()[0]))
+ # Check if entry listing correctly omits /images/
+ image = control.images['image']
+ fit_entry = image.GetEntries()['fit']
+ subentries = list(fit_entry.GetEntries().keys())
+ expected = ['kernel', 'fdt-1']
+ self.assertEqual(expected, subentries)
+
def testSimpleFit(self):
"""Test an image with a FIT inside"""
data = self._DoReadFile('161_fit.dts')
with self.assertRaises(ValueError) as e:
data = self._DoReadFile('231_pre_load_invalid_key.dts')
+ def _CheckSafeUniqueNames(self, *images):
+ """Check all entries of given images for unsafe unique names"""
+ for image in images:
+ entries = {}
+ image._CollectEntries(entries, {}, image)
+ for entry in entries.values():
+ uniq = entry.GetUniqueName()
+
+ # Used as part of a filename, so must not be absolute paths.
+ self.assertFalse(os.path.isabs(uniq))
+
+ def testSafeUniqueNames(self):
+ """Test entry unique names are safe in single image configuration"""
+ data = self._DoReadFileRealDtb('230_unique_names.dts')
+
+ orig_image = control.images['image']
+ image_fname = tools.get_output_filename('image.bin')
+ image = Image.FromFile(image_fname)
+
+ self._CheckSafeUniqueNames(orig_image, image)
+
+ def testSafeUniqueNamesMulti(self):
+ """Test entry unique names are safe with multiple images"""
+ data = self._DoReadFileRealDtb('231_unique_names_multi.dts')
+
+ orig_image = control.images['image']
+ image_fname = tools.get_output_filename('image.bin')
+ image = Image.FromFile(image_fname)
+
+ self._CheckSafeUniqueNames(orig_image, image)
+
+ def testReplaceCmdWithBintool(self):
+ """Test replacing an entry that needs a bintool to pack"""
+ data = self._DoReadFileRealDtb('232_replace_with_bintool.dts')
+ expected = U_BOOT_DATA + b'aa'
+ self.assertEqual(expected, data[:len(expected)])
+
+ try:
+ tmpdir, updated_fname = self._SetupImageInTmpdir()
+ fname = os.path.join(tmpdir, 'update-testing.bin')
+ tools.write_file(fname, b'zz')
+ self._DoBinman('replace', '-i', updated_fname,
+ '_testing', '-f', fname)
+
+ data = tools.read_file(updated_fname)
+ expected = U_BOOT_DATA + b'zz'
+ self.assertEqual(expected, data[:len(expected)])
+ finally:
+ shutil.rmtree(tmpdir)
+
+ def testReplaceCmdOtherWithBintool(self):
+ """Test replacing an entry when another needs a bintool to pack"""
+ data = self._DoReadFileRealDtb('232_replace_with_bintool.dts')
+ expected = U_BOOT_DATA + b'aa'
+ self.assertEqual(expected, data[:len(expected)])
+
+ try:
+ tmpdir, updated_fname = self._SetupImageInTmpdir()
+ fname = os.path.join(tmpdir, 'update-u-boot.bin')
+ tools.write_file(fname, b'x' * len(U_BOOT_DATA))
+ self._DoBinman('replace', '-i', updated_fname,
+ 'u-boot', '-f', fname)
+
+ data = tools.read_file(updated_fname)
+ expected = b'x' * len(U_BOOT_DATA) + b'aa'
+ self.assertEqual(expected, data[:len(expected)])
+ finally:
+ shutil.rmtree(tmpdir)
+
+ def testReplaceResizeNoRepackSameSize(self):
+ """Test replacing entries with same-size data without repacking"""
+ expected = b'x' * len(U_BOOT_DATA)
+ data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected)
+ self.assertEqual(expected, data)
+
+ path, fdtmap = state.GetFdtContents('fdtmap')
+ self.assertIsNotNone(path)
+ self.assertEqual(expected_fdtmap, fdtmap)
+
+ def testReplaceResizeNoRepackSmallerSize(self):
+ """Test replacing entries with smaller-size data without repacking"""
+ new_data = b'x'
+ data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', new_data)
+ expected = new_data.ljust(len(U_BOOT_DATA), b'\0')
+ self.assertEqual(expected, data)
+
+ path, fdtmap = state.GetFdtContents('fdtmap')
+ self.assertIsNotNone(path)
+ self.assertEqual(expected_fdtmap, fdtmap)
+
+ def testExtractFit(self):
+ """Test extracting a FIT section"""
+ self._DoReadFileRealDtb('233_fit_extract_replace.dts')
+ image_fname = tools.get_output_filename('image.bin')
+
+ fit_data = control.ReadEntry(image_fname, 'fit')
+ fit = fdt.Fdt.FromData(fit_data)
+ fit.Scan()
+
+ # Check subentry data inside the extracted fit
+ for node_path, expected in [
+ ('/images/kernel', U_BOOT_DATA),
+ ('/images/fdt-1', U_BOOT_NODTB_DATA),
+ ('/images/scr-1', COMPRESS_DATA),
+ ]:
+ node = fit.GetNode(node_path)
+ data = fit.GetProps(node)['data'].bytes
+ self.assertEqual(expected, data)
+
+ def testExtractFitSubentries(self):
+ """Test extracting FIT section subentries"""
+ self._DoReadFileRealDtb('233_fit_extract_replace.dts')
+ image_fname = tools.get_output_filename('image.bin')
+
+ for entry_path, expected in [
+ ('fit/kernel', U_BOOT_DATA),
+ ('fit/kernel/u-boot', U_BOOT_DATA),
+ ('fit/fdt-1', U_BOOT_NODTB_DATA),
+ ('fit/fdt-1/u-boot-nodtb', U_BOOT_NODTB_DATA),
+ ('fit/scr-1', COMPRESS_DATA),
+ ('fit/scr-1/blob', COMPRESS_DATA),
+ ]:
+ data = control.ReadEntry(image_fname, entry_path)
+ self.assertEqual(expected, data)
+
+ def testReplaceFitSubentryLeafSameSize(self):
+ """Test replacing a FIT leaf subentry with same-size data"""
+ new_data = b'x' * len(U_BOOT_DATA)
+ data, expected_fdtmap, _ = self._RunReplaceCmd(
+ 'fit/kernel/u-boot', new_data,
+ dts='233_fit_extract_replace.dts')
+ self.assertEqual(new_data, data)
+
+ path, fdtmap = state.GetFdtContents('fdtmap')
+ self.assertIsNotNone(path)
+ self.assertEqual(expected_fdtmap, fdtmap)
+
+ def testReplaceFitSubentryLeafBiggerSize(self):
+ """Test replacing a FIT leaf subentry with bigger-size data"""
+ new_data = b'ub' * len(U_BOOT_NODTB_DATA)
+ data, expected_fdtmap, _ = self._RunReplaceCmd(
+ 'fit/fdt-1/u-boot-nodtb', new_data,
+ dts='233_fit_extract_replace.dts')
+ self.assertEqual(new_data, data)
+
+ # Will be repacked, so fdtmap must change
+ path, fdtmap = state.GetFdtContents('fdtmap')
+ self.assertIsNotNone(path)
+ self.assertNotEqual(expected_fdtmap, fdtmap)
+
+ def testReplaceFitSubentryLeafSmallerSize(self):
+ """Test replacing a FIT leaf subentry with smaller-size data"""
+ new_data = b'x'
+ expected = new_data.ljust(len(U_BOOT_NODTB_DATA), b'\0')
+ data, expected_fdtmap, _ = self._RunReplaceCmd(
+ 'fit/fdt-1/u-boot-nodtb', new_data,
+ dts='233_fit_extract_replace.dts')
+ self.assertEqual(expected, data)
+
+ path, fdtmap = state.GetFdtContents('fdtmap')
+ self.assertIsNotNone(path)
+ self.assertEqual(expected_fdtmap, fdtmap)
+
+ @unittest.expectedFailure
+ def testReplaceSectionSimple(self):
+ """Test replacing a simple section with arbitrary data"""
+ new_data = b'w' * len(COMPRESS_DATA + U_BOOT_DATA)
+ data, expected_fdtmap, _ = self._RunReplaceCmd(
+ 'section', new_data,
+ dts='234_replace_section_simple.dts')
+ self.assertEqual(new_data, data)
+
+
if __name__ == "__main__":
unittest.main()
"""See README for more information"""
-from distutils.sysconfig import get_python_lib
import os
import site
import sys
sys.path.insert(2, os.path.join(srctree, 'build-sandbox/scripts/dtc/pylibfdt'))
sys.path.insert(2, os.path.join(srctree, 'build-sandbox_spl/scripts/dtc/pylibfdt'))
-# When running under python-coverage on Ubuntu 16.04, the dist-packages
-# directories are dropped from the python path. Add them in so that we can find
-# the elffile module. We could use site.getsitepackages() here but unfortunately
-# that is not available in a virtualenv.
-sys.path.append(get_python_lib())
-
from binman import cmdline
from binman import control
from patman import test_util
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ size = <0xc00>;
+ allow-repack;
+
+ u-boot {
+ };
+
+ fdtmap {
+ };
+
+ u-boot2 {
+ type = "u-boot";
+ };
+
+ text {
+ text = "some text";
+ };
+
+ u-boot-dtb {
+ };
+
+ image-header {
+ location = "end";
+ };
+ };
+};
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ multiple-images;
+
+ image {
+ size = <0xc00>;
+ allow-repack;
+
+ u-boot {
+ };
+
+ fdtmap {
+ };
+
+ u-boot2 {
+ type = "u-boot";
+ };
+
+ text {
+ text = "some text";
+ };
+
+ u-boot-dtb {
+ };
+
+ image-header {
+ location = "end";
+ };
+ };
+ };
+};
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ size = <0xc00>;
+ allow-repack;
+
+ u-boot {
+ };
+
+ _testing {
+ require-bintool-for-contents;
+ require-bintool-for-pack;
+ };
+
+ fdtmap {
+ };
+
+ u-boot2 {
+ type = "u-boot";
+ };
+
+ text {
+ text = "some text";
+ };
+
+ u-boot-dtb {
+ };
+
+ image-header {
+ location = "end";
+ };
+ };
+};
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ allow-repack;
+
+ fill {
+ size = <0x1000>;
+ fill-byte = [77];
+ };
+
+ fit {
+ description = "test-desc";
+ #address-cells = <1>;
+
+ images {
+ kernel {
+ description = "test u-boot";
+ type = "kernel";
+ arch = "arm64";
+ os = "linux";
+ compression = "none";
+ load = <00000000>;
+ entry = <00000000>;
+
+ u-boot {
+ };
+ };
+
+ fdt-1 {
+ description = "test u-boot-nodtb";
+ type = "flat_dt";
+ arch = "arm64";
+ compression = "none";
+
+ u-boot-nodtb {
+ };
+ };
+
+ scr-1 {
+ description = "test blob";
+ type = "script";
+ arch = "arm64";
+ compression = "none";
+
+ blob {
+ filename = "compress";
+ };
+ };
+ };
+
+ configurations {
+ default = "conf-1";
+
+ conf-1 {
+ description = "Kernel with FDT blob";
+ kernel = "kernel";
+ fdt = "fdt-1";
+ };
+ };
+ };
+
+ u-boot-dtb {
+ };
+
+ fdtmap {
+ };
+ };
+};
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0+
+/dts-v1/;
+
+/ {
+ binman {
+ allow-repack;
+
+ u-boot-dtb {
+ };
+
+ section {
+ blob {
+ filename = "compress";
+ };
+
+ u-boot {
+ };
+ };
+
+ fdtmap {
+ };
+ };
+};