From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 601DFC433F5 for ; Tue, 26 Oct 2021 03:33:43 +0000 (UTC) Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id D5B9560E74 for ; Tue, 26 Oct 2021 03:33:42 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org D5B9560E74 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=chromium.org Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=lists.denx.de Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 4ED6F835F9; Tue, 26 Oct 2021 05:32:45 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.b="e06uPDca"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id A0C798358B; Tue, 26 Oct 2021 05:31:29 +0200 (CEST) Received: from mail-io1-xd31.google.com (mail-io1-xd31.google.com [IPv6:2607:f8b0:4864:20::d31]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 68B1A835A0 for ; Tue, 26 Oct 2021 05:31:18 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=sjg@chromium.org Received: by mail-io1-xd31.google.com with SMTP id v65so6754637ioe.5 for ; Mon, 25 Oct 2021 20:31:18 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=FCFBFV+WgSFXNeAigPncfC2UoNehjHCLGVssgTp/FOM=; b=e06uPDcaxUGsR5gI3Op0b6npUleRdcqWg4ZHwe5zizEdcYn1v8/5GjlEfMRvqzRULk 3OpaBV03db8xYcEfOtxgFZzYCkl5XpiYOHRH0iLXGQlT8l1DsIvMTx3ccHxErTCArn39 XP+MQzR+1aIBoYhVmKhnhWOwrTrISDBg8fdI0= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=FCFBFV+WgSFXNeAigPncfC2UoNehjHCLGVssgTp/FOM=; b=ultsc1/AjA6rXszEotqxKhjsEfAoJWFH8AXVo+C+vYbl4W/w6LevxrT8WI49TqLPwc HvcTF9UUYV+xkZ21Tndo5hI7b3mFuLwo9GFCyww3uxuNJXZaTRcLFFcON50fNzELHJLB qLdgU08xDuFqDdImjMzLIrpieEzCta47ji5SfmUTchJAbjy7DX0lGegjwvQ9vePvW0ZW MtNIwIf0c2pFaHyXrmKKNWrG6K047hyQdaM+VzO9FEm788bfdhczfoLm/oDh8e/bl77p r3SWj/KcmVcvxuCaHF830uNX+gvp9OstvWazyN67aqT1WQJzAdiN5vjAQgZlJbJ+MzqM ZsFA== X-Gm-Message-State: AOAM533xYc8QzThMH7dcLN05WTOI3P6KDW8ye7SpXHEWYI0xcCK7HtsZ pi9aFp/dDCS4Lh3zfow2G/9+8TL5+5h8Lg== X-Google-Smtp-Source: ABdhPJzcl5MEIyxhhXI7Ak1AfYRbPJNk2wrfIlpnwf7zjLsjU4/HC7AdaXhfaBOyovpLZqcaoUtgcQ== X-Received: by 2002:a5e:db06:: with SMTP id q6mr13863102iop.43.1635219076861; Mon, 25 Oct 2021 20:31:16 -0700 (PDT) Received: from kiwi.bld.corp.google.com (c-67-190-101-114.hsd1.co.comcast.net. [67.190.101.114]) by smtp.gmail.com with ESMTPSA id s10sm10127203ild.78.2021.10.25.20.31.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 25 Oct 2021 20:31:16 -0700 (PDT) From: Simon Glass To: U-Boot Mailing List Cc: Ilias Apalodimas , Christian Melki , Bin Meng , Tom Rini , Heinrich Schuchardt , Simon Glass , Alexander Graf Subject: [PATCH v3 11/35] efi: Locate all block devices in the app Date: Mon, 25 Oct 2021 21:30:34 -0600 Message-Id: <20211025213041.v3.11.I0774d3540ebe726f31838b851815e829fb6a4056@changeid> X-Mailer: git-send-email 2.33.0.1079.g6e70778dc9-goog In-Reply-To: <20211026033058.430010-1-sjg@chromium.org> References: <20211026033058.430010-1-sjg@chromium.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.34 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.2 at phobos.denx.de X-Virus-Status: Clean When starting the app, locate all block devices and make them available to U-Boot. This allows listing partitions and accessing files in filesystems. EFI also has the concept of 'disks', meaning boot media. For now, this is not obviously useful in U-Boot, but add code to at least locate these. This can be expanded later as needed. Series-changes; 2 - Store device path in struct efi_media_plat - Don't export efi_bind_block() - Only bind devices for media devices, not for partitions - Show devices that are processed - Update documentation Signed-off-by: Simon Glass --- (no changes since v1) doc/develop/uefi/u-boot_on_efi.rst | 4 +- include/efi.h | 6 +- include/efi_api.h | 15 ++ lib/efi/efi_app.c | 223 +++++++++++++++++++++++++++++ 4 files changed, 243 insertions(+), 5 deletions(-) diff --git a/doc/develop/uefi/u-boot_on_efi.rst b/doc/develop/uefi/u-boot_on_efi.rst index 83de9309816..f39be4a1ed9 100644 --- a/doc/develop/uefi/u-boot_on_efi.rst +++ b/doc/develop/uefi/u-boot_on_efi.rst @@ -263,9 +263,7 @@ This work could be extended in a number of ways: - Figure out how to solve the interrupt problem -- Add more drivers to the application side (e.g. block devices, USB, - environment access). This would mostly be an academic exercise as a strong - use case is not readily apparent, but it might be fun. +- Add more drivers to the application side (e.g.USB, environment access). - Avoid turning off boot services in the stub. Instead allow U-Boot to make use of boot services in case it wants to. It is unclear what it might want diff --git a/include/efi.h b/include/efi.h index 0ec5913ddd1..908c5dc6ebd 100644 --- a/include/efi.h +++ b/include/efi.h @@ -419,10 +419,12 @@ struct efi_priv { * * @handle: handle of the controller on which this driver is installed * @blkio: block io protocol proxied by this driver + * @device_path: EFI path to the device */ struct efi_media_plat { - efi_handle_t handle; - struct efi_block_io *blkio; + efi_handle_t handle; + struct efi_block_io *blkio; + struct efi_device_path *device_path; }; /* Base address of the EFI image */ diff --git a/include/efi_api.h b/include/efi_api.h index c8f959bb720..0e88b3e5dbe 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -1994,4 +1994,19 @@ struct efi_firmware_management_protocol { const u16 *package_version_name); }; +#define EFI_DISK_IO_PROTOCOL_GUID \ + EFI_GUID(0xce345171, 0xba0b, 0x11d2, 0x8e, 0x4f, \ + 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b) + +struct efi_disk { + u64 revision; + efi_status_t (EFIAPI *read_disk)(struct efi_disk *this, u32 media_id, + u64 offset, efi_uintn_t buffer_size, + void *buffer); + + efi_status_t (EFIAPI *write_disk)(struct efi_disk *this, u32 media_id, + u64 offset, efi_uintn_t buffer_size, + void *buffer); +}; + #endif diff --git a/lib/efi/efi_app.c b/lib/efi/efi_app.c index f61665686c5..e38d46b15db 100644 --- a/lib/efi/efi_app.c +++ b/lib/efi/efi_app.c @@ -21,6 +21,9 @@ #include #include #include +#include +#include +#include DECLARE_GLOBAL_DATA_PTR; @@ -46,6 +49,64 @@ int efi_info_get(enum efi_entry_t type, void **datap, int *sizep) return -ENOSYS; } +/** + * efi_print_str() - Print a UFT-16 string to the U-Boot console + * + * @str: String to print + */ +static void efi_print_str(const u16 *str) +{ + while (*str) { + int ch = *str++; + + if (ch > ' ' && ch < 127) + putc(ch); + } +} + +/** + * efi_bind_block() - bind a new block device to an EFI device + * + * Binds a new top-level EFI_MEDIA device as well as a child block device so + * that the block device can be accessed in U-Boot. + * + * The device can then be accessed using 'part list efi 0', 'fat ls efi 0:1', + * for example, just like any other interface type. + * + * @handle: handle of the controller on which this driver is installed + * @blkio: block io protocol proxied by this driver + * @device_path: EFI device path structure for this + * @len: Length of @device_path in bytes + * @devp: Returns the bound device + * @return 0 if OK, -ve on error + */ +int efi_bind_block(efi_handle_t handle, struct efi_block_io *blkio, + struct efi_device_path *device_path, int len, + struct udevice **devp) +{ + struct efi_media_plat plat; + struct udevice *dev; + char name[18]; + int ret; + + plat.handle = handle; + plat.blkio = blkio; + plat.device_path = malloc(device_path->length); + if (!plat.device_path) + return log_msg_ret("path", -ENOMEM); + memcpy(plat.device_path, device_path, device_path->length); + ret = device_bind(dm_root(), DM_DRIVER_GET(efi_media), "efi_media", + &plat, ofnode_null(), &dev); + if (ret) + return log_msg_ret("bind", ret); + + snprintf(name, sizeof(name), "efi_media_%x", dev_seq(dev)); + device_set_name(dev, name); + *devp = dev; + + return 0; +} + static efi_status_t setup_memory(struct efi_priv *priv) { struct efi_boot_services *boot = priv->boot; @@ -105,6 +166,168 @@ static void free_memory(struct efi_priv *priv) global_data_ptr = NULL; } +static int setup_disks(void) +{ + /* This is not fully implemented yet */ + return 0; + + efi_guid_t efi_disk_guid = EFI_DISK_IO_PROTOCOL_GUID; + struct efi_boot_services *boot = efi_get_boot(); + struct efi_disk *disk; + int ret; + + if (!boot) + return log_msg_ret("sys", -ENOSYS); + ret = boot->locate_protocol(&efi_disk_guid, NULL, (void **)&disk); + if (ret) + return log_msg_ret("prot", -ENOTSUPP); + + return 0; +} + +/** + * devpath_is_partition() - Figure out if a device path is a partition + * + * Checks if a device path refers to a partition on some media device. This + * works by checking for a valid partition number in a hard-driver media device + * as the final component of the device path. + * + * @return true if a partition, false if not (e.g. it might be media which + * contains partitions) + */ +static bool devpath_is_partition(const struct efi_device_path *path) +{ + const struct efi_device_path *p; + bool was_part; + + for (p = path; p->type != DEVICE_PATH_TYPE_END; + p = (void *)p + p->length) { + was_part = false; + if (p->type == DEVICE_PATH_TYPE_MEDIA_DEVICE && + p->sub_type == DEVICE_PATH_SUB_TYPE_HARD_DRIVE_PATH) { + struct efi_device_path_hard_drive_path *hd = + (void *)path; + + if (hd->partition_number) + was_part = true; + } + } + + return was_part; +} + +/** + * setup_block() - Find all block devices and setup EFI devices for them + * + * Partitions are ignored, since U-Boot has partition handling. Errors with + * particular devices produce a warning but execution continues to try to + * find others. + * + * @return 0 if found, -ENOSYS if there is no boot-services table, -ENOTSUPP + * if a required protocol is not supported + */ +static int setup_block(void) +{ + efi_guid_t efi_blkio_guid = EFI_BLOCK_IO_PROTOCOL_GUID; + efi_guid_t efi_devpath_guid = EFI_DEVICE_PATH_PROTOCOL_GUID; + efi_guid_t efi_pathutil_guid = EFI_DEVICE_PATH_UTILITIES_PROTOCOL_GUID; + efi_guid_t efi_pathtext_guid = EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID; + struct efi_boot_services *boot = efi_get_boot(); + struct efi_device_path_utilities_protocol *util; + struct efi_device_path_to_text_protocol *text; + struct efi_device_path *path; + struct efi_block_io *blkio; + efi_uintn_t num_handles; + efi_handle_t *handle; + int ret, i; + + if (!boot) + return log_msg_ret("sys", -ENOSYS); + + /* Find all devices which support the block I/O protocol */ + ret = boot->locate_handle_buffer(BY_PROTOCOL, &efi_blkio_guid, NULL, + &num_handles, &handle); + if (ret) + return log_msg_ret("loc", -ENOTSUPP); + log_debug("Found %d handles:\n", (int)num_handles); + + /* We need to look up the path size and convert it to text */ + ret = boot->locate_protocol(&efi_pathutil_guid, NULL, (void **)&util); + if (ret) + return log_msg_ret("util", -ENOTSUPP); + ret = boot->locate_protocol(&efi_pathtext_guid, NULL, (void **)&text); + if (ret) + return log_msg_ret("text", -ENOTSUPP); + + for (i = 0; i < num_handles; i++) { + struct udevice *dev; + const u16 *name; + bool is_part; + int len; + + ret = boot->handle_protocol(handle[i], &efi_devpath_guid, + (void **)&path); + if (ret) { + log_warning("- devpath %d failed (ret=%d)\n", i, ret); + continue; + } + + ret = boot->handle_protocol(handle[i], &efi_blkio_guid, + (void **)&blkio); + if (ret) { + log_warning("- blkio %d failed (ret=%d)\n", i, ret); + continue; + } + + name = text->convert_device_path_to_text(path, true, false); + is_part = devpath_is_partition(path); + + if (!is_part) { + len = util->get_device_path_size(path); + ret = efi_bind_block(handle[i], blkio, path, len, &dev); + if (ret) { + log_warning("- blkio bind %d failed (ret=%d)\n", + i, ret); + continue; + } + } else { + dev = NULL; + } + + /* + * Show the device name if we created one. Otherwise indicate + * that it is a partition. + * + * We don't seem to have have a way to print unicode on the + * U-Boot console at present, so use our own function. + */ + printf("%2d: %-12s ", i, dev ? dev->name : ""); + efi_print_str(name); + printf("\n"); + } + boot->free_pool(handle); + + return 0; +} + +int dm_scan_other(bool pre_reloc_only) +{ + if (gd->flags & GD_FLG_RELOC) { + int ret; + + ret = setup_block(); + if (ret) + return ret; + + /* Not needed at present, but could be useful one day? */ + ret = setup_disks(); + if (ret) + return ret; + } + + return 0; +} + /** * efi_main() - Start an EFI image * -- 2.33.0.1079.g6e70778dc9-goog