Pull request for efi-2022-07-rc1-3

Documentation:
 
 * Document image size parameter of bootefi command
 
 UEFI:
 
 * avoid building partition support in SPL/TPL where not required
 * improve integration of EFI subsystem and driver model
 * restore ability to boot arbitrary blob
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEbcT5xx8ppvoGt20zxIHbvCwFGsQFAmJka8UACgkQxIHbvCwF
 GsQXVw/+OuG4lYgiBZUUOFtu7CZZTrEnMGszRhXmwEzTMNq2NBNRP1lRJFhyyU50
 ElS/I7wZwhFtEnsL5H4mf3Ww7BQLELecg/Q7bnDYhPNg4JWUWUSCGOVUkNRs5O1h
 3f6HBkdbvDVvITgopqEj1v4sNwSJCr8sFJQPe0o7i9FAb0+dbO/Er3Z6afp9vcsQ
 C6iiNq4zTaGm0YUZf1wOCJMngijvkJ+z+McAFCCAwH0zbT7GfNpmGNr8iviYPWJM
 tKzkvO73+LhGR6fgRl9XewbV0Mlkd2q54nfZrP+7tTycIrj0G/OUOyPnOUaJk485
 keouzcIVSzZGjeQtsZ9Rrw8EounuMJ/pRyGNsoWIyeY98gqJxtVYnrlNm/TvFs6F
 vALsqq0LsRkVmM/ut8eleV/U8Q6n6IYL4xtAH0tm4Jf4mrW1zt8IgWQnNOlHqg9J
 RjOAF0y38KUAoC7RzGjU+RJcWPoYuKGxEWEdGvIu3qP9blwaZ7UKRxqWilOgbypf
 pxbp9YsnT8pqY9cs6mzSZHPjJFSMVocaRzD521kgShS4cxOJHpZHU4wzd5hS4BFr
 BIMCSPPyuRmn3E2DDqncEtL4C7OoPV+LLXVyrF2neiWwjMd/4rGAoYnDwjRkD7dP
 uSFsNt9N3Mqpjwl/iMI5Kd+mOJ77TWnf9fKrEft4BIXexopzAms=
 =a5qc
 -----END PGP SIGNATURE-----

Merge tag 'efi-2022-07-rc1-3' of https://source.denx.de/u-boot/custodians/u-boot-efi

Pull request for efi-2022-07-rc1-3

Documentation:

* Document image size parameter of bootefi command

UEFI:

* avoid building partition support in SPL/TPL where not required
* improve integration of EFI subsystem and driver model
* restore ability to boot arbitrary blob
This commit is contained in:
Tom Rini 2022-04-23 18:42:00 -04:00
commit 46a06ed82a
25 changed files with 805 additions and 184 deletions

View File

