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 X-Spam-Level: X-Spam-Status: No, score=-19.5 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id D6D46C4338F for ; Thu, 19 Aug 2021 03:50:31 +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 52DD36109F for ; Thu, 19 Aug 2021 03:50:31 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org 52DD36109F 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 75C068324D; Thu, 19 Aug 2021 05:47:40 +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="N4pALlp6"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 450D3831F6; Thu, 19 Aug 2021 05:46:48 +0200 (CEST) Received: from mail-ot1-x333.google.com (mail-ot1-x333.google.com [IPv6:2607:f8b0:4864:20::333]) (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 F0E588317A for ; Thu, 19 Aug 2021 05:46:35 +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-x333.google.com with SMTP id 108-20020a9d01750000b029050e5cc11ae3so7000617otu.5 for ; Wed, 18 Aug 2021 20:46:35 -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=OCFF072t5wVBXHSVKYFBfg8x4N4deLerkXMlCKJWgf4=; b=N4pALlp60us+v+xSoVtMr3idcFux6PNqLh9Uu1jXnNeubjPSSaH3iKuyYgsneDIhT4 IONGVlO85ngl/TMmKe8IyC2Tzgnbza9ZlRZ1XEo3iZLL666cFbaeKL6knkOBWkn/nOHi oox/fdmA58N9O6KywAu2sIK5wcOVSXuGVNGLY= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=OCFF072t5wVBXHSVKYFBfg8x4N4deLerkXMlCKJWgf4=; b=EGSqZQZobbNvzw0o7sKu9cEUIpPCsVEAiLo7tlfWT8is9mfc+tMJLtcX4+y9AumMKu xtp4l1Bt72l1ZHMBREL4e/tX4jTG9YMFgr2Gag440LqZlJQhrlCxqilEtWziSuO1UvkA +gm9wuNp2wb2uDczxO0s4LpVl69sZfADvWetrYVAXgIb00ZvEh2/u6mKUU/vO6OR1/tq CxrsvIaepqL4eBZ8s2zeSDLgLneMYbXYUex3d1aU96+0idRvNUx9vGqgKK3gQNGJALhA xrlp34Us9gedrp9JdfltiZsZDd0S9Xe5ThM7k9itGRlZcp4NquFDZL8WeHWn7Ms8ZEcW qgMw== X-Gm-Message-State: AOAM533ZyVt97wPLZFUw6o3tOjO7nri+SjOn7L4/itBA7L9kkcl0/Rs4 9Js9d6T4YY/BKg1oetAW7jl9LF4885rOFQ== X-Google-Smtp-Source: ABdhPJxU2mCdNLGZSb/20DHs01kjMcYTZbDXS3TGzh7f52fbx5VJ2/DAP2rul+lqFTFX/49UwvacTg== X-Received: by 2002:a9d:22a4:: with SMTP id y33mr9136350ota.324.1629344793792; Wed, 18 Aug 2021 20:46:33 -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 q3sm370025ooa.13.2021.08.18.20.46.32 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 18 Aug 2021 20:46:33 -0700 (PDT) From: Simon Glass To: U-Boot Mailing List Cc: Ilias Apalodimas , Steffen Jaeckel , Michal Simek , Tom Rini , Dennis Gilmore , Daniel Schwierzeck , Lukas Auer , Simon Glass Subject: [PATCH 20/28] bootmethod: Add an implementation of distro boot Date: Wed, 18 Aug 2021 21:45:53 -0600 Message-Id: <20210818214547.20.Iafd004865970e7357960cacc4981e212e4cf3d16@changeid> X-Mailer: git-send-email 2.33.0.rc1.237.g0d66db33f3-goog In-Reply-To: <20210819034601.1618773-1-sjg@chromium.org> References: <20210819034601.1618773-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 a bootmethod type which handles distro boot, so we can boot a bootflow using this commonly used mechanism. In effect, this provides the same functionality as the 'pxe' and 'sysboot' commands and shares the same code. But the interface into it is via a bootmethod. For now this requires the 'pxe' command be enabled. Signed-off-by: Simon Glass --- MAINTAINERS | 2 + boot/Kconfig | 11 +++ boot/Makefile | 1 + boot/bootmethod.c | 14 ++++ boot/distro.c | 194 +++++++++++++++++++++++++++++++++++++++++++ include/bootmethod.h | 2 + include/distro.h | 62 ++++++++++++++ 7 files changed, 286 insertions(+) create mode 100644 boot/distro.c create mode 100644 include/distro.h diff --git a/MAINTAINERS b/MAINTAINERS index d977cee562b..f78141c138b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -634,7 +634,9 @@ BOOTMETHOD M: Simon Glass S: Maintained F: boot/bootmethod.c +F: boot/distro.c F: include/bootmethod.h +F: include/distro.h BTRFS M: Marek Behun diff --git a/boot/Kconfig b/boot/Kconfig index 90f716c3ef1..8565fbeab84 100644 --- a/boot/Kconfig +++ b/boot/Kconfig @@ -299,6 +299,17 @@ config BOOTMETHOD iterating through available bootmethods to find a bootflow suitable for booting. +config BOOTMETHOD_DISTRO + bool "Bootmethod support for distro boot" + depends on BOOTMETHOD && CMD_PXE + default y + help + Enables support for distro boot using bootmethods. This makes the + bootmethods look for a 'extlinux/extlinux.conf' on each filesystem + they scan. + + This provides a way to try out bootmethod on an existing boot flow. + config LEGACY_IMAGE_FORMAT bool "Enable support for the legacy image format" default y if !FIT_SIGNATURE diff --git a/boot/Makefile b/boot/Makefile index 10d427e115c..4ce721242b0 100644 --- a/boot/Makefile +++ b/boot/Makefile @@ -23,6 +23,7 @@ obj-y += image.o obj-$(CONFIG_ANDROID_AB) += android_ab.o obj-$(CONFIG_ANDROID_BOOT_IMAGE) += image-android.o image-android-dt.o obj-$(CONFIG_$(SPL_TPL_)BOOTMETHOD) += bootmethod.o +obj-$(CONFIG_$(SPL_TPL_)BOOTMETHOD_DISTRO) += distro.o obj-$(CONFIG_$(SPL_TPL_)OF_LIBFDT) += image-fdt.o obj-$(CONFIG_$(SPL_TPL_)FIT_SIGNATURE) += fdt_region.o obj-$(CONFIG_$(SPL_TPL_)FIT) += image-fit.o diff --git a/boot/bootmethod.c b/boot/bootmethod.c index 8e4157c6a47..be9d4aa02cc 100644 --- a/boot/bootmethod.c +++ b/boot/bootmethod.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -34,6 +35,7 @@ static const char *const bootmethod_state[BOOTFLOWST_COUNT] = { }; static const char *const bootmethod_type[BOOTFLOWT_COUNT] = { + "distro-boot", }; int bootmethod_get_state(struct bootflow_state **statep) @@ -360,6 +362,12 @@ int bootmethod_find_in_blk(struct udevice *dev, struct udevice *blk, int seq, bflow->state = BOOTFLOWST_FS; + if (CONFIG_IS_ENABLED(BOOTMETHOD_DISTRO)) { + ret = distro_boot_setup(desc, partnum, bflow); + if (ret) + return log_msg_ret("distro", ret); + } + return 0; } @@ -372,6 +380,12 @@ int bootflow_boot(struct bootflow *bflow) return log_msg_ret("load", -EPROTO); switch (bflow->type) { + case BOOTFLOWT_DISTRO: + if (CONFIG_IS_ENABLED(BOOTMETHOD_DISTRO)) { + done = true; + ret = distro_boot(bflow); + } + break; case BOOTFLOWT_COUNT: break; } diff --git a/boot/distro.c b/boot/distro.c new file mode 100644 index 00000000000..062a8535ef1 --- /dev/null +++ b/boot/distro.c @@ -0,0 +1,194 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * distro boot implementation for bootflow + * + * Copyright 2021 Google LLC + * Written by Simon Glass + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DISTRO_FNAME "extlinux/extlinux.conf" + +/** + * struct distro_info - useful information for distro_getfile() + * + * @bflow: bootflow being booted + */ +struct distro_info { + struct bootflow *bflow; +}; + +static int distro_net_getfile(struct pxe_context *ctx, const char *file_path, + char *file_addr, ulong *sizep) +{ + char *tftp_argv[] = {"tftp", NULL, NULL, NULL}; + int ret; + + printf("get %s %s\n", file_addr, file_path); + tftp_argv[1] = file_addr; + tftp_argv[2] = (void *)file_path; + + if (do_tftpb(ctx->cmdtp, 0, 3, tftp_argv)) + return -ENOENT; + ret = pxe_get_file_size(sizep); + if (ret) + return log_msg_ret("tftp", ret); + + return 0; +} + +int distro_net_setup(struct bootflow *bflow) +{ + const char *addr_str; + char fname[200]; + char *bootdir; + ulong addr; + ulong size; + char *buf; + int ret; + + addr_str = env_get("pxefile_addr_r"); + if (!addr_str) + return log_msg_ret("pxeb", -EPERM); + addr = simple_strtoul(addr_str, NULL, 16); + + bflow->type = BOOTFLOWT_DISTRO; + ret = pxe_get(addr, &bootdir, &size); + if (ret) + return log_msg_ret("pxeb", ret); + bflow->size = size; + + /* Use the directory of the dhcp bootdir as our subdir, if provided */ + if (bootdir) { + const char *last_slash; + int path_len; + + last_slash = strrchr(bootdir, '/'); + if (last_slash) { + path_len = (last_slash - bootdir) + 1; + bflow->subdir = malloc(path_len + 1); + memcpy(bflow->subdir, bootdir, path_len); + bflow->subdir[path_len] = '\0'; + } + } + snprintf(fname, sizeof(fname), "%s%s", + bflow->subdir ? bflow->subdir : "", DISTRO_FNAME); + + bflow->fname = strdup(fname); + if (!bflow->fname) + return log_msg_ret("name", -ENOMEM); + + bflow->state = BOOTFLOWST_LOADED; + + /* Allocate the buffer, including the \0 byte added by get_pxe_file() */ + buf = malloc(size + 1); + if (!buf) + return log_msg_ret("buf", -ENOMEM); + memcpy(buf, map_sysmem(addr, 0), size + 1); + bflow->buf = buf; + + return 0; +} + +int distro_boot_setup(struct blk_desc *desc, int partnum, + struct bootflow *bflow) +{ + loff_t size, bytes_read; + ulong addr; + char *buf; + int ret; + + bflow->type = BOOTFLOWT_DISTRO; + bflow->fname = strdup(DISTRO_FNAME); + if (!bflow->fname) + return log_msg_ret("name", -ENOMEM); + ret = fs_size(bflow->fname, &size); + if (ret) + return log_msg_ret("size", ret); + bflow->state = BOOTFLOWST_FILE; + bflow->size = size; + log_debug(" - distro file size %x\n", (uint)size); + if (size > 0x10000) + return log_msg_ret("chk", -E2BIG); + + /* Sadly FS closes the file after fs_size() so we must redo this */ + ret = fs_set_blk_dev_with_part(desc, partnum); + if (ret) + return log_msg_ret("set", ret); + + buf = malloc(size + 1); + if (!buf) + return log_msg_ret("buf", -ENOMEM); + addr = map_to_sysmem(buf); + + ret = fs_read(bflow->fname, addr, 0, 0, &bytes_read); + if (ret) { + free(buf); + return log_msg_ret("read", ret); + } + if (size != bytes_read) + return log_msg_ret("bread", -EINVAL); + buf[size] = '\0'; + bflow->state = BOOTFLOWST_LOADED; + bflow->buf = buf; + + return 0; +} + +static int disto_getfile(struct pxe_context *ctx, const char *file_path, + char *file_addr, ulong *sizep) +{ + struct distro_info *info = ctx->userdata; + struct bootflow *bflow = info->bflow; + struct blk_desc *desc = dev_get_uclass_plat(bflow->blk); + loff_t len_read; + ulong addr; + int ret; + + addr = simple_strtoul(file_addr, NULL, 16); + ret = fs_set_blk_dev_with_part(desc, bflow->part); + if (ret) + return ret; + ret = fs_read(file_path, addr, 0, 0, &len_read); + if (ret) + return ret; + *sizep = len_read; + + return 0; +} + +int distro_boot(struct bootflow *bflow) +{ + struct cmd_tbl cmdtp = {}; /* dummy */ + struct pxe_context ctx; + struct distro_info info; + bool is_net = !bflow->blk; + ulong addr; + int ret; + + addr = map_to_sysmem(bflow->buf); + info.bflow = bflow; + ret = pxe_setup_ctx(&ctx, &cmdtp, + is_net ? distro_net_getfile : disto_getfile, + &info, !is_net, bflow->subdir); + if (ret) + return log_msg_ret("ctx", -EINVAL); + + ret = pxe_process(&ctx, addr, false); + if (ret) + return log_msg_ret("bread", -EINVAL); + + return 0; +} diff --git a/include/bootmethod.h b/include/bootmethod.h index a45897b0c0c..d80be556b8a 100644 --- a/include/bootmethod.h +++ b/include/bootmethod.h @@ -24,6 +24,8 @@ enum bootflow_state_t { }; enum bootflow_type_t { + BOOTFLOWT_DISTRO, /**< Distro boot */ + BOOTFLOWT_COUNT, }; diff --git a/include/distro.h b/include/distro.h new file mode 100644 index 00000000000..80b8da4bed3 --- /dev/null +++ b/include/distro.h @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright 2021 Google LLC + * Written by Simon Glass + */ + +#ifndef __distro_h +#define __distro_h + +struct blk_desc; + +/** + * distro_boot_setup() - Set up a bootflow for distro boot from a block device + * + * This fills out a bootflow for a particular boot device and partition. It + * scans for a filesystem and suitable file, updating the bootflow accordingly. + * + * This sets the following fields in @bflow: + * + * type, size, fname, state, subdir, buf + * + * The caller mast have already set the other fields. + * + * @desc: Block-device descriptor + * @partnum: Partition number (1..) + * @bflow: Partial bootflow to be completed by this function + * @return 0 on success (bootflow got to 'loaded' state), -ve on error + */ +int distro_boot_setup(struct blk_desc *desc, int partnum, + struct bootflow *bflow); + +/** + * distro_boot_setup() - Set up a bootflow for distro boot from a network device + * + * This fills out a bootflow for a network device. It scans the tftp server for + * a suitable file, updating the bootflow accordingly. + * + * At present no control is provided as to which network device is used. + * + * This sets the following fields in @bflow: + * + * type, size, fname, state,, buf + * + * The caller mast have already set the other fields. + * + * @bflow: Partial bootflow to be completed by this function + * @return 0 on success (bootflow got to 'loaded' state), -ve on error + */ +int distro_net_setup(struct bootflow *bflow); + +/** + * distro_boot() - Boot a distro + * + * Boots a bootflow of type BOOTFLOWT_DISTRO. This typically needs to load more + * files as it processes and this is done via the same media as the bootflow + * was loaded + * + * @bflow: Bootflow to boot +*/ +int distro_boot(struct bootflow *bflow); + +#endif -- 2.33.0.rc1.237.g0d66db33f3-goog