[U-Boot] [PATCH 7/9] efi_loader: Add disk interfaces
Alexander Graf
agraf at suse.de
Fri Jan 15 03:40:53 CET 2016
On 15.01.16 02:37, Simon Glass wrote:
> Hi Alexander,
>
> On 22 December 2015 at 06:57, Alexander Graf <agraf at suse.de> wrote:
>> A EFI applications usually want to access storage devices to load data from.
>>
>> This patch adds support for EFI disk interfaces. It loops through all block
>> storage interfaces known to U-Boot and creates an EFI object for each existing
>> one. EFI applications can then through these objects call U-Boot's read and
>> write functions.
>>
>> Signed-off-by: Alexander Graf <agraf at suse.de>
>> ---
>> include/efi_loader.h | 1 +
>> lib/efi_loader/efi_disk.c | 227 ++++++++++++++++++++++++++++++++++++++++++++++
>> 2 files changed, 228 insertions(+)
>> create mode 100644 lib/efi_loader/efi_disk.c
>
> Reviewed-by: Simon Glass <sjg at chromium.org>
>
> Some nits below.
>
>>
>> diff --git a/include/efi_loader.h b/include/efi_loader.h
>> index af1c88f..7e821e5 100644
>> --- a/include/efi_loader.h
>> +++ b/include/efi_loader.h
>> @@ -72,6 +72,7 @@ struct efi_object {
>> };
>> extern struct list_head efi_obj_list;
>>
>> +int efi_disk_register(void);
>> efi_status_t efi_return_handle(void *handle,
>> efi_guid_t *protocol, void **protocol_interface,
>> void *agent_handle, void *controller_handle,
>> diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c
>> new file mode 100644
>> index 0000000..1804e3e
>> --- /dev/null
>> +++ b/lib/efi_loader/efi_disk.c
>> @@ -0,0 +1,227 @@
>> +/*
>> + * EFI application disk support
>> + *
>> + * Copyright (c) 2015 Alexander Graf
>> + *
>> + * This library is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU Lesser General Public
>> + * License as published by the Free Software Foundation; either
>> + * version 2.1 of the License, or (at your option) any later version.
>> + *
>> + * This library is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
>> + * Lesser General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU Lesser General Public
>> + * License along with this library; if not, write to the Free Software
>> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
>> + *
>> + * SPDX-License-Identifier: LGPL-2.1+
>
> Can we have GPL 2 / 2+? Also drop the text?
>
>> + */
>> +
>> +#include <common.h>
>> +#include <efi_loader.h>
>> +#include <part.h>
>> +#include <malloc.h>
>> +#include <inttypes.h>
>
> inttypes.h should go above part.h
>
>> +
>> +static const efi_guid_t efi_block_io_guid = BLOCK_IO_GUID;
>> +
>> +struct efi_disk_obj {
>
> Could use comments on these members
>
>> + struct efi_object parent;
>> + struct efi_block_io ops;
>> + const char *ifname;
>> + int dev_index;
>> + struct efi_block_io_media media;
>> + struct efi_device_path_file_path *dp;
>> +};
>> +
>> +static void ascii2unicode(u16 *unicode, char *ascii)
>> +{
>> + while (*ascii)
>> + *(unicode++) = *(ascii++);
>> +}
>> +
>> +static efi_status_t efi_disk_open_block(void *handle, efi_guid_t *protocol,
>> + void **protocol_interface, void *agent_handle,
>> + void *controller_handle, uint32_t attributes)
>> +{
>> + struct efi_disk_obj *diskobj = handle;
>> +
>> + *protocol_interface = &diskobj->ops;
>> +
>> + return EFI_SUCCESS;
>> +}
>> +
>> +static efi_status_t efi_disk_open_dp(void *handle, efi_guid_t *protocol,
>> + void **protocol_interface, void *agent_handle,
>> + void *controller_handle, uint32_t attributes)
>> +{
>> + struct efi_disk_obj *diskobj = handle;
>> +
>> + *protocol_interface = diskobj->dp;
>> +
>> + return EFI_SUCCESS;
>> +}
>> +
>> +static efi_status_t efi_disk_reset(struct efi_block_io *this,
>> + char extended_verification)
>> +{
>> + EFI_ENTRY("%p, %x", this, extended_verification);
>> + return EFI_EXIT(EFI_DEVICE_ERROR);
>> +}
>> +
>> +enum efi_disk_direction {
>> + EFI_DISK_READ,
>> + EFI_DISK_WRITE,
>> +};
>> +
>> +static efi_status_t efi_disk_rw_blocks(struct efi_block_io *this,
>> + u32 media_id, u64 lba, unsigned long buffer_size,
>> + void *buffer, enum efi_disk_direction direction)
>> +{
>> + struct efi_disk_obj *diskobj;
>> + struct block_dev_desc *desc;
>> + int blksz;
>> + int blocks;
>> + unsigned long n;
>> +
>> + EFI_ENTRY("%p, %x, %"PRIx64", %lx, %p", this, media_id, lba,
>> + buffer_size, buffer);
>> +
>> + diskobj = container_of(this, struct efi_disk_obj, ops);
>> + if (!(desc = get_dev(diskobj->ifname, diskobj->dev_index)))
>> + return EFI_EXIT(EFI_DEVICE_ERROR);
>> + blksz = desc->blksz;
>> + blocks = buffer_size / blksz;
>> +
>> +#ifdef DEBUG_EFI
>> + printf("EFI: %s:%d blocks=%x lba=%"PRIx64" blksz=%x dir=%d\n", __func__,
>> + __LINE__, blocks, lba, blksz, direction);
>> +#endif
>> +
>> + /* We only support full block access */
>> + if (buffer_size & (blksz - 1))
>> + return EFI_EXIT(EFI_DEVICE_ERROR);
>> +
>> + if (direction == EFI_DISK_READ)
>> + n = desc->block_read(desc->dev, lba, blocks, buffer);
>> + else
>> + n = desc->block_write(desc->dev, lba, blocks, buffer);
>> +
>> + /* We don't do interrupts, so check for timers cooperatively */
>> + efi_timer_check();
>> +
>> +#ifdef DEBUG_EFI
>> + printf("EFI: %s:%d n=%lx blocks=%x\n", __func__, __LINE__, n, blocks);
>> +#endif
>> + if (n != blocks)
>> + return EFI_EXIT(EFI_DEVICE_ERROR);
>> +
>> + return EFI_EXIT(EFI_SUCCESS);
>> +}
>> +
>> +static efi_status_t efi_disk_read_blocks(struct efi_block_io *this,
>> + u32 media_id, u64 lba, unsigned long buffer_size,
>> + void *buffer)
>> +{
>> + return efi_disk_rw_blocks(this, media_id, lba, buffer_size, buffer,
>> + EFI_DISK_READ);
>> +}
>> +
>> +static efi_status_t efi_disk_write_blocks(struct efi_block_io *this,
>> + u32 media_id, u64 lba, unsigned long buffer_size,
>> + void *buffer)
>> +{
>> + return efi_disk_rw_blocks(this, media_id, lba, buffer_size, buffer,
>> + EFI_DISK_WRITE);
>> +}
>> +
>> +static efi_status_t efi_disk_flush_blocks(struct efi_block_io *this)
>> +{
>> + /* We always write synchronously */
>> + return EFI_SUCCESS;
>> +}
>> +
>> +static const struct efi_block_io block_io_disk_template = {
>> + .reset = &efi_disk_reset,
>> + .read_blocks = &efi_disk_read_blocks,
>> + .write_blocks = &efi_disk_write_blocks,
>> + .flush_blocks = &efi_disk_flush_blocks,
>> +};
>> +
>> +/*
>> + * 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 gets called from do_bootefi_exec().
>> + */
>> +int efi_disk_register(void)
>> +{
>> + const char **cur_drvr;
>> + int i;
>> + int disks = 0;
>> +
>> + /* Search for all available disk devices */
>> + for (cur_drvr = available_block_drvrs; *cur_drvr; cur_drvr++) {
>> + printf("Scanning disks on %s...\n", *cur_drvr);
>> + for (i = 0; i < 4; i++) {
>
> What is 4 for?
4 disks should be enough for everyone ;).
I couldn't find an easy way to limit the number of devices we have to
scan. You may have 4 MMC slots, but only slot 3 is actually populated.
How do you know how many there really are?
So we have to use some upper bound for the scan. The 4 is simply because
most devices I'm aware of that U-Boot runs on don't have much more than
4 devices per block bus attached to them. I had 128 in here first, but
then I ran into endless timeouts with MMC scans.
Thanks a bunch for the review :)
Alex
More information about the U-Boot
mailing list