@ -422,10 +422,11 @@ static int do_efibootmgr(void)
* 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;
@ -443,14 +444,21 @@ static int do_bootefi_image(const char *image_opt)
/* 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);
@ -654,7 +662,7 @@ static int do_bootefi(struct cmd_tbl *cmdtp, int flag, int argc,
return CMD_RET_FAILURE;
}
if (argc > 2) {
if (argc > 2 && strcmp(argv[2], "-")) {
uintptr_t fdt_addr;
fdt_addr = hextoul(argv[2], NULL);
@ -677,15 +685,15 @@ static int do_bootefi(struct cmd_tbl *cmdtp, int flag, int argc,
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"
@ -707,7 +715,7 @@ static char bootefi_help_text[] =
#endif
U_BOOT_CMD(
bootefi, 3, 0, do_bootefi,
bootefi, 4, 0, do_bootefi,
"Boots an EFI payload from memory",
bootefi_help_text
);

View File

@ -463,7 +463,7 @@ static void bootmenu_show(int delay)
}
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;
}
@ -476,7 +476,7 @@ static void bootmenu_show(int delay)
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);

View File

@ -795,7 +795,7 @@ static init_fnc_t init_sequence_r[] = {
initr_mem,
#endif
#ifdef CONFIG_EFI_SETUP_EARLY
(init_fnc_t)efi_init_obj_list,
efi_init_early,
#endif
run_main_loop,
};

View File

@ -54,8 +54,11 @@ void main_loop(void)
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))

View File

@ -2,8 +2,7 @@
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:
@ -20,8 +19,7 @@ config PARTITIONS
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
@ -30,8 +28,7 @@ config SPL_PARTITIONS
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
@ -41,57 +38,61 @@ config TPL_PARTITIONS
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
@ -128,9 +129,10 @@ config EFI_PARTITION_ENTRIES_OFF
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"
@ -143,12 +145,11 @@ config PARTITION_UUIDS
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

View File

@ -6,6 +6,9 @@
#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

247
disk/disk-uclass.c Normal file
View File

@ -0,0 +1,247 @@
// 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",
};

View File

@ -10,6 +10,7 @@ the following SoCs work:
- 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:
@ -78,5 +79,5 @@ supported SoCs.
- Base Address
* - M1 (t8103)
- 0x235200000
* - M1 Pro/Max (t6000/t6001)
* - M1 Pro/Max/Ultra (t6000/t6001/t6002)
- 0x39b200000

View File

@ -1042,6 +1042,27 @@ data structure might be worthwhile in some rare cases, once we understand
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
----------------

View File

@ -74,7 +74,7 @@ BootROM's standard input and BootROM's terminal echo are active and working
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

View File

@ -9,7 +9,7 @@ Synopsis
::
bootefi [image_addr] [fdt_addr]
bootefi [image_addr] [fdt_addr [image_size]]
bootefi bootmgr [fdt_addr]
bootefi hello [fdt_addr]
bootefi selftest [fdt_addr]
@ -41,13 +41,28 @@ command sequence to run a UEFI application might look like
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.

View File

@ -741,6 +741,10 @@ static int blk_post_probe(struct udevice *dev)
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;

View File

@ -29,7 +29,7 @@ int dev_tag_set_ptr(struct udevice *dev, enum dm_tag_t tag, void *ptr)
node = calloc(sizeof(*node), 1);
if (!node)
return -ENOSPC;
return -ENOMEM;
node->dev = dev;
node->tag = tag;
@ -53,7 +53,7 @@ int dev_tag_set_val(struct udevice *dev, enum dm_tag_t tag, ulong val)
node = calloc(sizeof(*node), 1);
if (!node)
return -ENOSPC;
return -ENOMEM;
node->dev = dev;
node->tag = tag;

View File

@ -83,6 +83,7 @@ enum uclass_id {
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 */

View File

