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 A5750C433EF for ; Sat, 23 Oct 2021 23:30:07 +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 2B11360F22 for ; Sat, 23 Oct 2021 23:30:07 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org 2B11360F22 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 57D298350D; Sun, 24 Oct 2021 01:29:38 +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="H0kXrJ84"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 2C8AF8331C; Sun, 24 Oct 2021 01:27:48 +0200 (CEST) Received: from mail-ot1-x331.google.com (mail-ot1-x331.google.com [IPv6:2607:f8b0:4864:20::331]) (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 DBECF8331C for ; Sun, 24 Oct 2021 01:27:11 +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-ot1-x331.google.com with SMTP id s18-20020a0568301e1200b0054e77a16651so9299419otr.7 for ; Sat, 23 Oct 2021 16:27:11 -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=MTV/BkokAJnBkNJ4OUyi/1nBNcjXkHoK3BSP2RWVvxQ=; b=H0kXrJ84sJ8gXE/H56TGIsBwX9prSehfGMB9waCnqq6lTxvdzQFq+AaQvMKlCOiYZz 3jN0JDA1kLQO8cRAwc40V29YR23mdm7MhGWqhA9eIqKCr15fi46L2I6rh56yrdsTshEs OLGvMw3OPwL4gSIpdnG9vwPqA+PTpq01b/c1c= 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=MTV/BkokAJnBkNJ4OUyi/1nBNcjXkHoK3BSP2RWVvxQ=; b=eQR8roMi2wck9StS2LV4EiboMHhZ1/Ie35HqZT0zDJjtKKcKWil5VqRokuGYHqKBUF kKubLmQujlprYase2PPHAuqSFQz2vsAXzCNldnyqFmBfKuZq6a6KRVh6KToakcx3hFiB NFVlUM/6M3hpy/955tTmlS281Dt46MFK96/hItBPSNtscfXUj52mY8zMJ/aviz5EP6T/ O4vDVhKV71DLsWPHcMInv6EH02GXonZg/qNHqYRaVRDONZdM5X+IrYaibFh/DBSiR9WA Nhoe7SYKhjOi/hERFcGNVS0XTXej6jMUVtDg+89471pBK9BQdW3QDVh8Ow5Bl5FzJEqW I/kw== X-Gm-Message-State: AOAM533RpaqKPl800TmlxBXkU3SjKgfwt1zzPQgZhS8907bgYKnlg3Ot NGkEvwA5qJeH17pQSERZ8xm34rUBfSUTpw== X-Google-Smtp-Source: ABdhPJw0qq//lHoZzucMcp+0Ax6u7kyw4E/PyNpS/GJSN+O9v+2OC+/W4TWRMCBfduKMPm3cfD3+JQ== X-Received: by 2002:a05:6830:147:: with SMTP id j7mr6683329otp.67.1635031630125; Sat, 23 Oct 2021 16:27:10 -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 l24sm2253885oop.4.2021.10.23.16.27.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 23 Oct 2021 16:27:09 -0700 (PDT) From: Simon Glass To: U-Boot Mailing List Cc: Michal Simek , Heinrich Schuchardt , Tom Rini , Ilias Apalodimas , Daniel Schwierzeck , Steffen Jaeckel , =?UTF-8?q?Marek=20Beh=C3=BAn?= , Lukas Auer , Dennis Gilmore , Simon Glass Subject: [PATCH v2 23/41] bootstd: Add support for bootflows Date: Sat, 23 Oct 2021 17:26:17 -0600 Message-Id: <20211023232635.9195-20-sjg@chromium.org> X-Mailer: git-send-email 2.33.0.1079.g6e70778dc9-goog In-Reply-To: <20211023232635.9195-1-sjg@chromium.org> References: <20211023232635.9195-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 Add support for bootflows, including maintaining a list of them and iterating to find them. Signed-off-by: Simon Glass --- (no changes since v1) MAINTAINERS | 3 +- boot/Makefile | 1 + boot/bootdev-uclass.c | 12 +- boot/bootflow.c | 576 ++++++++++++++++++++++++++++++++++++++++++ boot/bootstd-uclass.c | 2 +- include/bootflow.h | 50 ++++ 6 files changed, 640 insertions(+), 4 deletions(-) create mode 100644 boot/bootflow.c diff --git a/MAINTAINERS b/MAINTAINERS index be11e3c2f2a..cbb7a160a26 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -636,8 +636,9 @@ F: tools/binman/ BOOTDEVICE M: Simon Glass S: Maintained -F: boot/bootmeth*.c F: boot/bootdev*.c +F: boot/bootflow.c +F: boot/bootmeth*.c F: boot/bootstd.c F: include/bootdev*.h F: include/bootflow.h diff --git a/boot/Makefile b/boot/Makefile index 54ded9541e0..f58c192ae07 100644 --- a/boot/Makefile +++ b/boot/Makefile @@ -24,6 +24,7 @@ obj-$(CONFIG_ANDROID_AB) += android_ab.o obj-$(CONFIG_ANDROID_BOOT_IMAGE) += image-android.o image-android-dt.o obj-$(CONFIG_$(SPL_TPL_)BOOTSTD) += bootdev-uclass.o +obj-$(CONFIG_$(SPL_TPL_)BOOTSTD) += bootflow.o obj-$(CONFIG_$(SPL_TPL_)BOOTSTD) += bootmeth-uclass.o obj-$(CONFIG_$(SPL_TPL_)BOOTSTD) += bootstd-uclass.o diff --git a/boot/bootdev-uclass.c b/boot/bootdev-uclass.c index c8455ec5159..deefe32605c 100644 --- a/boot/bootdev-uclass.c +++ b/boot/bootdev-uclass.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -121,9 +122,12 @@ int bootdev_find_in_blk(struct udevice *dev, struct udevice *blk, if (!bflow->name) return log_msg_ret("name", -ENOMEM); - bflow->state = BOOTFLOWST_BASE; bflow->part = iter->part; + ret = bootmeth_check(bflow->method, iter); + if (ret) + return log_msg_ret("check", ret); + /* * partition numbers start at 0 so this cannot succeed, but it can tell * us whether there is valid media there @@ -165,6 +169,10 @@ int bootdev_find_in_blk(struct udevice *dev, struct udevice *blk, bflow->state = BOOTFLOWST_FS; } + ret = bootmeth_read_bootflow(bflow->method, bflow); + if (ret) + return log_msg_ret("method", ret); + return 0; } @@ -401,7 +409,7 @@ void bootdev_clear_bootflows(struct udevice *dev) bflow = list_first_entry(&ucp->bootflow_head, struct bootflow, bm_node); - /* later bootflow_remove(bflow); */ + bootflow_remove(bflow); } } diff --git a/boot/bootflow.c b/boot/bootflow.c new file mode 100644 index 00000000000..b87b656f5bd --- /dev/null +++ b/boot/bootflow.c @@ -0,0 +1,576 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2021 Google LLC + * Written by Simon Glass + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* error codes used to signal running out of things */ +enum { + BF_NO_MORE_PARTS = -ESHUTDOWN, + BF_NO_MORE_DEVICES = -ENODEV, +}; + +static const char *const bootflow_state[BOOTFLOWST_COUNT] = { + "base", + "media", + "part", + "fs", + "file", + "ready", +}; + +const char *bootflow_state_get_name(enum bootflow_state_t state) +{ + if (state < 0 || state >= BOOTFLOWST_COUNT) + return "?"; + + return bootflow_state[state]; +} + +int bootflow_first_glob(struct bootflow **bflowp) +{ + struct bootstd_priv *std; + int ret; + + ret = bootstd_get_priv(&std); + if (ret) + return ret; + + if (list_empty(&std->glob_head)) + return -ENOENT; + + *bflowp = list_first_entry(&std->glob_head, struct bootflow, + glob_node); + + return 0; +} + +int bootflow_next_glob(struct bootflow **bflowp) +{ + struct bootstd_priv *std; + struct bootflow *bflow = *bflowp; + int ret; + + ret = bootstd_get_priv(&std); + if (ret) + return ret; + + *bflowp = NULL; + + if (list_is_last(&bflow->glob_node, &std->glob_head)) + return -ENOENT; + + *bflowp = list_entry(bflow->glob_node.next, struct bootflow, glob_node); + + return 0; +} + +void bootflow_iter_init(struct bootflow_iter *iter, int flags) +{ + memset(iter, '\0', sizeof(*iter)); + iter->flags = flags; +} + +void bootflow_iter_uninit(struct bootflow_iter *iter) +{ + free(iter->dev_order); + free(iter->method_order); +} + +int bootflow_iter_drop_bootmeth(struct bootflow_iter *iter, + const struct udevice *bmeth) +{ + /* We only support disabling the current bootmeth */ + if (bmeth != iter->method || iter->cur_method >= iter->num_methods || + iter->method_order[iter->cur_method] != bmeth) + return -EINVAL; + + memmove(&iter->method_order[iter->cur_method], + &iter->method_order[iter->cur_method + 1], + (iter->num_methods - iter->cur_method - 1) * sizeof(void *)); + + iter->num_methods--; + + return 0; +} + +static void bootflow_iter_set_dev(struct bootflow_iter *iter, + struct udevice *dev) +{ + iter->dev = dev; + if ((iter->flags & (BOOTFLOWF_SHOW | BOOTFLOWF_SINGLE_DEV)) == + BOOTFLOWF_SHOW) { + if (dev) + printf("Scanning bootdev '%s':\n", dev->name); + else + printf("No more bootdevs\n"); + } +} + +/** + * h_cmp_bootdev() - Compare two bootdevs to find out which should go first + * + * @v1: struct udevice * of first bootdev device + * @v2: struct udevice * of second bootdev device + * @return sort order (<0 if dev1 < dev2, ==0 if equal, >0 if dev1 > dev2) + */ +static int h_cmp_bootdev(const void *v1, const void *v2) +{ + const struct udevice *dev1 = *(struct udevice **)v1; + const struct udevice *dev2 = *(struct udevice **)v2; + const struct bootdev_uc_plat *ucp1 = dev_get_uclass_plat(dev1); + const struct bootdev_uc_plat *ucp2 = dev_get_uclass_plat(dev2); + int diff; + + /* Use priority first */ + diff = ucp1->prio - ucp2->prio; + if (diff) + return diff; + + /* Fall back to seq for devices of the same priority */ + diff = dev_seq(dev1) - dev_seq(dev2); + + return diff; +} + +/** + * setup_order() - Set up the ordering of bootdevs to scan + * + * This sets up the ordering information in @iter, based on the priority of each + * bootdev and the bootdev-order property in the bootstd node + * + * If a single device is requested, no ordering is needed + * + * @iter: Iterator to update with the order + * @devp: On entry, *devp is NULL to scan all, otherwise this is the (single) + * device to scan. Returns the first device to use, which is the passed-in + * @devp if it was non-NULL + * @return 0 if OK, -ENOENT if no bootdevs, -ENOMEM if out of memory, other -ve + * on other error + */ +static int setup_bootdev_order(struct bootflow_iter *iter, + struct udevice **devp) +{ + struct udevice *bootstd, *dev = *devp, **order; + const char *const *labels; + int upto, i; + int count; + int ret; + + ret = uclass_first_device_err(UCLASS_BOOTSTD, &bootstd); + if (ret) { + log_err("Missing bootstd device\n"); + return log_msg_ret("std", ret); + } + + /* Handle scanning a single device */ + if (dev) { + iter->flags |= BOOTFLOWF_SINGLE_DEV; + return 0; + } + + count = uclass_id_count(UCLASS_BOOTDEV); + if (!count) + return log_msg_ret("count", -ENOENT); + + order = calloc(count, sizeof(struct udevice *)); + if (!order) + return log_msg_ret("order", -ENOMEM); + + /* + * Get a list of bootdevs, in seq order (i.e. using aliases). There may + * be gaps so try to count up high enough to find them all. + */ + for (i = 0, upto = 0; upto < count && i < 20 + count * 2; i++) { + ret = uclass_find_device_by_seq(UCLASS_BOOTDEV, i, &dev); + if (!ret) + order[upto++] = dev; + } + log_debug("Found %d bootdevs\n", count); + if (upto != count) + log_warning("Expected %d bootdevs, found %d using aliases\n", + count, upto); + count = upto; + + labels = bootstd_get_bootdev_order(bootstd); + if (labels) { + upto = 0; + for (i = 0; labels[i]; i++) { + ret = bootdev_find_by_label(labels[i], &dev); + if (!ret) { + if (upto == count) { + log_warning("Expected at most %d bootdevs, but overflowed with boot_target '%s'\n", + count, labels[i]); + break; + } + order[upto++] = dev; + } + } + count = upto; + if (!count) { + free(order); + return log_msg_ret("targ", -ENOMEM); + } + } else { + /* sort them into priorty order */ + qsort(order, count, sizeof(struct udevice *), h_cmp_bootdev); + } + + iter->dev_order = order; + iter->num_devs = count; + iter->cur_dev = 0; + + dev = *order; + ret = device_probe(dev); + if (ret) + return log_msg_ret("probe", ret); + *devp = dev; + + return 0; +} + +/** + * setup_bootmeth_order() - Set up the ordering of bootmeths to scan + * + * This sets up the ordering information in @iter, based on the selected + * ordering of the bootmethds in bootstd_priv->bootmeth_order. If there is no + * ordering there, then all bootmethods are added + * + * @iter: Iterator to update with the order + * @return 0 if OK, -ENOENT if no bootdevs, -ENOMEM if out of memory, other -ve + * on other error + */ +static int setup_bootmeth_order(struct bootflow_iter *iter) +{ + struct bootstd_priv *std; + struct udevice **order; + int count; + int ret; + + ret = bootstd_get_priv(&std); + if (ret) + return ret; + + /* Create an array large enough */ + count = std->bootmeth_count ? std->bootmeth_count : + uclass_id_count(UCLASS_BOOTMETH); + if (!count) + return log_msg_ret("count", -ENOENT); + + order = calloc(count, sizeof(struct udevice *)); + if (!order) + return log_msg_ret("order", -ENOMEM); + + /* If we have an ordering, copy it */ + if (std->bootmeth_count) { + memcpy(order, std->bootmeth_order, + count * sizeof(struct bootmeth *)); + } else { + struct udevice *dev; + int i, upto; + + /* + * Get a list of bootmethods, in seq order (i.e. using aliases). + * There may be gaps so try to count up high enough to find them + * all. + */ + for (i = 0, upto = 0; upto < count && i < 20 + count * 2; i++) { + ret = uclass_get_device_by_seq(UCLASS_BOOTMETH, i, + &dev); + if (!ret) + order[upto++] = dev; + } + count = upto; + } + + iter->method_order = order; + iter->num_methods = count; + iter->cur_method = 0; + + return 0; +} + +/** + * iter_incr() - Move to the next item (method, part, bootdev) + * + * @return 0 if OK, BF_NO_MORE_DEVICES if there are no more bootdevs + */ +static int iter_incr(struct bootflow_iter *iter) +{ + struct udevice *dev; + int ret; + + if (iter->err == BF_NO_MORE_DEVICES) + return BF_NO_MORE_DEVICES; + + if (iter->err != BF_NO_MORE_PARTS) { + /* Get the next boothmethod */ + if (++iter->cur_method < iter->num_methods) { + iter->method = iter->method_order[iter->cur_method]; + return 0; + } + } + + /* No more bootmeths; start at the first one, and... */ + iter->cur_method = 0; + iter->method = iter->method_order[iter->cur_method]; + + if (iter->err != BF_NO_MORE_PARTS) { + /* ...select next partition */ + if (++iter->part <= iter->max_part) + return 0; + } + + /* No more partitions; start at the first one and...*/ + iter->part = 0; + + /* + * Note: as far as we know, there is no partition table on the next + * bootdev, so set max_part to 0 until we discover otherwise. See + * bootdev_find_in_blk() for where this is set. + */ + iter->max_part = 0; + + /* ...select next bootdev */ + if (iter->flags & BOOTFLOWF_SINGLE_DEV) { + ret = -ENOENT; + } else if (++iter->cur_dev == iter->num_devs) { + ret = -ENOENT; + bootflow_iter_set_dev(iter, NULL); + } else { + dev = iter->dev_order[iter->cur_dev]; + ret = device_probe(dev); + if (!log_msg_ret("probe", ret)) + bootflow_iter_set_dev(iter, dev); + } + + /* if there are no more bootdevs, give up */ + if (ret) + return log_msg_ret("next", BF_NO_MORE_DEVICES); + + return 0; +} + +/** + * bootflow_check() - Check if a bootflow can be obtained + * + * @iter: Provides part, bootmeth to use + * @bflow: Bootflow to update on success + * @return 0 if OK, -ENOSYS if there is no bootflow support on this device, + * BF_NO_MORE_PARTS if there are no more partitions on bootdev + */ +static int bootflow_check(struct bootflow_iter *iter, struct bootflow *bflow) +{ + struct udevice *dev; + int ret; + + dev = iter->dev; + ret = bootdev_get_bootflow(dev, iter, bflow); + + /* If we got a valid bootflow, return it */ + if (!ret) { + log_debug("Bootdevice '%s' part %d method '%s': Found bootflow\n", + dev->name, iter->part, iter->method->name); + return 0; + } + + /* Unless there is nothing more to try, move to the next device */ + else if (ret != BF_NO_MORE_PARTS && ret != -ENOSYS) { + log_debug("Bootdevice '%s' part %d method '%s': Error %d\n", + dev->name, iter->part, iter->method->name, ret); + /* + * For 'all' we return all bootflows, even + * those with errors + */ + if (iter->flags & BOOTFLOWF_ALL) + return log_msg_ret("all", ret); + } + if (ret) + return log_msg_ret("check", ret); + + return 0; +} + +int bootflow_scan_bootdev(struct udevice *dev, struct bootflow_iter *iter, + int flags, struct bootflow *bflow) +{ + int ret; + + bootflow_iter_init(iter, flags); + + ret = setup_bootdev_order(iter, &dev); + if (ret) + return log_msg_ret("obdev", -ENODEV); + bootflow_iter_set_dev(iter, dev); + + ret = setup_bootmeth_order(iter); + if (ret) + return log_msg_ret("obmeth", -ENODEV); + + /* Find the first bootmeth (there must be at least one!) */ + iter->method = iter->method_order[iter->cur_method]; + + ret = bootflow_check(iter, bflow); + if (ret) { + if (ret != BF_NO_MORE_PARTS && ret != -ENOSYS) { + if (iter->flags & BOOTFLOWF_ALL) + return log_msg_ret("all", ret); + } + iter->err = ret; + ret = bootflow_scan_next(iter, bflow); + if (ret) + return log_msg_ret("get", ret); + } + + return 0; +} + +int bootflow_scan_first(struct bootflow_iter *iter, int flags, + struct bootflow *bflow) +{ + return bootflow_scan_bootdev(NULL, iter, flags, bflow); +} + +int bootflow_scan_next(struct bootflow_iter *iter, struct bootflow *bflow) +{ + int ret; + + do { + ret = iter_incr(iter); + if (ret == BF_NO_MORE_DEVICES) + return log_msg_ret("done", ret); + + if (!ret) { + ret = bootflow_check(iter, bflow); + if (!ret) + return 0; + iter->err = ret; + if (ret != BF_NO_MORE_PARTS && ret != -ENOSYS) { + if (iter->flags & BOOTFLOWF_ALL) + return log_msg_ret("all", ret); + } + } else { + iter->err = ret; + } + + } while (1); +} + +void bootflow_free(struct bootflow *bflow) +{ + free(bflow->name); + free(bflow->subdir); + free(bflow->fname); + free(bflow->buf); +} + +void bootflow_remove(struct bootflow *bflow) +{ + list_del(&bflow->bm_node); + list_del(&bflow->glob_node); + + bootflow_free(bflow); + free(bflow); +} + +int bootflow_boot(struct bootflow *bflow) +{ + int ret; + + if (bflow->state != BOOTFLOWST_READY) + return log_msg_ret("load", -EPROTO); + + ret = bootmeth_boot(bflow->method, bflow); + if (ret) + return log_msg_ret("boot", ret); + + /* + * internal error, should not get here since we should have booted + * something or returned an error + */ + + return log_msg_ret("end", -EFAULT); +} + +int bootflow_run_boot(struct bootflow_iter *iter, struct bootflow *bflow) +{ + int ret; + + printf("** Booting bootflow '%s'\n", bflow->name); + ret = bootflow_boot(bflow); + switch (ret) { + case -EPROTO: + printf("Bootflow not loaded (state '%s')\n", + bootflow_state_get_name(bflow->state)); + break; + case -ENOSYS: + printf("Boot method '%s' not supported\n", bflow->method->name); + break; + case -ENOTSUPP: + /* Disable this bootflow for this iteration */ + if (iter) { + int ret2; + + ret2 = bootflow_iter_drop_bootmeth(iter, bflow->method); + if (!ret2) { + printf("Boot method '%s' failed and will not be retried\n", + bflow->method->name); + } + } + + break; + default: + printf("Boot failed (err=%d)\n", ret); + break; + } + + return ret; +} + +int bootflow_iter_uses_blk_dev(const struct bootflow_iter *iter) +{ + const struct udevice *media = dev_get_parent(iter->dev); + enum uclass_id id = device_get_uclass_id(media); + + log_debug("uclass %d: %s\n", id, uclass_get_name(id)); + if (id != UCLASS_ETH && id != UCLASS_BOOTSTD) + return 0; + + return -ENOTSUPP; +} + +int bootflow_iter_uses_network(const struct bootflow_iter *iter) +{ + const struct udevice *media = dev_get_parent(iter->dev); + enum uclass_id id = device_get_uclass_id(media); + + log_debug("uclass %d: %s\n", id, uclass_get_name(id)); + if (id == UCLASS_ETH) + return 0; + + return -ENOTSUPP; +} + +int bootflow_iter_uses_system(const struct bootflow_iter *iter) +{ + const struct udevice *media = dev_get_parent(iter->dev); + enum uclass_id id = device_get_uclass_id(media); + + log_debug("uclass %d: %s\n", id, uclass_get_name(id)); + if (id == UCLASS_BOOTSTD) + return 0; + + return -ENOTSUPP; +} diff --git a/boot/bootstd-uclass.c b/boot/bootstd-uclass.c index f812fbd0ae8..7dddd72bc4a 100644 --- a/boot/bootstd-uclass.c +++ b/boot/bootstd-uclass.c @@ -38,7 +38,7 @@ static void bootstd_clear_glob_(struct bootstd_priv *priv) bflow = list_first_entry(&priv->glob_head, struct bootflow, glob_node); - /* add later bootflow_remove(bflow); */ + bootflow_remove(bflow); } } diff --git a/include/bootflow.h b/include/bootflow.h index 56ff101a78a..420400c8363 100644 --- a/include/bootflow.h +++ b/include/bootflow.h @@ -145,6 +145,18 @@ void bootflow_iter_init(struct bootflow_iter *iter, int flags); */ void bootflow_iter_uninit(struct bootflow_iter *iter); +/** + * bootflow_iter_drop_bootmeth() - Remove a bootmeth from an iterator + * + * Update the iterator so that the bootmeth will not be used again while this + * iterator is in use + * + * @iter: Iterator to update + * @bmeth: Boot method to remove + */ +int bootflow_iter_drop_bootmeth(struct bootflow_iter *iter, + const struct udevice *bmeth); + /** * bootflow_scan_bootdev() - find the first bootflow in a bootdev * @@ -251,4 +263,42 @@ int bootflow_run_boot(struct bootflow_iter *iter, struct bootflow *bflow); */ const char *bootflow_state_get_name(enum bootflow_state_t state); +/** + * bootflow_remove() - Remove a bootflow and free its memory + * + * This updates the linked lists containing the bootflow then frees it. + * + * @bflow: Bootflow to remove + */ +void bootflow_remove(struct bootflow *bflow); + +/** + * bootflow_iter_uses_blk_dev() - Check that a bootflow uses a block device + * + * This checks the bootdev in the bootflow to make sure it uses a block device + * + * @return 0 if OK, -ENOTSUPP if some other device is used (e.g. ethernet) + */ +int bootflow_iter_uses_blk_dev(const struct bootflow_iter *iter); + +/** + * bootflow_iter_uses_network() - Check that a bootflow uses a network device + * + * This checks the bootdev in the bootflow to make sure it uses a network + * device + * + * @return 0 if OK, -ENOTSUPP if some other device is used (e.g. MMC) + */ +int bootflow_iter_uses_network(const struct bootflow_iter *iter); + +/** + * bootflow_iter_uses_system() - Check that a bootflow uses the bootstd device + * + * This checks the bootdev in the bootflow to make sure it uses the bootstd + * device + * + * @return 0 if OK, -ENOTSUPP if some other device is used (e.g. MMC) + */ +int bootflow_iter_uses_system(const struct bootflow_iter *iter); + #endif -- 2.33.0.1079.g6e70778dc9-goog