@ -493,6 +493,8 @@ struct efi_register_notify_event {
/* 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 */
@ -523,8 +525,8 @@ void efi_carve_out_dt_rsv(void *fdt);
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 */

View File

@ -10,6 +10,7 @@
#include <ide.h>
#include <uuid.h>
#include <linker_lists.h>
#include <linux/errno.h>
#include <linux/list.h>
struct block_drvr {
@ -86,7 +87,7 @@ struct disk_part {
};
/* 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
*
@ -103,7 +104,6 @@ struct disk_part {
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,
@ -275,6 +275,22 @@ static inline int blk_get_device_part_str(const char *ifname,
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,
@ -287,6 +303,23 @@ part_get_info_by_dev_and_name_or_num(const char *dev_iface,
}
#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.
@ -496,7 +529,7 @@ int layout_mbr_partitions(struct disk_partition *p, int count,
#endif
#ifdef CONFIG_PARTITIONS
#if CONFIG_IS_ENABLED(PARTITIONS)
/**
* part_driver_get_count() - get partition driver count
*

View File

@ -26,4 +26,6 @@ struct host_block_dev {
*/
int host_dev_bind(int dev, char *filename, bool removable);
int host_get_dev_err(int dev, struct blk_desc **blk_devp);
#endif

View File

@ -35,6 +35,7 @@
#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.
@ -106,25 +107,6 @@ static ulong efi_bl_write(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
return blkcnt;
}
/**
* 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
*
@ -139,7 +121,6 @@ static int efi_bl_bind(efi_handle_t handle, void *interface)
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);
@ -173,15 +154,20 @@ static int efi_bl_bind(efi_handle_t handle, void *interface)
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;
}

View File

@ -14,8 +14,10 @@ config EFI_LOADER
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
@ -40,6 +42,7 @@ config CMD_BOOTEFI_BOOTMGR
config EFI_SETUP_EARLY
bool
default y
choice
prompt "Store for non-volatile UEFI variables"

View File

@ -68,7 +68,7 @@ obj-y += efi_watchdog.o
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

View File

@ -864,11 +864,16 @@ static void *dp_part_node(void *buf, struct blk_desc *desc, int part)
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;
}

View File

@ -10,6 +10,9 @@
#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>
@ -33,7 +36,7 @@ const efi_guid_t efi_system_partition_guid = PARTITION_SYSTEM_GUID;
* @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;
@ -45,7 +48,7 @@ struct efi_disk_obj {
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 */
};
/**
@ -80,14 +83,12 @@ static efi_status_t efi_disk_rw_blocks(struct efi_block_io *this,
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;
@ -98,10 +99,21 @@ static efi_status_t efi_disk_rw_blocks(struct efi_block_io *this,
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();
@ -443,7 +455,6 @@ static efi_status_t efi_disk_add_dev(
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;
@ -487,103 +498,255 @@ error:
return ret;
}
/**
* efi_disk_create_partitions() - create handles and protocols for partitions
/*
* Create a handle for a whole raw disk
*
* Create handles and protocols for the partitions of a block device.
* @dev uclass device (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
* Create an efi_disk object which is associated with @dev.
* The type of @dev must be UCLASS_BLK.
*
* @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)
{
int disks = 0;
char devname[32] = { 0 }; /* dp->str is u16[32] long */
int part;
struct efi_device_path *dp = NULL;
efi_status_t ret;
struct efi_handler *handler;
/* 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++;
}
return disks;
}
/**
* efi_disk_register() - register block devices
*
* 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.
*
* This function is called in efi_init_obj_list().
*
* 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: status code
*/
efi_status_t efi_disk_register(void)
static int efi_disk_create_raw(struct udevice *dev)
{
struct efi_disk_obj *disk;
int disks = 0;
struct blk_desc *desc;
const char *if_typename;
int diskid;
efi_status_t ret;
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);
desc = dev_get_uclass_plat(dev);
if_typename = blk_get_if_type_name(desc->if_type);
diskid = desc->devnum;
/* 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) {
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);
continue;
}
if (ret) {
log_err("ERROR: failure to add disk device %s, r = %lu\n",
dev->name, ret & ~EFI_ERROR_MASK);
continue;
}
disks++;
else
log_err("Adding disk for %s failed\n", dev->name);
/* Partitions show up as block devices in EFI */
disks += efi_disk_create_partitions(
&disk->header, desc, if_typename,
desc->devnum, 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;
}
log_info("Found %d disks\n", disks);
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;
ret = efi_search_protocol(parent, &efi_guid_device_path, &handler);
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 0;
}
/*
* Create efi_disk objects for a block device
*
* @dev uclass device (UCLASS_BLK)
*
* 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.
*
* @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
*
* @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
*/
static int efi_disk_delete_raw(struct udevice *dev)
{
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;
dev = event->data.dm.dev;
id = device_get_uclass_id(dev);
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;
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;
}
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;
}

View File

@ -174,6 +174,55 @@ static efi_status_t efi_init_os_indications(void)
&os_indications_supported, false);
}
/**
* __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
*/
static efi_status_t __efi_init_early(void)
{
efi_status_t ret = EFI_SUCCESS;
/* Allow unaligned memory access */
allow_unaligned();
/* Initialize root node */
ret = efi_root_node_register();
if (ret != EFI_SUCCESS)
goto out;
ret = efi_console_register();
if (ret != EFI_SUCCESS)
goto out;
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
@ -188,23 +237,12 @@ efi_status_t efi_init_obj_list(void)
if (efi_obj_list_initialized != OBJ_LIST_NOT_INITIALIZED)
return efi_obj_list_initialized;
/* Allow unaligned memory access */
allow_unaligned();
if (!IS_ENABLED(CONFIG_EFI_SETUP_EARLY)) {
ret = __efi_init_early();
if (ret != EFI_SUCCESS)
goto out;
}
/* Initialize root node */
ret = efi_root_node_register();
if (ret != EFI_SUCCESS)
goto out;
ret = efi_console_register();
if (ret != EFI_SUCCESS)
goto out;
#ifdef CONFIG_PARTITIONS
ret = efi_disk_register();
if (ret != EFI_SUCCESS)
goto out;
#endif
if (IS_ENABLED(CONFIG_EFI_RNG_PROTOCOL)) {
ret = efi_rng_register();
if (ret != EFI_SUCCESS)

View File

@ -102,6 +102,7 @@ obj-y += syscon.o
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

84
test/dm/tag.c Normal file
View File

@ -0,0 +1,84 @@
// 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);